summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan Skinner <aidan@apache.org>2009-10-11 23:22:08 +0000
committerAidan Skinner <aidan@apache.org>2009-10-11 23:22:08 +0000
commit98cc985dbd81a84cd0b0a969c57cb941680ec81f (patch)
treea9060c1f208897cbd9dd4791b29202c78566993b
parent788f96fd8af146cba5bff57300b1a513988c34b9 (diff)
downloadqpid-python-98cc985dbd81a84cd0b0a969c57cb941680ec81f.tar.gz
Merge from trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/java-network-refactor@824198 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/CMakeLists.txt146
-rw-r--r--qpid/cpp/bindings/qmf/python/Makefile.am2
-rw-r--r--qpid/cpp/bindings/qmf/python/qmf.py4
-rw-r--r--qpid/cpp/bindings/qmf/qmfengine.i35
-rw-r--r--qpid/cpp/bindings/qmf/ruby/Makefile.am7
-rw-r--r--qpid/cpp/bindings/qmf/ruby/qmf.rb321
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/agent_ruby.rb103
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/ruby_console.rb76
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/ruby_console_test.rb194
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/run_interop_tests10
-rw-r--r--qpid/cpp/bindings/qmf/tests/test_base.rb73
-rw-r--r--qpid/cpp/boost-1.32-support/supressions76
-rw-r--r--qpid/cpp/etc/CMakeLists.txt20
-rw-r--r--qpid/cpp/examples/messaging/client.cpp2
-rw-r--r--qpid/cpp/examples/messaging/map_receiver.cpp4
-rw-r--r--qpid/cpp/examples/messaging/map_sender.cpp11
-rw-r--r--qpid/cpp/examples/messaging/queue_listener.cpp4
-rw-r--r--qpid/cpp/examples/messaging/queue_receiver.cpp8
-rw-r--r--qpid/cpp/examples/messaging/queue_sender.cpp15
-rw-r--r--qpid/cpp/examples/messaging/server.cpp8
-rw-r--r--qpid/cpp/examples/messaging/topic_listener.cpp4
-rw-r--r--qpid/cpp/examples/messaging/topic_receiver.cpp4
-rw-r--r--qpid/cpp/examples/qmf-agent/Makefile2
-rw-r--r--qpid/cpp/include/qmf/ConnectionSettings.h121
-rw-r--r--qpid/cpp/include/qmf/ConsoleObject.h94
-rw-r--r--qpid/cpp/include/qmf/engine/Agent.h (renamed from qpid/cpp/src/qmf/AgentEngine.h)34
-rw-r--r--qpid/cpp/include/qmf/engine/ConnectionSettings.h150
-rw-r--r--qpid/cpp/include/qmf/engine/Console.h (renamed from qpid/cpp/src/qmf/ConsoleEngine.h)91
-rw-r--r--qpid/cpp/include/qmf/engine/Event.h (renamed from qpid/cpp/src/qmf/Event.h)6
-rw-r--r--qpid/cpp/include/qmf/engine/Message.h (renamed from qpid/cpp/src/qmf/Message.h)6
-rw-r--r--qpid/cpp/include/qmf/engine/Object.h (renamed from qpid/cpp/src/qmf/Object.h)24
-rw-r--r--qpid/cpp/include/qmf/engine/ObjectId.h (renamed from qpid/cpp/src/qmf/ObjectId.h)20
-rw-r--r--qpid/cpp/include/qmf/engine/QmfEngineImportExport.h33
-rw-r--r--qpid/cpp/include/qmf/engine/Query.h (renamed from qpid/cpp/src/qmf/Query.h)20
-rw-r--r--qpid/cpp/include/qmf/engine/ResilientConnection.h (renamed from qpid/cpp/src/qmf/ResilientConnection.h)10
-rw-r--r--qpid/cpp/include/qmf/engine/Schema.h (renamed from qpid/cpp/src/qmf/Schema.h)69
-rw-r--r--qpid/cpp/include/qmf/engine/Typecode.h (renamed from qpid/cpp/src/qmf/Typecode.h)6
-rw-r--r--qpid/cpp/include/qmf/engine/Value.h (renamed from qpid/cpp/src/qmf/Value.h)20
-rw-r--r--qpid/cpp/include/qpid/client/QueueOptions.h15
-rw-r--r--qpid/cpp/include/qpid/messaging/ListContent.h90
-rw-r--r--qpid/cpp/include/qpid/messaging/ListView.h67
-rw-r--r--qpid/cpp/include/qpid/messaging/MapContent.h90
-rw-r--r--qpid/cpp/include/qpid/messaging/MapView.h70
-rw-r--r--qpid/cpp/include/qpid/messaging/Message.h22
-rw-r--r--qpid/cpp/include/qpid/messaging/MessageContent.h90
-rw-r--r--qpid/cpp/include/qpid/sys/posix/PrivatePosix.h5
-rwxr-xr-xqpid/cpp/include/qpid/sys/windows/IntegerTypes.h4
-rw-r--r--qpid/cpp/managementgen/CMakeLists.txt19
-rw-r--r--qpid/cpp/packaging/NSIS/qpid-icon.icobin0 -> 52972 bytes
-rw-r--r--qpid/cpp/packaging/NSIS/qpid-icon.pngbin0 -> 97992 bytes
-rw-r--r--qpid/cpp/packaging/NSIS/qpid-install-banner.bmpbin0 -> 9742 bytes
-rw-r--r--qpid/cpp/packaging/NSIS/qpid-install-banner.pngbin0 -> 57218 bytes
-rwxr-xr-xqpid/cpp/rubygen/framing.0-10/structs.rb3
-rw-r--r--qpid/cpp/src/CMakeLists.txt277
-rw-r--r--qpid/cpp/src/Makefile.am11
-rw-r--r--qpid/cpp/src/cluster.mk3
-rw-r--r--qpid/cpp/src/qmf.mk120
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngine.cpp1091
-rw-r--r--qpid/cpp/src/qmf/engine/Agent.cpp (renamed from qpid/cpp/src/qmf/AgentEngine.cpp)248
-rw-r--r--qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp763
-rw-r--r--qpid/cpp/src/qmf/engine/BrokerProxyImpl.h239
-rw-r--r--qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp (renamed from qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp)104
-rw-r--r--qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h (renamed from qpid/cpp/src/qmf/ConnectionSettingsImpl.h)19
-rw-r--r--qpid/cpp/src/qmf/engine/ConsoleImpl.cpp419
-rw-r--r--qpid/cpp/src/qmf/engine/ConsoleImpl.h145
-rw-r--r--qpid/cpp/src/qmf/engine/MessageImpl.cpp (renamed from qpid/cpp/src/qmf/MessageImpl.cpp)4
-rw-r--r--qpid/cpp/src/qmf/engine/MessageImpl.h (renamed from qpid/cpp/src/qmf/MessageImpl.h)8
-rw-r--r--qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp (renamed from qpid/cpp/src/qmf/ObjectIdImpl.cpp)96
-rw-r--r--qpid/cpp/src/qmf/engine/ObjectIdImpl.h (renamed from qpid/cpp/src/qmf/ObjectIdImpl.h)17
-rw-r--r--qpid/cpp/src/qmf/engine/ObjectImpl.cpp (renamed from qpid/cpp/src/qmf/ObjectImpl.cpp)56
-rw-r--r--qpid/cpp/src/qmf/engine/ObjectImpl.h (renamed from qpid/cpp/src/qmf/ObjectImpl.h)33
-rw-r--r--qpid/cpp/src/qmf/engine/Protocol.cpp (renamed from qpid/cpp/src/qmf/Protocol.cpp)4
-rw-r--r--qpid/cpp/src/qmf/engine/Protocol.h (renamed from qpid/cpp/src/qmf/Protocol.h)6
-rw-r--r--qpid/cpp/src/qmf/engine/QueryImpl.cpp (renamed from qpid/cpp/src/qmf/QueryImpl.cpp)15
-rw-r--r--qpid/cpp/src/qmf/engine/QueryImpl.h (renamed from qpid/cpp/src/qmf/QueryImpl.h)34
-rw-r--r--qpid/cpp/src/qmf/engine/ResilientConnection.cpp (renamed from qpid/cpp/src/qmf/ResilientConnection.cpp)53
-rw-r--r--qpid/cpp/src/qmf/engine/SchemaImpl.cpp (renamed from qpid/cpp/src/qmf/SchemaImpl.cpp)221
-rw-r--r--qpid/cpp/src/qmf/engine/SchemaImpl.h (renamed from qpid/cpp/src/qmf/SchemaImpl.h)75
-rw-r--r--qpid/cpp/src/qmf/engine/SequenceManager.cpp (renamed from qpid/cpp/src/qmf/SequenceManager.cpp)10
-rw-r--r--qpid/cpp/src/qmf/engine/SequenceManager.h (renamed from qpid/cpp/src/qmf/SequenceManager.h)10
-rw-r--r--qpid/cpp/src/qmf/engine/ValueImpl.cpp (renamed from qpid/cpp/src/qmf/ValueImpl.cpp)390
-rw-r--r--qpid/cpp/src/qmf/engine/ValueImpl.h (renamed from qpid/cpp/src/qmf/ValueImpl.h)32
-rw-r--r--qpid/cpp/src/qpid/acl/AclData.cpp109
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp53
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.h11
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Connection.cpp21
-rw-r--r--qpid/cpp/src/qpid/amqp_0_10/Connection.h2
-rw-r--r--qpid/cpp/src/qpid/broker/AclModule.h22
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp16
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.h3
-rw-r--r--qpid/cpp/src/qpid/broker/DirectExchange.cpp33
-rw-r--r--qpid/cpp/src/qpid/broker/DtxAck.cpp22
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.cpp34
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.h3
-rw-r--r--qpid/cpp/src/qpid/broker/FanOutExchange.cpp32
-rw-r--r--qpid/cpp/src/qpid/broker/HeadersExchange.cpp29
-rw-r--r--qpid/cpp/src/qpid/broker/Message.cpp110
-rw-r--r--qpid/cpp/src/qpid/broker/Message.h17
-rw-r--r--qpid/cpp/src/qpid/broker/MessageBuilder.cpp3
-rw-r--r--qpid/cpp/src/qpid/broker/MessageStoreModule.cpp6
-rw-r--r--qpid/cpp/src/qpid/broker/MessageStoreModule.h5
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.cpp31
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.h21
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.cpp102
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.h17
-rw-r--r--qpid/cpp/src/qpid/broker/QueueEvents.cpp41
-rw-r--r--qpid/cpp/src/qpid/broker/QueueEvents.h4
-rw-r--r--qpid/cpp/src/qpid/broker/QueuePolicy.cpp144
-rw-r--r--qpid/cpp/src/qpid/broker/QueuePolicy.h34
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.cpp35
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.h2
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp7
-rw-r--r--qpid/cpp/src/qpid/broker/SessionContext.h3
-rw-r--r--qpid/cpp/src/qpid/broker/SessionState.h2
-rw-r--r--qpid/cpp/src/qpid/broker/SignalHandler.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/SignalHandler.h3
-rw-r--r--qpid/cpp/src/qpid/broker/TopicExchange.cpp43
-rw-r--r--qpid/cpp/src/qpid/broker/TxAccept.cpp8
-rw-r--r--qpid/cpp/src/qpid/broker/TxPublish.cpp54
-rw-r--r--qpid/cpp/src/qpid/broker/TxPublish.h14
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.cpp1
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.h2
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionImpl.cpp6
-rw-r--r--qpid/cpp/src/qpid/client/Connector.cpp82
-rw-r--r--qpid/cpp/src/qpid/client/RdmaConnector.cpp15
-rw-r--r--qpid/cpp/src/qpid/client/Sasl.h1
-rw-r--r--qpid/cpp/src/qpid/client/SaslFactory.cpp13
-rw-r--r--qpid/cpp/src/qpid/client/SessionImpl.cpp18
-rw-r--r--qpid/cpp/src/qpid/client/SessionImpl.h4
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp11
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp11
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp17
-rw-r--r--qpid/cpp/src/qpid/client/windows/SaslFactory.cpp6
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.cpp30
-rw-r--r--qpid/cpp/src/qpid/cluster/ErrorCheck.cpp30
-rw-r--r--qpid/cpp/src/qpid/cluster/ErrorCheck.h1
-rw-r--r--qpid/cpp/src/qpid/cluster/Event.cpp9
-rw-r--r--qpid/cpp/src/qpid/cluster/Multicaster.cpp4
-rw-r--r--qpid/cpp/src/qpid/cluster/Multicaster.h3
-rw-r--r--qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp12
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateClient.cpp9
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateExchange.h2
-rw-r--r--qpid/cpp/src/qpid/messaging/ListContent.cpp98
-rw-r--r--qpid/cpp/src/qpid/messaging/ListView.cpp63
-rw-r--r--qpid/cpp/src/qpid/messaging/MapContent.cpp87
-rw-r--r--qpid/cpp/src/qpid/messaging/MapView.cpp63
-rw-r--r--qpid/cpp/src/qpid/messaging/Message.cpp28
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.cpp149
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.h54
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIO.h6
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp39
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIOHandler.h2
-rw-r--r--qpid/cpp/src/qpid/sys/LatencyTracker.h157
-rw-r--r--qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp20
-rw-r--r--qpid/cpp/src/qpid/sys/Socket.h2
-rw-r--r--qpid/cpp/src/qpid/sys/SocketAddress.h51
-rw-r--r--qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp27
-rw-r--r--qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp31
-rw-r--r--qpid/cpp/src/qpid/sys/posix/Socket.cpp55
-rw-r--r--qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp71
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp17
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp5
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaIO.h9
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp12
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h9
-rw-r--r--qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp2
-rw-r--r--qpid/cpp/src/qpid/xml/XmlExchange.cpp39
-rw-r--r--qpid/cpp/src/qpidd.cpp34
-rw-r--r--qpid/cpp/src/tests/AsyncCompletion.cpp6
-rw-r--r--qpid/cpp/src/tests/ClusterFixture.h4
-rw-r--r--qpid/cpp/src/tests/ExchangeTest.cpp2
-rw-r--r--qpid/cpp/src/tests/Makefile.am64
-rw-r--r--qpid/cpp/src/tests/MessageUtils.h5
-rw-r--r--qpid/cpp/src/tests/MessagingSessionTests.cpp83
-rw-r--r--qpid/cpp/src/tests/PartialFailure.cpp5
-rw-r--r--qpid/cpp/src/tests/QueuePolicyTest.cpp58
-rw-r--r--qpid/cpp/src/tests/QueueTest.cpp341
-rw-r--r--qpid/cpp/src/tests/TxPublishTest.cpp2
-rwxr-xr-xqpid/cpp/src/tests/acl.py126
-rwxr-xr-xqpid/cpp/src/tests/ais_check35
-rw-r--r--qpid/cpp/src/tests/background.ps121
-rw-r--r--qpid/cpp/src/tests/cluster.mk5
-rwxr-xr-xqpid/cpp/src/tests/cluster_read_credit27
-rw-r--r--qpid/cpp/src/tests/cluster_test.cpp59
-rwxr-xr-xqpid/cpp/src/tests/clustered_replication_test41
-rwxr-xr-xqpid/cpp/src/tests/federated_cluster_test39
-rwxr-xr-xqpid/cpp/src/tests/federated_topic_test17
-rw-r--r--qpid/cpp/src/tests/python_env.sh26
-rwxr-xr-xqpid/cpp/src/tests/python_tests10
-rw-r--r--qpid/cpp/src/tests/python_tests.ps142
-rw-r--r--qpid/cpp/src/tests/qpid_stream.cpp9
-rw-r--r--qpid/cpp/src/tests/quick_topictest.ps111
-rwxr-xr-xqpid/cpp/src/tests/reliable_replication_test14
-rwxr-xr-xqpid/cpp/src/tests/replication_test43
-rwxr-xr-xqpid/cpp/src/tests/ring_queue_test7
-rwxr-xr-xqpid/cpp/src/tests/run_acl_tests4
-rwxr-xr-xqpid/cpp/src/tests/run_cli_tests6
-rwxr-xr-xqpid/cpp/src/tests/run_cluster_test26
-rwxr-xr-xqpid/cpp/src/tests/run_cluster_tests38
-rwxr-xr-xqpid/cpp/src/tests/run_failover_soak24
-rwxr-xr-xqpid/cpp/src/tests/run_federation_tests4
-rw-r--r--qpid/cpp/src/tests/run_federation_tests.ps165
-rwxr-xr-xqpid/cpp/src/tests/run_header_test2
-rw-r--r--qpid/cpp/src/tests/run_header_test.ps133
-rwxr-xr-xqpid/cpp/src/tests/run_long_cluster_tests3
-rwxr-xr-xqpid/cpp/src/tests/run_ring_queue_test5
-rw-r--r--qpid/cpp/src/tests/run_test.ps13
-rw-r--r--qpid/cpp/src/tests/start_broker.ps121
-rwxr-xr-xqpid/cpp/src/tests/start_cluster9
-rw-r--r--qpid/cpp/src/tests/stop_broker.ps117
-rw-r--r--qpid/cpp/src/tests/test_store.cpp3
-rw-r--r--qpid/cpp/src/tests/topictest.ps132
-rw-r--r--qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp17
-rw-r--r--qpid/cpp/src/windows/QpiddBroker.cpp9
-rw-r--r--qpid/java/broker/etc/log4j.xml4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java109
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java13
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java13
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java106
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java16
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java278
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java3
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java1002
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java2
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java37
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java3
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java5
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java5
-rw-r--r--qpid/java/client/src/main/java/log4j.xml36
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java12
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java9
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java13
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java13
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java152
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java3
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java11
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java13
-rwxr-xr-xqpid/java/common/bin/qpid-run1
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java1
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java2
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java2
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java2
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java2
-rw-r--r--qpid/java/module.xml2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java22
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java330
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java5
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java393
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java123
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java170
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java22
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java271
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java193
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java356
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java306
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java170
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java179
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java40
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java148
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java253
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java306
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java403
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java83
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java221
-rwxr-xr-x[-rw-r--r--]qpid/java/test-profiles/010Excludes9
-rw-r--r--qpid/java/test-profiles/08Excludes2
-rw-r--r--qpid/java/test-profiles/08StandaloneExcludes2
-rw-r--r--qpid/java/test-profiles/Excludes12
-rw-r--r--qpid/java/test-profiles/default.testprofile3
-rw-r--r--qpid/java/test-profiles/log4j-test.xml6
-rw-r--r--qpid/java/test-profiles/test-provider.properties17
-rw-r--r--qpid/python/Makefile2
-rwxr-xr-xqpid/python/examples/api/drain62
-rwxr-xr-xqpid/python/examples/api/ping76
-rwxr-xr-xqpid/python/qpid-python-test42
-rw-r--r--qpid/python/qpid/address.py171
-rw-r--r--qpid/python/qpid/compat.py11
-rw-r--r--qpid/python/qpid/driver.py864
-rw-r--r--qpid/python/qpid/messaging.py148
-rw-r--r--qpid/python/qpid/ops.py6
-rw-r--r--qpid/python/qpid/selector.py156
-rw-r--r--qpid/python/qpid/tests/messaging.py174
-rwxr-xr-xqpid/review/changeLogToWiki.py85
-rw-r--r--qpid/wcf/ReadMe.txt8
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs6
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs11
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs4
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs2
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs4
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs8
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs11
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp32
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h3
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h1
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp150
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/InputLink.h15
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj4
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h4
-rwxr-xr-xqpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat10
-rw-r--r--qpid/wcf/tools/QCreate/QCreate.vcproj6
327 files changed, 13050 insertions, 5807 deletions
diff --git a/qpid/cpp/CMakeLists.txt b/qpid/cpp/CMakeLists.txt
index de1353bd11..18a7616d99 100644
--- a/qpid/cpp/CMakeLists.txt
+++ b/qpid/cpp/CMakeLists.txt
@@ -23,26 +23,150 @@ if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
+set (QPID_VERSION_MAJOR 0)
+set (QPID_VERSION_MINOR 6)
+set (qpidc_version ${QPID_VERSION_MAJOR}.${QPID_VERSION_MINOR})
+
enable_testing()
include (CTest)
-set (qpidc_version 0.5)
+# When doing installs, there are a number of components that the item can
+# be associated with. Since there may be different sets of components desired
+# for the various platforms, the component names are defined here. When
+# setting the COMPONENT in an install directive, use these to ensure that
+# the item is installed correctly.
+#
+# This section also has all the setup for various packaging-specific options.
+if (WIN32)
+ set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+ set (CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico")
+ set (CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico")
+ set (CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-install-banner.bmp")
-# set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ # Install types; these defines the component sets that are installed.
+ # Each component (below) indicates which of these install type(s) it is
+ # included in. The user can refine the components at install time.
+ set (CPACK_ALL_INSTALL_TYPES Broker Development Full)
-add_subdirectory(managementgen)
-# add_subdirectory(etc)
-add_subdirectory(src)
-# add_subdirectory(docs/api)
-# add_subdirectory(docs/man)
+ set (QPID_COMPONENT_COMMON Common)
+ set (CPACK_COMPONENT_COMMON_INSTALL_TYPES Broker Development Full)
+ set (CPACK_COMPONENT_COMMON_DISPLAY_NAME "Required common runtime items")
+ set (CPACK_COMPONENT_COMMON_DESCRIPTION
+ "Run-time library common to all runtime components in Qpid.\n
+ This item is required by both broker and client components.")
+
+ set (QPID_COMPONENT_BROKER Broker)
+ set (CPACK_COMPONENT_BROKER_DEPENDS Common)
+ set (CPACK_COMPONENT_BROKER_INSTALL_TYPES Broker Full)
+ set (CPACK_COMPONENT_BROKER_DISPLAY_NAME "Broker")
+ set (CPACK_COMPONENT_BROKER_DESCRIPTION
+ "Messaging broker; controls message flow within the system.\n
+ At least one broker is required to run any messaging application.")
+
+ set (QPID_COMPONENT_CLIENT Client)
+ set (CPACK_COMPONENT_CLIENT_DEPENDS Common)
+ set (CPACK_COMPONENT_CLIENT_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_CLIENT_DISPLAY_NAME "Client runtime libraries")
+ set (CPACK_COMPONENT_CLIENT_DESCRIPTION
+ "Runtime library components required to build and execute a client application.")
+
+ set (QPID_COMPONENT_CLIENT_INCLUDE ClientInclude)
+ set (CPACK_COMPONENT_CLIENTINCLUDE_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_CLIENTINCLUDE_DISPLAY_NAME
+ "Client programming header files")
+ set (CPACK_COMPONENT_CLIENTINCLUDE_DESCRIPTION
+ "C++ header files required to build any Qpid messaging application.")
+
+ set (QPID_COMPONENT_QMF QMF)
+ set (CPACK_COMPONENT_QMF_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_QMF_DISPLAY_NAME
+ "Qpid Management Framework (QMF)")
+ set (CPACK_COMPONENT_QMF_DESCRIPTION
+ "QMF Agent allows you to embed QMF management in your program.\n
+ QMF Console allows you to build management programs using QMF.")
+
+ set (QPID_INSTALL_BINDIR bin CACHE STRING
+ "Directory to install user executables")
+ set (QPID_INSTALL_CONFDIR conf CACHE STRING
+ "Directory to install configuration files")
+ set (QPID_INSTALL_DATADIR conf CACHE STRING
+ "Directory to install read-only arch.-independent data root")
+ set (QPID_INSTALL_INCLUDEDIR include CACHE STRING
+ "Directory to install programming header files")
+ set (QPID_INSTALL_LIBDIR bin CACHE STRING
+ "Directory to install library files")
+ set (QPID_INSTALL_SBINDIR bin CACHE STRING
+ "Directory to install system admin executables")
+ set (QPIDC_MODULE_DIR plugins/client CACHE STRING
+ "Directory to load client plug-in modules from")
+ set (QPIDD_MODULE_DIR plugins/broker CACHE STRING
+ "Directory to load broker plug-in modules from")
+endif (WIN32)
+if (CMAKE_SYSTEM_NAME STREQUAL Linux)
+ # Set up install locations. Since the Linux install puts some files in
+ # /etc and most in the install location, we need to use a DESTDIR build
+ # rather than the usual simple use of CPACK_INSTALL_PREFIX.
+ set (CPACK_SET_DESTDIR ON)
-# if (WIN32)
-# do something Microsoft specific
-# endif (WIN32)
+ set (QPID_COMPONENT_BROKER runtime)
+ set (QPID_COMPONENT_CLIENT runtime)
+ set (QPID_COMPONENT_COMMON runtime)
+ set (CPACK_COMPONENT_RUNTIME_DISPLAY_NAME
+ "Items required to run broker and/or client programs")
+ set (QPID_COMPONENT_CLIENT_INCLUDE development)
+ set (QPID_COMPONENT_QMF development)
+ set (CPACK_COMPONENT_DEVELOPMENT_DISPLAY_NAME
+ "Items required to build new C++ Qpid client programs")
+
+
+ set (QPID_INSTALL_BINDIR bin CACHE STRING
+ "Directory to install user executables")
+ set (QPID_INSTALL_CONFDIR /etc/qpid CACHE STRING
+ "Directory to install configuration files")
+ set (QPID_INSTALL_DATADIR share/qpid CACHE STRING
+ "Directory to install read-only arch.-independent data root")
+ set (QPID_INSTALL_INCLUDEDIR include CACHE STRING
+ "Directory to install programming header files")
+ set (QPID_INSTALL_LIBDIR lib CACHE STRING
+ "Directory to install library files")
+ set (QPID_INSTALL_SBINDIR sbin CACHE STRING
+ "Directory to install system admin executables")
+ set (QPIDC_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/client CACHE STRING
+ "Directory to load client plug-in modules from")
+ set (QPIDD_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/daemon CACHE STRING
+ "Directory to load broker plug-in modules from")
+endif (CMAKE_SYSTEM_NAME STREQUAL Linux)
+
+set (QPIDC_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidc.conf CACHE STRING
+ "Name of the Qpid client configuration file")
+set (QPIDD_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidd.conf CACHE STRING
+ "Name of the Qpid broker configuration file")
install(FILES LICENSE NOTICE README SSL RELEASE_NOTES DESIGN
xml/cluster.xml INSTALL-WINDOWS
- DESTINATION .)
+ DESTINATION ${QPID_INSTALL_DATADIR})
+
+if (WIN32)
+ set (CMAKE_DEBUG_POSTFIX "d")
+endif (WIN32)
+
+# set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_subdirectory(managementgen)
+add_subdirectory(etc)
+add_subdirectory(src)
+# add_subdirectory(docs/api)
+# add_subdirectory(docs/man)
add_subdirectory(examples)
+
+set(CPACK_PACKAGE_NAME "qpid-cpp")
+set(CPACK_PACKAGE_VENDOR "Apache Software Foundation")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Qpid C++")
+set(CPACK_PACKAGE_VERSION "${qpidc_version}")
+set(CPACK_PACKAGE_VERSION_MAJOR "${QPID_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${QPID_VERSION_MINOR}")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "qpidc-${qpidc_version}")
+
+include (CPack)
diff --git a/qpid/cpp/bindings/qmf/python/Makefile.am b/qpid/cpp/bindings/qmf/python/Makefile.am
index 55d9079fb7..53303c7be9 100644
--- a/qpid/cpp/bindings/qmf/python/Makefile.am
+++ b/qpid/cpp/bindings/qmf/python/Makefile.am
@@ -38,7 +38,7 @@ lib_LTLIBRARIES = _qmfengine.la
#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so"
_qmfengine_la_LDFLAGS = -avoid-version -module -shared
-_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfagent.la
+_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmf.la
_qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC)
nodist__qmfengine_la_SOURCES = qmfengine.cpp
diff --git a/qpid/cpp/bindings/qmf/python/qmf.py b/qpid/cpp/bindings/qmf/python/qmf.py
index 4800b327f1..383baad0e3 100644
--- a/qpid/cpp/bindings/qmf/python/qmf.py
+++ b/qpid/cpp/bindings/qmf/python/qmf.py
@@ -566,7 +566,7 @@ class Console:
# attr_reader :impl
def initialize(handler=None, kwargs={}):
self._handler = handler
- self.impl = qmfengine.ConsoleEngine()
+ self.impl = qmfengine.Console()
self._event = qmfengine.ConsoleEvent()
self._broker_list = []
@@ -741,7 +741,7 @@ class Agent(ConnectionHandler):
self._agentLabel = label
self._conn = None
self._handler = handler
- self.impl = qmfengine.AgentEngine(self._agentLabel)
+ self.impl = qmfengine.Agent(self._agentLabel)
self._event = qmfengine.AgentEvent()
self._xmtMessage = qmfengine.Message()
diff --git a/qpid/cpp/bindings/qmf/qmfengine.i b/qpid/cpp/bindings/qmf/qmfengine.i
index d3500c9b8f..3477215254 100644
--- a/qpid/cpp/bindings/qmf/qmfengine.i
+++ b/qpid/cpp/bindings/qmf/qmfengine.i
@@ -19,34 +19,35 @@
%{
-#include "qmf/AgentEngine.h"
-#include "qmf/ConsoleEngine.h"
-#include "qmf/ResilientConnection.h"
+#include "qmf/engine/Agent.h"
+#include "qmf/engine/Console.h"
+#include "qmf/engine/ResilientConnection.h"
%}
-%include <qmf/QmfImportExport.h>
-%include <qmf/Query.h>
-%include <qmf/Message.h>
-%include <qmf/AgentEngine.h>
-%include <qmf/ConsoleEngine.h>
-%include <qmf/ConnectionSettings.h>
-%include <qmf/ResilientConnection.h>
-%include <qmf/Typecode.h>
-%include <qmf/Schema.h>
-%include <qmf/Value.h>
-%include <qmf/ObjectId.h>
-%include <qmf/Object.h>
+%include <qmf/engine/QmfEngineImportExport.h>
+%include <qmf/engine/Query.h>
+%include <qmf/engine/Message.h>
+%include <qmf/engine/Agent.h>
+%include <qmf/engine/Console.h>
+%include <qmf/engine/ConnectionSettings.h>
+%include <qmf/engine/ResilientConnection.h>
+%include <qmf/engine/Typecode.h>
+%include <qmf/engine/Schema.h>
+%include <qmf/engine/Value.h>
+%include <qmf/engine/ObjectId.h>
+%include <qmf/engine/Object.h>
%inline {
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
namespace qmf {
+namespace engine {
-
+}
}
}
diff --git a/qpid/cpp/bindings/qmf/ruby/Makefile.am b/qpid/cpp/bindings/qmf/ruby/Makefile.am
index 0537dd1cd8..34096da9ee 100644
--- a/qpid/cpp/bindings/qmf/ruby/Makefile.am
+++ b/qpid/cpp/bindings/qmf/ruby/Makefile.am
@@ -23,23 +23,22 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src
EXTRA_DIST = ruby.i
BUILT_SOURCES = qmfengine.cpp
-generated_file_list = qmfengine.cpp
rubylibdir = $(RUBY_LIB)
dist_rubylib_DATA = qmf.rb
-$(generated_file_list): $(srcdir)/ruby.i $(srcdir)/../qmfengine.i
+qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i
$(SWIG) -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -o qmfengine.cpp $(srcdir)/ruby.i
rubylibarchdir = $(RUBY_LIB_ARCH)
rubylibarch_LTLIBRARIES = qmfengine.la
qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)"
-qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfagent.la
+qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfengine.la
qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
nodist_qmfengine_la_SOURCES = qmfengine.cpp
-CLEANFILES = $(generated_file_list)
+CLEANFILES = qmfengine.cpp
endif # HAVE_RUBY_DEVEL
diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb
index 16f1058f4a..fbf95215fd 100644
--- a/qpid/cpp/bindings/qmf/ruby/qmf.rb
+++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb
@@ -60,7 +60,19 @@ module Qmf
raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}"
end
- @impl.setAttr(key, v)
+ good = @impl.setAttr(key, v)
+ raise "Invalid attribute '#{key}'" unless good
+ end
+
+ def method_missing(name_in, *args)
+ name = name_in.to_s
+ if name[name.length - 1] == 61
+ attr = name[0..name.length - 2]
+ set_attr(attr, args[0])
+ return
+ end
+
+ super.method_missing(name_in, args)
end
end
@@ -85,12 +97,17 @@ module Qmf
@new_conn_handlers = []
@conn_handlers_to_delete = []
@conn_handlers = []
+ @connected = nil
@thread = Thread.new do
run
end
end
+ def connected?
+ @connected
+ end
+
def kick
@sockEngine.write(".")
@sockEngine.flush
@@ -112,7 +129,6 @@ module Qmf
def run()
eventImpl = Qmfengine::ResilientConnectionEvent.new
- connected = nil
new_handlers = nil
del_handlers = nil
bt_count = 0
@@ -129,7 +145,7 @@ module Qmf
new_handlers.each do |nh|
@conn_handlers << nh
- nh.conn_event_connected() if connected
+ nh.conn_event_connected() if @connected
end
new_handlers = nil
@@ -143,10 +159,10 @@ module Qmf
begin
case eventImpl.kind
when Qmfengine::ResilientConnectionEvent::CONNECTED
- connected = :true
+ @connected = :true
@conn_handlers.each { |h| h.conn_event_connected() }
when Qmfengine::ResilientConnectionEvent::DISCONNECTED
- connected = nil
+ @connected = nil
@conn_handlers.each { |h| h.conn_event_disconnected(eventImpl.errorText) }
when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
@@ -189,8 +205,16 @@ module Qmf
##==============================================================================
class QmfObject
+ include MonitorMixin
attr_reader :impl, :object_class
def initialize(cls, kwargs={})
+ super()
+ @cv = new_cond
+ @sync_count = 0
+ @sync_result = nil
+ @allow_sets = :false
+ @broker = kwargs[:broker] if kwargs.include?(:broker)
+
if cls:
@object_class = cls
@impl = Qmfengine::Object.new(@object_class.impl)
@@ -204,6 +228,22 @@ module Qmf
return ObjectId.new(@impl.getObjectId)
end
+ def properties
+ list = []
+ @object_class.properties.each do |prop|
+ list << [prop, get_attr(prop.name)]
+ end
+ return list
+ end
+
+ def statistics
+ list = []
+ @object_class.statistics.each do |stat|
+ list << [stat, get_attr(stat.name)]
+ end
+ return list
+ end
+
def get_attr(name)
val = value(name)
case val.getType
@@ -212,7 +252,7 @@ module Qmf
when TYPE_SSTR, TYPE_LSTR then val.asString
when TYPE_ABSTIME then val.asInt64
when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
+ when TYPE_REF then ObjectId.new(val.asObjectId)
when TYPE_BOOL then val.asBool
when TYPE_FLOAT then val.asFloat
when TYPE_DOUBLE then val.asDouble
@@ -264,6 +304,103 @@ module Qmf
set_attr(name, get_attr(name) - by)
end
+ def method_missing(name_in, *args)
+ #
+ # Convert the name to a string and determine if it represents an
+ # attribute assignment (i.e. "attr=")
+ #
+ name = name_in.to_s
+ attr_set = (name[name.length - 1] == 61)
+ name = name[0..name.length - 2] if attr_set
+ raise "Sets not permitted on this object" if attr_set && !@allow_sets
+
+ #
+ # If the name matches a property name, set or return the value of the property.
+ #
+ @object_class.properties.each do |prop|
+ if prop.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
+ end
+ end
+
+ #
+ # Do the same for statistics
+ #
+ @object_class.statistics.each do |stat|
+ if stat.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
+ end
+ end
+
+ #
+ # If we still haven't found a match for the name, check to see if
+ # it matches a method name. If so, marshall the arguments and invoke
+ # the method.
+ #
+ @object_class.methods.each do |method|
+ if method.name == name
+ raise "Sets not permitted on methods" if attr_set
+ timeout = 30
+ synchronize do
+ @sync_count = 1
+ @impl.invokeMethod(name, _marshall(method, args), self)
+ @broker.conn.kick if @broker
+ unless @cv.wait(timeout) { @sync_count == 0 }
+ raise "Timed out waiting for response"
+ end
+ end
+
+ return @sync_result
+ end
+ end
+
+ #
+ # This name means nothing to us, pass it up the line to the parent
+ # class's handler.
+ #
+ super.method_missing(name_in, args)
+ end
+
+ def _method_result(result)
+ synchronize do
+ @sync_result = result
+ @sync_count -= 1
+ @cv.signal
+ end
+ end
+
+ #
+ # Convert a Ruby array of arguments (positional) into a Value object of type "map".
+ #
+ private
+ def _marshall(schema, args)
+ map = Qmfengine::Value.new(TYPE_MAP)
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ map.insert(arg.name, Qmfengine::Value.new(arg.typecode))
+ end
+ end
+
+ marshalled = Arguments.new(map)
+ idx = 0
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ marshalled[arg.name] = args[idx] unless args[idx] == nil
+ idx += 1
+ end
+ end
+
+ return marshalled.map
+ end
+
private
def value(name)
val = @impl.getValue(name.to_s)
@@ -277,6 +414,7 @@ module Qmf
class AgentObject < QmfObject
def initialize(cls, kwargs={})
super(cls, kwargs)
+ @allow_sets = :true
end
def destroy
@@ -296,20 +434,22 @@ module Qmf
end
def update()
+ raise "No linkage to broker" unless @broker
+ newer = @broker.console.objects(Query.new(:object_id => object_id))
+ raise "Expected exactly one update for this object" unless newer.size == 1
+ merge_update(newer[0])
end
- def mergeUpdate(newObject)
+ def merge_update(new_object)
+ @impl.merge(new_object.impl)
end
def deleted?()
- @delete_time > 0
+ @impl.isDeleted
end
def index()
end
-
- def method_missing(name, *args)
- end
end
class ObjectId
@@ -323,17 +463,29 @@ module Qmf
end
def object_num_high
- return @impl.getObjectNumHi
+ @impl.getObjectNumHi
end
def object_num_low
- return @impl.getObjectNumLo
+ @impl.getObjectNumLo
+ end
+
+ def broker_bank
+ @impl.getBrokerBank
+ end
+
+ def agent_bank
+ @impl.getAgentBank
end
def ==(other)
return (@impl.getObjectNumHi == other.impl.getObjectNumHi) &&
(@impl.getObjectNumLo == other.impl.getObjectNumLo)
end
+
+ def to_s
+ @impl.str
+ end
end
class Arguments
@@ -362,6 +514,14 @@ module Qmf
@by_hash.each { |k, v| yield(k, v) }
end
+ def method_missing(name, *args)
+ if @by_hash.include?(name.to_s)
+ return @by_hash[name.to_s]
+ end
+
+ super.method_missing(name, args)
+ end
+
def by_key(key)
val = @map.byKey(key)
case val.getType
@@ -370,7 +530,7 @@ module Qmf
when TYPE_SSTR, TYPE_LSTR then val.asString
when TYPE_ABSTIME then val.asInt64
when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
+ when TYPE_REF then ObjectId.new(val.asObjectId)
when TYPE_BOOL then val.asBool
when TYPE_FLOAT then val.asFloat
when TYPE_DOUBLE then val.asDouble
@@ -407,6 +567,32 @@ module Qmf
end
end
+ class MethodResponse
+ def initialize(impl)
+ @impl = Qmfengine::MethodResponse.new(impl)
+ end
+
+ def status
+ @impl.getStatus
+ end
+
+ def exception
+ @impl.getException
+ end
+
+ def text
+ exception.asString
+ end
+
+ def args
+ Arguments.new(@impl.getArgs)
+ end
+
+ def method_missing(name, *extra_args)
+ args.__send__(name, extra_args)
+ end
+ end
+
##==============================================================================
## QUERY
##==============================================================================
@@ -421,13 +607,13 @@ module Qmf
if kwargs.include?(:key)
@impl = Qmfengine::Query.new(kwargs[:key])
elsif kwargs.include?(:object_id)
- @impl = Qmfengine::Query.new(kwargs[:object_id])
+ @impl = Qmfengine::Query.new(kwargs[:object_id].impl)
else
package = kwargs[:package] if kwargs.include?(:package)
if kwargs.include?(:class)
@impl = Qmfengine::Query.new(kwargs[:class], package)
else
- raise ArgumentError, "Invalid arguments, use :key or :class[,:package]"
+ raise ArgumentError, "Invalid arguments, use :key, :object_id or :class[,:package]"
end
end
end
@@ -470,6 +656,18 @@ module Qmf
def name
@impl.getName
end
+
+ def direction
+ @impl.getDirection
+ end
+
+ def typecode
+ @impl.getType
+ end
+
+ def to_s
+ name
+ end
end
class SchemaMethod
@@ -496,6 +694,10 @@ module Qmf
def name
@impl.getName
end
+
+ def to_s
+ name
+ end
end
class SchemaProperty
@@ -516,6 +718,10 @@ module Qmf
def name
@impl.getName
end
+
+ def to_s
+ name
+ end
end
class SchemaStatistic
@@ -533,6 +739,10 @@ module Qmf
def name
@impl.getName
end
+
+ def to_s
+ name
+ end
end
class SchemaClassKey
@@ -541,12 +751,16 @@ module Qmf
@impl = i
end
- def get_package()
- @impl.getPackageName()
+ def package_name
+ @impl.getPackageName
+ end
+
+ def class_name
+ @impl.getClassName
end
- def get_class()
- @impl.getClassName()
+ def to_s
+ @impl.asString
end
end
@@ -590,7 +804,15 @@ module Qmf
@impl.addMethod(meth.impl)
end
- def name
+ def class_key
+ SchemaClassKey.new(@impl.getClassKey)
+ end
+
+ def package_name
+ @impl.getClassKey.getPackageName
+ end
+
+ def class_name
@impl.getClassKey.getClassName
end
end
@@ -643,7 +865,7 @@ module Qmf
def initialize(handler = nil, kwargs={})
super()
@handler = handler
- @impl = Qmfengine::ConsoleEngine.new
+ @impl = Qmfengine::Console.new
@event = Qmfengine::ConsoleEvent.new
@broker_list = []
@cv = new_cond
@@ -662,7 +884,7 @@ module Qmf
@broker_list.delete(broker)
end
- def get_packages()
+ def packages()
plist = []
count = @impl.packageCount
for i in 0...count
@@ -671,7 +893,7 @@ module Qmf
return plist
end
- def get_classes(package, kind=CLASS_OBJECT)
+ def classes(package, kind=CLASS_OBJECT)
clist = []
count = @impl.classCount(package)
for i in 0...count
@@ -708,7 +930,7 @@ module Qmf
end
end
- def get_agents(broker = nil)
+ def agents(broker = nil)
blist = []
if broker
blist << broker
@@ -727,11 +949,17 @@ module Qmf
return agents
end
- def get_objects(query, kwargs = {})
+ def objects(query, kwargs = {})
timeout = 30
+ kwargs.merge!(query) if query.class == Hash
+
if kwargs.include?(:timeout)
timeout = kwargs[:timeout]
+ kwargs.delete(:timeout)
end
+
+ query = Query.new(kwargs) if query.class == Hash
+
synchronize do
@sync_count = 1
@sync_result = []
@@ -745,6 +973,18 @@ module Qmf
end
end
+ # Return one and only one object or nil.
+ def object(query, kwargs = {})
+ objs = objects(query, kwargs)
+ return objs.length == 1 ? objs[0] : nil
+ end
+
+ # Return the first of potentially many objects.
+ def first_object(query, kwargs = {})
+ objs = objects(query, kwargs)
+ return objs.length > 0 ? objs[0] : nil
+ end
+
def _get_result(list, context)
synchronize do
list.each do |item|
@@ -769,15 +1009,20 @@ module Qmf
valid = @impl.getEvent(@event)
while valid
count += 1
- puts "Console Event: #{@event.kind}"
case @event.kind
when Qmfengine::ConsoleEvent::AGENT_ADDED
+ @handler.agent_added(AgentProxy.new(@event.agent, nil)) if @handler
when Qmfengine::ConsoleEvent::AGENT_DELETED
+ @handler.agent_deleted(AgentProxy.new(@event.agent, nil)) if @handler
when Qmfengine::ConsoleEvent::NEW_PACKAGE
+ @handler.new_package(@event.name) if @handler
when Qmfengine::ConsoleEvent::NEW_CLASS
+ @handler.new_class(SchemaClassKey.new(@event.classKey)) if @handler
when Qmfengine::ConsoleEvent::OBJECT_UPDATE
+ @handler.object_update(ConsoleObject.new(nil, :impl => @event.object), @event.hasProps, @event.hasStats) if @handler
when Qmfengine::ConsoleEvent::EVENT_RECEIVED
when Qmfengine::ConsoleEvent::AGENT_HEARTBEAT
+ @handler.agent_heartbeat(AgentProxy.new(@event.agent, nil), @event.timestamp) if @handler
when Qmfengine::ConsoleEvent::METHOD_RESPONSE
end
@impl.popEvent
@@ -798,14 +1043,23 @@ module Qmf
def label
@impl.getLabel
end
+
+ def broker_bank
+ @impl.getBrokerBank
+ end
+
+ def agent_bank
+ @impl.getAgentBank
+ end
end
class Broker < ConnectionHandler
include MonitorMixin
- attr_reader :impl
+ attr_reader :impl, :conn, :console, :broker_bank
def initialize(console, conn)
super()
+ @broker_bank = 1
@console = console
@conn = conn
@session = nil
@@ -825,7 +1079,7 @@ module Qmf
@operational = :false
end
- def waitForStable(timeout = nil)
+ def wait_for_stable(timeout = nil)
synchronize do
return if @stable
if timeout
@@ -850,7 +1104,6 @@ module Qmf
valid = @impl.getEvent(@event)
while valid
count += 1
- puts "Broker Event: #{@event.kind}"
case @event.kind
when Qmfengine::BrokerEvent::BROKER_INFO
when Qmfengine::BrokerEvent::DECLARE_QUEUE
@@ -871,9 +1124,12 @@ module Qmf
when Qmfengine::BrokerEvent::QUERY_COMPLETE
result = []
for idx in 0...@event.queryResponse.getObjectCount
- result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx))
+ result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx), :broker => self)
end
@console._get_result(result, @event.context)
+ when Qmfengine::BrokerEvent::METHOD_RESPONSE
+ obj = @event.context
+ obj._method_result(MethodResponse.new(@event.methodResponse))
end
@impl.popEvent
valid = @impl.getEvent(@event)
@@ -946,7 +1202,7 @@ module Qmf
end
@conn = nil
@handler = handler
- @impl = Qmfengine::AgentEngine.new(@agentLabel)
+ @impl = Qmfengine::Agent.new(@agentLabel)
@event = Qmfengine::AgentEvent.new
@xmtMessage = Qmfengine::Message.new
end
@@ -1050,5 +1306,4 @@ module Qmf
do_events
end
end
-
end
diff --git a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
index 67591319ee..426a284e7d 100755
--- a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
+++ b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
@@ -40,6 +40,9 @@ class Model
@parent_class.add_property(Qmf::SchemaProperty.new("int16val", Qmf::TYPE_INT16))
@parent_class.add_property(Qmf::SchemaProperty.new("int8val", Qmf::TYPE_INT8))
+ @parent_class.add_property(Qmf::SchemaProperty.new("sstrval", Qmf::TYPE_SSTR))
+ @parent_class.add_property(Qmf::SchemaProperty.new("lstrval", Qmf::TYPE_LSTR))
+
@parent_class.add_statistic(Qmf::SchemaStatistic.new("queryCount", Qmf::TYPE_UINT32, :unit => "query", :desc => "Query count"))
method = Qmf::SchemaMethod.new("echo", :desc => "Check responsiveness of the agent object")
@@ -50,6 +53,14 @@ class Model
method.add_argument(Qmf::SchemaArgument.new("test", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN))
@parent_class.add_method(method)
+ method = Qmf::SchemaMethod.new("set_short_string", :desc => "Set the short string value in the object")
+ method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("set_long_string", :desc => "Set the long string value in the object")
+ method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
method = Qmf::SchemaMethod.new("create_child", :desc => "Create a new child object")
method.add_argument(Qmf::SchemaArgument.new("child_name", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN))
method.add_argument(Qmf::SchemaArgument.new("child_ref", Qmf::TYPE_REF, :dir => Qmf::DIR_OUT))
@@ -84,68 +95,74 @@ class App < Qmf::AgentHandler
def method_call(context, name, object_id, args, userId)
# puts "Method: user=#{userId} context=#{context} method=#{name} object_num=#{object_id.object_num_low if object_id} args=#{args}"
+ retCode = 0
+ retText = "OK"
+
if name == "echo"
@agent.method_response(context, 0, "OK", args)
elsif name == "set_numerics"
- retCode = 0
- retText = "OK"
if args['test'] == "big"
- @parent.set_attr("uint64val", 0x9494949449494949)
- @parent.set_attr("uint32val", 0xa5a55a5a)
- @parent.set_attr("uint16val", 0xb66b)
- @parent.set_attr("uint8val", 0xc7)
+ @parent.uint64val = 0x9494949449494949
+ @parent.uint32val = 0xa5a55a5a
+ @parent.uint16val = 0xb66b
+ @parent.uint8val = 0xc7
- @parent.set_attr("int64val", 1000000000000000000)
- @parent.set_attr("int32val", 1000000000)
- @parent.set_attr("int16val", 10000)
- @parent.set_attr("int8val", 100)
+ @parent.int64val = 1000000000000000000
+ @parent.int32val = 1000000000
+ @parent.int16val = 10000
+ @parent.int8val = 100
elsif args['test'] == "small"
- @parent.set_attr("uint64val", 4)
- @parent.set_attr("uint32val", 5)
- @parent.set_attr("uint16val", 6)
- @parent.set_attr("uint8val", 7)
+ @parent.uint64val = 4
+ @parent.uint32val = 5
+ @parent.uint16val = 6
+ @parent.uint8val = 7
- @parent.set_attr("int64val", 8)
- @parent.set_attr("int32val", 9)
- @parent.set_attr("int16val", 10)
- @parent.set_attr("int8val", 11)
+ @parent.int64val = 8
+ @parent.int32val = 9
+ @parent.int16val = 10
+ @parent.int8val = 11
elsif args['test'] == "negative"
- @parent.set_attr("uint64val", 0)
- @parent.set_attr("uint32val", 0)
- @parent.set_attr("uint16val", 0)
- @parent.set_attr("uint8val", 0)
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
- @parent.set_attr("int64val", -10000000000)
- @parent.set_attr("int32val", -100000)
- @parent.set_attr("int16val", -1000)
- @parent.set_attr("int8val", -100)
+ @parent.int64val = -10000000000
+ @parent.int32val = -100000
+ @parent.int16val = -1000
+ @parent.int8val = -100
else
retCode = 1
retText = "Invalid argument value for test"
end
- @agent.method_response(context, retCode, retText, args)
+ elsif name == "set_short_string"
+ @parent.sstrval = args['value']
+
+ elsif name == "set_long_string"
+ @parent.lstrval = args['value']
elsif name == "create_child"
oid = @agent.alloc_object_id(2)
args['child_ref'] = oid
@child = Qmf::AgentObject.new(@model.child_class)
- @child.set_attr("name", args.by_key("child_name"))
+ @child.name = args.by_key("child_name")
@child.set_object_id(oid)
- @agent.method_response(context, 0, "OK", args)
elsif name == "probe_userid"
args['userid'] = userId
- @agent.method_response(context, 0, "OK", args)
else
- @agent.method_response(context, 1, "Unimplemented Method: #{name}", args)
+ retCode = 1
+ retText = "Unimplemented Method: #{name}"
end
+
+ @agent.method_response(context, retCode, retText, args)
end
def main
@@ -161,18 +178,18 @@ class App < Qmf::AgentHandler
@agent.set_connection(@connection)
@parent = Qmf::AgentObject.new(@model.parent_class)
- @parent.set_attr("name", "Parent One")
- @parent.set_attr("state", "OPERATIONAL")
-
- @parent.set_attr("uint64val", 0)
- @parent.set_attr("uint32val", 0)
- @parent.set_attr("uint16val", 0)
- @parent.set_attr("uint8val", 0)
-
- @parent.set_attr("int64val", 0)
- @parent.set_attr("int32val", 0)
- @parent.set_attr("int16val", 0)
- @parent.set_attr("int8val", 0)
+ @parent.name = "Parent One"
+ @parent.state = "OPERATIONAL"
+
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
+
+ @parent.int64val = 0
+ @parent.int32val = 0
+ @parent.int16val = 0
+ @parent.int8val = 0
@parent_oid = @agent.alloc_object_id(1)
@parent.set_object_id(@parent_oid)
diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console.rb b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
index c071829f09..0fa856c724 100755
--- a/qpid/cpp/bindings/qmf/tests/ruby_console.rb
+++ b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
@@ -24,13 +24,46 @@ require 'socket'
class App < Qmf::ConsoleHandler
+ def agent_added(agent)
+ puts "AgentAdded: #{agent.label} broker=#{agent.broker_bank} agent=#{agent.agent_bank}"
+ end
+
+ def agent_deleted(agent)
+ puts "AgentDeleted: #{agent.label}"
+ end
+
+ def new_package(package)
+ puts "NewPackage: #{package}"
+ end
+
+ def new_class(class_key)
+ puts "NewClass: #{class_key}"
+ end
+
+ def object_update(object, hasProps, hasStats)
+ puts "ObjectUpdate: #{object.object_class.class_name} props=#{hasProps} stats=#{hasStats}"
+ puts " broker-bank=#{object.object_id.broker_bank}"
+ puts " agent-bank=#{object.object_id.agent_bank}"
+ puts " package=#{object.object_class.package_name}"
+ end
+
+ def event_received(event); end
+
+ def agent_heartbeat(agent, timestamp)
+ puts "AgentHeartbeat: #{agent.label} time=#{timestamp/1000000000}"
+ end
+
+ def method_response(resp); end
+ def broker_info(broker); end
+
+
def dump_schema
- packages = @qmfc.get_packages
+ packages = @qmfc.packages
puts "----- Packages -----"
packages.each do |p|
puts p
puts " ----- Object Classes -----"
- classes = @qmfc.get_classes(p)
+ classes = @qmfc.classes(p)
classes.each do |c|
puts " #{c.name}"
@@ -59,7 +92,7 @@ class App < Qmf::ConsoleHandler
end
puts " ----- Event Classes -----"
- classes = @qmfc.get_classes(p, Qmf::CLASS_EVENT)
+ classes = @qmfc.classes(p, Qmf::CLASS_EVENT)
classes.each do |c|
puts " #{c.name}"
puts " ---- Args ----"
@@ -74,17 +107,17 @@ class App < Qmf::ConsoleHandler
def main
@settings = Qmf::ConnectionSettings.new
- @settings.set_attr("host", ARGV[0]) if ARGV.size > 0
- @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1
+ @settings.host = ARGV[0] if ARGV.size > 0
+ @settings.port = ARGV[1].to_i if ARGV.size > 1
@connection = Qmf::Connection.new(@settings)
- @qmfc = Qmf::Console.new
+ @qmfc = Qmf::Console.new(self)
@broker = @qmfc.add_connection(@connection)
- @broker.waitForStable
+ @broker.wait_for_stable
- dump_schema
+ ##dump_schema
- agents = @qmfc.get_agents()
+ agents = @qmfc.agents()
puts "---- Agents ----"
agents.each do |a|
puts " => #{a.label}"
@@ -92,13 +125,30 @@ class App < Qmf::ConsoleHandler
puts "----"
for idx in 0...20
- blist = @qmfc.get_objects(Qmf::Query.new(:class => "broker"))
+ blist = @qmfc.objects(Qmf::Query.new(:class => "broker"))
puts "---- Brokers ----"
blist.each do |b|
puts " ---- Broker ----"
- puts " systemRef: #{b.get_attr('systemRef')}"
- puts " port : #{b.get_attr('port')}"
- puts " uptime : #{b.get_attr('uptime') / 1000000000}"
+ puts " systemRef: #{b.systemRef}"
+ puts " port : #{b.port}"
+ puts " uptime : #{b.uptime / 1000000000}"
+ puts " properties : #{b.properties}"
+ puts " statistics : #{b.statistics}"
+
+ for rep in 0...1
+ puts " Pinging..."
+ ret = b.echo(45, 'text string')
+ puts " status=#{ret.status} text=#{ret.exception.asString} seq=#{ret.args.sequence} body=#{ret.args.body}"
+ end
+ end
+ puts "----"
+
+ qlist = @qmfc.objects(Qmf::Query.new(:package => "org.apache.qpid.broker",
+ :class => "queue"))
+ puts "---- Queues ----"
+ qlist.each do |q|
+ puts " ---- Queue ----"
+ puts " name : #{q.name}"
end
puts "----"
sleep(5)
diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb
new file mode 100755
index 0000000000..b72c8e3806
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb
@@ -0,0 +1,194 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'test_base'
+
+class ConsoleTest < ConsoleTestBase
+
+ def test_A_agent_presence
+ assert(@connection.connected?, "Connection not connected")
+
+ agents = []
+ count = 0
+ while agents.size == 0
+ agents = @qmfc.objects(Qmf::Query.new(:class => "agent"))
+ sleep(1)
+ count += 1
+ fail("Timed out waiting for remote agent") if count > 10
+ end
+
+ agentList = @qmfc.agents
+ assert_equal(agentList.size, 2, "Number of agents reported by Console")
+ end
+
+ def test_A_connection_settings
+ begin
+ @settings.bogusAttribute = 25
+ fail("Connection settings accepted bogus attribute")
+ rescue
+ end
+ end
+
+ def test_B_basic_method_invocation
+ parent = @qmfc.object(:class => "parent")
+ assert(parent, "Number of 'parent' objects")
+ for seq in 0...10
+ result = parent.echo(seq)
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+ assert_equal(result.args.sequence, seq, "Echo Response Sequence")
+ end
+
+ result = parent.set_numerics("bogus")
+ assert_equal(result.status, 1)
+ assert_equal(result.text, "Invalid argument value for test")
+ end
+
+ def test_C_basic_types_numeric_big
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("big")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 0x9494949449494949)
+ assert_equal(parent.uint32val, 0xA5A55A5A)
+ assert_equal(parent.uint16val, 0xB66B)
+ assert_equal(parent.uint8val, 0xC7)
+
+ assert_equal(parent.int64val, 1000000000000000000)
+ assert_equal(parent.int32val, 1000000000)
+ assert_equal(parent.int16val, 10000)
+ assert_equal(parent.int8val, 100)
+ end
+
+ def test_C_basic_types_numeric_small
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("small")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 4)
+ assert_equal(parent.uint32val, 5)
+ assert_equal(parent.uint16val, 6)
+ assert_equal(parent.uint8val, 7)
+
+ assert_equal(parent.int64val, 8)
+ assert_equal(parent.int32val, 9)
+ assert_equal(parent.int16val, 10)
+ assert_equal(parent.int8val, 11)
+ end
+
+ def test_C_basic_types_numeric_negative
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("negative")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 0)
+ assert_equal(parent.uint32val, 0)
+ assert_equal(parent.uint16val, 0)
+ assert_equal(parent.uint8val, 0)
+
+ assert_equal(parent.int64val, -10000000000)
+ assert_equal(parent.int32val, -100000)
+ assert_equal(parent.int16val, -1000)
+ assert_equal(parent.int8val, -100)
+ end
+
+ def test_C_basic_types_string_short
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ strings = []
+ strings << ""
+ strings << "A"
+ strings << "BC"
+ strings << "DEF"
+ strings << "GHIJKLMNOPQRSTUVWXYZ"
+ big = "a"
+ for i in 0...270
+ big << "X"
+ end
+ strings << big
+
+ strings.each do |str|
+ result = parent.set_short_string(str)
+ assert_equal(result.status, 0, "Method Response Status")
+ compare = str
+ compare = compare[0..254] if compare.size > 255
+ assert_equal(result.args.value, compare, "Value returned by method")
+ parent.update
+ assert_equal(parent.sstrval, compare, "Value stored in the object")
+ end
+ end
+
+ def test_C_basic_types_string_long
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ strings = []
+ strings << ""
+ strings << "A"
+ strings << "BC"
+ strings << "DEF"
+ strings << "GHIJKLMNOPQRSTUVWXYZ"
+ big = "a"
+ for i in 0...270
+ big << "X"
+ end
+ strings << big
+
+ strings.each do |str|
+ result = parent.set_long_string(str)
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.args.value, str, "Value returned by method")
+ parent.update
+ assert_equal(parent.lstrval, str, "Value stored in the object")
+ end
+ end
+
+ def test_D_userid_for_method
+ parent = @qmfc.object(:class => "parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.probe_userid
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.args.userid, "anonymous")
+ end
+
+end
+
+app = ConsoleTest.new
+
+
+
diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests
index 01d7221ac6..b5545d736d 100755
--- a/qpid/cpp/bindings/qmf/tests/run_interop_tests
+++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests
@@ -88,11 +88,19 @@ if test -d ${PYTHON_DIR} ; then
echo " Ruby agent started at pid $AGENT_PID"
${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
RETCODE=$?
- stop_ruby_agent
if test x$RETCODE != x0; then
echo "FAIL qmf interop tests (Ruby Agent)";
TESTS_FAILED=1
fi
+
+ echo " Ruby Agent (external storage) vs. Ruby Console"
+ ruby -I${MY_DIR} -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/ruby_console_test.rb localhost $BROKER_PORT $@
+ RETCODE=$?
+ stop_ruby_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Ruby Console/Ruby Agent)";
+ TESTS_FAILED=1
+ fi
fi
# Also against the Pure-Python console:
diff --git a/qpid/cpp/bindings/qmf/tests/test_base.rb b/qpid/cpp/bindings/qmf/tests/test_base.rb
new file mode 100644
index 0000000000..cb7fd9d4f9
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/test_base.rb
@@ -0,0 +1,73 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qmf'
+require 'socket'
+
+class ConsoleTestBase < Qmf::ConsoleHandler
+ def initialize
+ @settings = Qmf::ConnectionSettings.new
+ @settings.host = ARGV[0] if ARGV.size > 0
+ @settings.port = ARGV[1].to_i if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @qmfc = Qmf::Console.new
+
+ @broker = @qmfc.add_connection(@connection)
+ @broker.wait_for_stable
+
+ tests = []
+ methods.each do |m|
+ name = m.to_s
+ tests << name if name[0..4] == "test_"
+ end
+
+ failures = 0
+
+ tests.sort.each do |t|
+ begin
+ print "#{t}..."
+ $stdout.flush
+ send(t)
+ puts " Pass"
+ rescue
+ puts " Fail: #{$!}"
+ failures += 1
+ end
+ end
+
+ @qmfc.del_connection(@broker)
+ exit(1) if failures > 0
+ end
+
+ def assert_equal(left, right, in_text=nil)
+ text = " (#{in_text})" if in_text
+ raise "Assertion failed: #{left} != #{right}#{text}" unless left == right
+ end
+
+ def assert(condition, in_text=nil)
+ text = " (#{in_text})" if in_text
+ raise "Assertion failed: #{left} != #{right}#{text}" unless condition
+ end
+
+ def fail(text)
+ raise text
+ end
+end
diff --git a/qpid/cpp/boost-1.32-support/supressions b/qpid/cpp/boost-1.32-support/supressions
index 0747e32cc7..c2b4392566 100644
--- a/qpid/cpp/boost-1.32-support/supressions
+++ b/qpid/cpp/boost-1.32-support/supressions
@@ -789,3 +789,79 @@
fun:getaddrinfo
fun:_ZNK4qpid3sys6Socket7connectERKSst
}
+{
+ dl 0
+ Memcheck:Leak
+ fun:*dl*
+}
+
+{
+ dl 1
+ Memcheck:Leak
+ fun:*
+ fun:*dl*
+}
+
+{
+ dl 2
+ fun:*
+ fun:*
+ Memcheck:Leak
+ fun:*dl*
+}
+
+{
+ Znwm
+ Memcheck:Leak
+ fun:_Znwm
+}
+
+{
+ Znwj
+ Memcheck:Leak
+ fun:_Znwj
+}
+
+{
+ Znaj
+ Memcheck:Leak
+ fun:_Znaj
+}
+
+{
+ libc res nsend
+ Memcheck:Leak
+ fun:malloc
+ fun:__libc_res_nsend
+}
+
+{
+ new exitfn
+ Memcheck:Leak
+ fun:malloc
+ fun:__new_exitfn
+}
+
+{
+ pthread mutex unlock
+ Memcheck:Param
+ futex(uaddr2)
+ fun:__lll_mutex_unlock_wake
+ fun:pthread_mutex_unlock
+}
+
+{
+ sasl 1
+ Memcheck:Leak
+ fun:*
+ fun:sasl*
+}
+
+{
+ sasl 2
+ Memcheck:Leak
+ fun:*
+ obj:*
+ fun:sasl*
+}
+
diff --git a/qpid/cpp/etc/CMakeLists.txt b/qpid/cpp/etc/CMakeLists.txt
new file mode 100644
index 0000000000..03121b364a
--- /dev/null
+++ b/qpid/cpp/etc/CMakeLists.txt
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+install(FILES qpidd.conf qpidc.conf DESTINATION ${QPID_INSTALL_CONFDIR})
diff --git a/qpid/cpp/examples/messaging/client.cpp b/qpid/cpp/examples/messaging/client.cpp
index 45c065880b..de6d7768df 100644
--- a/qpid/cpp/examples/messaging/client.cpp
+++ b/qpid/cpp/examples/messaging/client.cpp
@@ -63,7 +63,7 @@ int main(int argc, char** argv) {
request.setContent(s[i]);
sender.send(request);
Message response = receiver.fetch();
- std::cout << request.getContent().asString() << " -> " << response.getContent().asString() << std::endl;
+ std::cout << request.getContent() << " -> " << response.getContent() << std::endl;
}
connection.close();
return 0;
diff --git a/qpid/cpp/examples/messaging/map_receiver.cpp b/qpid/cpp/examples/messaging/map_receiver.cpp
index e6557b1560..f97c44eebd 100644
--- a/qpid/cpp/examples/messaging/map_receiver.cpp
+++ b/qpid/cpp/examples/messaging/map_receiver.cpp
@@ -20,6 +20,7 @@
*/
#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapView.h>
#include <qpid/messaging/Message.h>
#include <qpid/messaging/Receiver.h>
#include <qpid/messaging/Session.h>
@@ -42,7 +43,8 @@ int main(int argc, char** argv) {
Session session = connection.newSession();
Receiver receiver = session.createReceiver("message_queue");
Message message = receiver.fetch();
- std::cout << message.getContent().asMap() << std::endl;
+ MapView content(message);
+ std::cout << content << std::endl;
session.acknowledge();
receiver.cancel();
connection.close();
diff --git a/qpid/cpp/examples/messaging/map_sender.cpp b/qpid/cpp/examples/messaging/map_sender.cpp
index 9301c1fe1f..02c6433836 100644
--- a/qpid/cpp/examples/messaging/map_sender.cpp
+++ b/qpid/cpp/examples/messaging/map_sender.cpp
@@ -20,6 +20,7 @@
*/
#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapContent.h>
#include <qpid/messaging/Message.h>
#include <qpid/messaging/Sender.h>
#include <qpid/messaging/Session.h>
@@ -43,14 +44,16 @@ int main(int argc, char** argv) {
Sender sender = session.createSender("message_queue");
Message message;
- message.getContent()["id"] = 987654321;
- message.getContent()["name"] = "Widget";
- message.getContent()["price"] = 0.99;//bad use of floating point number, just an example!
+ MapContent content(message);
+ content["id"] = 987654321;
+ content["name"] = "Widget";
+ content["price"] = 0.99;//bad use of floating point number, just an example!
Variant::List colours;
colours.push_back(Variant("red"));
colours.push_back(Variant("green"));
colours.push_back(Variant("white"));
- message.getContent()["colours"] = colours;
+ content["colours"] = colours;
+ content.encode();
sender.send(message);
session.sync();
diff --git a/qpid/cpp/examples/messaging/queue_listener.cpp b/qpid/cpp/examples/messaging/queue_listener.cpp
index 099e8e145a..92a0eed5ed 100644
--- a/qpid/cpp/examples/messaging/queue_listener.cpp
+++ b/qpid/cpp/examples/messaging/queue_listener.cpp
@@ -47,8 +47,8 @@ bool Listener::isFinished() { return finished; }
void Listener::received(Message& message)
{
- std::cout << "Message: " << message.getContent().asString() << std::endl;
- if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Message: " << message.getContent() << std::endl;
+ if (message.getContent() == "That's all, folks!") {
std::cout << "Shutting down listener" << std::endl;
receiver.cancel();
finished = true;
diff --git a/qpid/cpp/examples/messaging/queue_receiver.cpp b/qpid/cpp/examples/messaging/queue_receiver.cpp
index 83a44b2ca9..40f863eb30 100644
--- a/qpid/cpp/examples/messaging/queue_receiver.cpp
+++ b/qpid/cpp/examples/messaging/queue_receiver.cpp
@@ -24,16 +24,10 @@
#include <qpid/messaging/Receiver.h>
#include <qpid/messaging/Session.h>
-#include <cstdlib>
#include <iostream>
-#include <sstream>
-
using namespace qpid::messaging;
-using std::stringstream;
-using std::string;
-
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
@@ -47,7 +41,7 @@ int main(int argc, char** argv) {
Message message = receiver.fetch();
std::cout << "Message: " << message.getContent() << std::endl;
session.acknowledge();
- if (message.getContent().asString() == "That's all, folks!") {
+ if (message.getContent() == "That's all, folks!") {
std::cout << "Cancelling receiver" << std::endl;
receiver.cancel();
break;
diff --git a/qpid/cpp/examples/messaging/queue_sender.cpp b/qpid/cpp/examples/messaging/queue_sender.cpp
index 637e7eb8e4..1396e26d5c 100644
--- a/qpid/cpp/examples/messaging/queue_sender.cpp
+++ b/qpid/cpp/examples/messaging/queue_sender.cpp
@@ -26,14 +26,10 @@
#include <cstdlib>
#include <iostream>
-
#include <sstream>
using namespace qpid::messaging;
-using std::stringstream;
-using std::string;
-
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
int count = argc>2 ? atoi(argv[2]) : 10;
@@ -45,14 +41,13 @@ int main(int argc, char** argv) {
// Now send some messages ...
for (int i=0; i<count; i++) {
- Message message;
- message.getContent() << "Message " << i;
- sender.send(message);
+ std::stringstream content;
+ content << "Message " << i;
+ sender.send(Message(content.str()));
}
- // And send a final message to indicate termination.
- Message message("That's all, folks!");
- sender.send(message);
+ // And send a final message to indicate termination.
+ sender.send(Message("That's all, folks!"));
session.sync();
connection.close();
return 0;
diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp
index 38f4601ff6..024832f914 100644
--- a/qpid/cpp/examples/messaging/server.cpp
+++ b/qpid/cpp/examples/messaging/server.cpp
@@ -51,17 +51,17 @@ int main(int argc, char** argv) {
const Address& address = request.getReplyTo();
if (address) {
Sender sender = session.createSender(address);
- std::string s = request.getContent().asString();
+ std::string s = request.getContent();
std::transform(s.begin(), s.end(), s.begin(), toupper);
Message response(s);
sender.send(response);
std::cout << "Processed request: "
- << request.getContent().asString()
+ << request.getContent()
<< " -> "
- << response.getContent().asString() << std::endl;
+ << response.getContent() << std::endl;
session.acknowledge();
} else {
- std::cerr << "Error: no reply address specified for request: " << request.getContent().asString() << std::endl;
+ std::cerr << "Error: no reply address specified for request: " << request.getContent() << std::endl;
session.reject(request);
}
}
diff --git a/qpid/cpp/examples/messaging/topic_listener.cpp b/qpid/cpp/examples/messaging/topic_listener.cpp
index 700e03cdf9..ba999c03a7 100644
--- a/qpid/cpp/examples/messaging/topic_listener.cpp
+++ b/qpid/cpp/examples/messaging/topic_listener.cpp
@@ -48,8 +48,8 @@ bool Listener::isFinished() { return finished; }
void Listener::received(Message& message)
{
- std::cout << "Message: " << message.getContent().asString() << std::endl;
- if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Message: " << message.getContent() << std::endl;
+ if (message.getContent() == "That's all, folks!") {
std::cout << "Shutting down listener" << std::endl;
receiver.cancel();
finished = true;
diff --git a/qpid/cpp/examples/messaging/topic_receiver.cpp b/qpid/cpp/examples/messaging/topic_receiver.cpp
index 063f0d9cb0..7352a91b30 100644
--- a/qpid/cpp/examples/messaging/topic_receiver.cpp
+++ b/qpid/cpp/examples/messaging/topic_receiver.cpp
@@ -47,8 +47,8 @@ int main(int argc, char** argv) {
Receiver receiver = session.createReceiver(Address("news_service", "topic"), filter);
while (true) {
Message message = receiver.fetch();
- std::cout << "Message: " << message.getContent().asString() << std::endl;
- if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Message: " << message.getContent() << std::endl;
+ if (message.getContent() == "That's all, folks!") {
std::cout << "Cancelling receiver" << std::endl;
receiver.cancel();
break;
diff --git a/qpid/cpp/examples/qmf-agent/Makefile b/qpid/cpp/examples/qmf-agent/Makefile
index e652edb1a2..5b1afc4b01 100644
--- a/qpid/cpp/examples/qmf-agent/Makefile
+++ b/qpid/cpp/examples/qmf-agent/Makefile
@@ -27,7 +27,7 @@ CC = gcc
LIB_DIR = $(QPID_DIR)/cpp/src/.libs
CC_INCLUDES = -I$(SRC_DIR) -I$(QPID_DIR)/cpp/include -I$(GEN_DIR)
CC_FLAGS = -g -O3
-LD_FLAGS = -lqmfagent -lqmfcommon -L$(LIB_DIR)
+LD_FLAGS = -lqmf -L$(LIB_DIR)
SPEC_DIR = $(QPID_DIR)/specs
MGEN_DIR = $(QPID_DIR)/cpp/managementgen
MGEN = $(MGEN_DIR)/qmf-gen
diff --git a/qpid/cpp/include/qmf/ConnectionSettings.h b/qpid/cpp/include/qmf/ConnectionSettings.h
index 9bd6922a56..11af73d797 100644
--- a/qpid/cpp/include/qmf/ConnectionSettings.h
+++ b/qpid/cpp/include/qmf/ConnectionSettings.h
@@ -20,124 +20,13 @@
* under the License.
*/
-#include "qmf/QmfImportExport.h"
-#include "qpid/sys/IntegerTypes.h"
-
namespace qmf {
+ namespace engine {
+ class ConnectionSettings;
+ }
- class ConnectionSettingsImpl;
- class Value;
-
- /**
- * Settings for AMQP connections to the broker.
- *
- * \ingroup qmfapi
- */
- class ConnectionSettings {
- public:
-
- ConnectionSettings(const ConnectionSettings& copy);
-
- /**
- * Create a set of default connection settings.
- *
- * If no further attributes are set, the settings will cause a connection to be made to
- * the default broker (on localhost or at a host/port supplied by service discovery) and
- * authentication will be the best-available (GSSAPI/Kerberos, Anonymous, Plain with prompts
- * for username and password).
- */
- QMF_EXTERN ConnectionSettings();
-
- /**
- * Create a set of connection settings by URL.
- *
- * @param url Universal resource locator describing the broker address and additional attributes.
- *
- * The URL is of the form:
- * amqp[s]://host[:port][?key=value[&key=value]*]
- *
- * For example:
- * amqp://localhost
- * amqp://broker?transport=rdma&authmech=GSSAPI&authservice=qpidd
- * amqps://broker?authmech=PLAIN&authuser=guest&authpass=guest
- */
- QMF_EXTERN ConnectionSettings(const char* url);
-
- /**
- * Destroy the connection settings object.
- */
- QMF_EXTERN ~ConnectionSettings();
-
- /**
- * Set an attribute to control connection setup.
- *
- * @param key A null-terminated string that is an attribute name.
- *
- * @param value Reference to a value to be stored as the attribute. The type of the value
- * is specific to the key.
- */
- QMF_EXTERN void setAttr(const char* key, const Value& value);
-
- /**
- * Get the value of an attribute.
- *
- * @param key A null-terminated attribute name.
- *
- * @return The value associated with the attribute name.
- */
- QMF_EXTERN Value getAttr(const char* key) const;
-
- /**
- * Get the attribute string (the portion of the URL following the '?') for the settings.
- *
- * @return A pointer to the attribute string. If the content of this string needs to be
- * available beyond the scope of the calling function, it should be copied. The
- * returned pointer may become invalid if the set of attributes is changed.
- */
- QMF_EXTERN const char* getAttrString() const;
-
- /**
- * Shortcuts for setting the transport for the connection.
- *
- * @param port The port value for the connection address.
- */
- QMF_EXTERN void transportTcp(uint16_t port = 5672);
- QMF_EXTERN void transportSsl(uint16_t port = 5671);
- QMF_EXTERN void transportRdma(uint16_t port = 5672);
-
- /**
- * Shortcuts for setting authentication mechanisms.
- *
- * @param username Null-terminated authentication user name.
- *
- * @param password Null-terminated authentication password.
- *
- * @param serviceName Null-terminated GSSAPI service name (Kerberos service principal)
- *
- * @param minSsf Minimum security factor for connections. 0 = encryption not required.
- *
- * @param maxSsf Maximum security factor for connections. 0 = encryption not permitted.
- */
- QMF_EXTERN void authAnonymous(const char* username = 0);
- QMF_EXTERN void authPlain(const char* username = 0, const char* password = 0);
- QMF_EXTERN void authGssapi(const char* serviceName, uint32_t minSsf = 0, uint32_t maxSsf = 256);
-
- /**
- * Shortcut for setting connection retry attributes.
- *
- * @param delayMin Minimum delay (in seconds) between connection attempts.
- *
- * @param delaxMax Maximum delay (in seconds) between connection attempts.
- *
- * @param delayFactor Factor to multiply the delay by between failed connection attempts.
- */
- QMF_EXTERN void setRetry(int delayMin = 1, int delayMax = 128, int delayFactor = 2);
-
- private:
- friend class ResilientConnectionImpl;
- ConnectionSettingsImpl* impl;
- };
-
+ typedef class engine::ConnectionSettings ConnectionSettings;
}
#endif
+
diff --git a/qpid/cpp/include/qmf/ConsoleObject.h b/qpid/cpp/include/qmf/ConsoleObject.h
new file mode 100644
index 0000000000..acbc285e05
--- /dev/null
+++ b/qpid/cpp/include/qmf/ConsoleObject.h
@@ -0,0 +1,94 @@
+#ifndef _QmfConsoleObject_
+#define _QmfConsoleObject_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/QmfImportExport.h"
+
+namespace qmf {
+
+ class ConsoleObjectImpl;
+ class SchemaObjectClass;
+ class ObjectId;
+ class Value;
+
+ /**
+ * ConsoleObject is an extension of Object with console-specific methods added.
+ *
+ * \ingroup qmfapi
+ */
+ class ConsoleObject : public Object {
+ public:
+ /**
+ * Create a new Object of a specific type.
+ *
+ * @param type Pointer to the schema class to use as a type for this object.
+ */
+ QMF_EXTERN ConsoleObject(const SchemaObjectClass* type);
+
+ /**
+ * Destroy the object.
+ */
+ QMF_EXTERN virtual ~ConsoleObject();
+
+ /**
+ *
+ */
+ QMF_EXTERN const SchemaObjectClass* getSchema() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN ObjectId* getObjectId() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN uint64_t getCurrentTime() const;
+ QMF_EXTERN uint64_t getCreateTime() const;
+ QMF_EXTERN uint64_t getDeleteTime() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN bool isDeleted() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN void update();
+
+ /**
+ *
+ */
+ QMF_EXTERN void invokeMethod(const char* name, const Value* arguments, MethodResult& result);
+
+ /**
+ *
+ */
+ QMF_EXTERN uint32_t invokeMethodAsync(const char* name, const Value* arguments = 0);
+
+ private:
+ ConsoleObjectImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/src/qmf/AgentEngine.h b/qpid/cpp/include/qmf/engine/Agent.h
index c88ef33657..71abf82254 100644
--- a/qpid/cpp/src/qmf/AgentEngine.h
+++ b/qpid/cpp/include/qmf/engine/Agent.h
@@ -1,5 +1,5 @@
-#ifndef _QmfAgentEngine_
-#define _QmfAgentEngine_
+#ifndef _QmfEngineAgent_
+#define _QmfEngineAgent_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,15 +20,16 @@
* under the License.
*/
-#include <qmf/Schema.h>
-#include <qmf/ObjectId.h>
-#include <qmf/Object.h>
-#include <qmf/Event.h>
-#include <qmf/Query.h>
-#include <qmf/Value.h>
-#include <qmf/Message.h>
+#include <qmf/engine/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Object.h>
+#include <qmf/engine/Event.h>
+#include <qmf/engine/Query.h>
+#include <qmf/engine/Value.h>
+#include <qmf/engine/Message.h>
namespace qmf {
+namespace engine {
/**
* AgentEvent
@@ -61,18 +62,18 @@ namespace qmf {
Value* arguments; // Method parameters (METHOD_CALL)
char* exchange; // Exchange for bind (BIND, UNBIND)
char* bindingKey; // Key for bind (BIND, UNBIND)
- SchemaObjectClass* objectClass; // (METHOD_CALL)
+ const SchemaObjectClass* objectClass; // (METHOD_CALL)
};
- class AgentEngineImpl;
+ class AgentImpl;
/**
- * AgentEngine - Protocol engine for the QMF agent
+ * Agent - Protocol engine for the QMF agent
*/
- class AgentEngine {
+ class Agent {
public:
- AgentEngine(char* label, bool internalStore=true);
- ~AgentEngine();
+ Agent(char* label, bool internalStore=true);
+ ~Agent();
/**
* Configure the directory path for storing persistent data.
@@ -199,9 +200,10 @@ namespace qmf {
void raiseEvent(Event& event);
private:
- AgentEngineImpl* impl;
+ AgentImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/include/qmf/engine/ConnectionSettings.h b/qpid/cpp/include/qmf/engine/ConnectionSettings.h
new file mode 100644
index 0000000000..36312400b1
--- /dev/null
+++ b/qpid/cpp/include/qmf/engine/ConnectionSettings.h
@@ -0,0 +1,150 @@
+#ifndef _QmfEngineConnectionSettings_
+#define _QmfEngineConnectionSettings_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/QmfEngineImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qmf {
+namespace engine {
+
+ class ConnectionSettingsImpl;
+ class Value;
+
+ /**
+ * Settings for AMQP connections to the broker.
+ *
+ * \ingroup qmfapi
+ */
+ class ConnectionSettings {
+ public:
+
+ /**
+ * Create a set of default connection settings.
+ *
+ * If no further attributes are set, the settings will cause a connection to be made to
+ * the default broker (on localhost or at a host/port supplied by service discovery) and
+ * authentication will be the best-available (GSSAPI/Kerberos, Anonymous, Plain with prompts
+ * for username and password).
+ */
+ QMFE_EXTERN ConnectionSettings();
+
+ /**
+ * Create a set of connection settings by URL.
+ *
+ * @param url Universal resource locator describing the broker address and additional attributes.
+ *
+ * The URL is of the form:
+ * amqp[s]://host[:port][?key=value[&key=value]*]
+ *
+ * For example:
+ * amqp://localhost
+ * amqp://broker?transport=rdma&authmech=GSSAPI&authservice=qpidd
+ * amqps://broker?authmech=PLAIN&authuser=guest&authpass=guest
+ */
+ QMFE_EXTERN ConnectionSettings(const char* url);
+
+ /**
+ * Copy Constructor.
+ */
+ ConnectionSettings(const ConnectionSettings& from);
+
+ /**
+ * Destroy the connection settings object.
+ */
+ QMFE_EXTERN ~ConnectionSettings();
+
+ /**
+ * Set an attribute to control connection setup.
+ *
+ * @param key A null-terminated string that is an attribute name.
+ *
+ * @param value Reference to a value to be stored as the attribute. The type of the value
+ * is specific to the key.
+ *
+ * @return True if success, False if invalid attribute
+ */
+ QMFE_EXTERN bool setAttr(const char* key, const Value& value);
+
+ /**
+ * Get the value of an attribute.
+ *
+ * @param key A null-terminated attribute name.
+ *
+ * @return The value associated with the attribute name.
+ */
+ QMFE_EXTERN Value getAttr(const char* key) const;
+
+ /**
+ * Get the attribute string (the portion of the URL following the '?') for the settings.
+ *
+ * @return A pointer to the attribute string. If the content of this string needs to be
+ * available beyond the scope of the calling function, it should be copied. The
+ * returned pointer may become invalid if the set of attributes is changed.
+ */
+ QMFE_EXTERN const char* getAttrString() const;
+
+ /**
+ * Shortcuts for setting the transport for the connection.
+ *
+ * @param port The port value for the connection address.
+ */
+ QMFE_EXTERN void transportTcp(uint16_t port = 5672);
+ QMFE_EXTERN void transportSsl(uint16_t port = 5671);
+ QMFE_EXTERN void transportRdma(uint16_t port = 5672);
+
+ /**
+ * Shortcuts for setting authentication mechanisms.
+ *
+ * @param username Null-terminated authentication user name.
+ *
+ * @param password Null-terminated authentication password.
+ *
+ * @param serviceName Null-terminated GSSAPI service name (Kerberos service principal)
+ *
+ * @param minSsf Minimum security factor for connections. 0 = encryption not required.
+ *
+ * @param maxSsf Maximum security factor for connections. 0 = encryption not permitted.
+ */
+ QMFE_EXTERN void authAnonymous(const char* username = 0);
+ QMFE_EXTERN void authPlain(const char* username = 0, const char* password = 0);
+ QMFE_EXTERN void authGssapi(const char* serviceName, uint32_t minSsf = 0, uint32_t maxSsf = 256);
+
+ /**
+ * Shortcut for setting connection retry attributes.
+ *
+ * @param delayMin Minimum delay (in seconds) between connection attempts.
+ *
+ * @param delaxMax Maximum delay (in seconds) between connection attempts.
+ *
+ * @param delayFactor Factor to multiply the delay by between failed connection attempts.
+ */
+ QMFE_EXTERN void setRetry(int delayMin = 1, int delayMax = 128, int delayFactor = 2);
+
+ private:
+ friend class ResilientConnectionImpl;
+ ConnectionSettingsImpl* impl;
+ };
+
+}
+}
+
+#endif
diff --git a/qpid/cpp/src/qmf/ConsoleEngine.h b/qpid/cpp/include/qmf/engine/Console.h
index 457e83ad58..ce72360da7 100644
--- a/qpid/cpp/src/qmf/ConsoleEngine.h
+++ b/qpid/cpp/include/qmf/engine/Console.h
@@ -1,5 +1,5 @@
-#ifndef _QmfConsoleEngine_
-#define _QmfConsoleEngine_
+#ifndef _QmfEngineConsole_
+#define _QmfEngineConsole_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,39 +20,42 @@
* under the License.
*/
-#include <qmf/ResilientConnection.h>
-#include <qmf/Schema.h>
-#include <qmf/ObjectId.h>
-#include <qmf/Object.h>
-#include <qmf/Event.h>
-#include <qmf/Query.h>
-#include <qmf/Value.h>
-#include <qmf/Message.h>
+#include <qmf/engine/ResilientConnection.h>
+#include <qmf/engine/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Object.h>
+#include <qmf/engine/Event.h>
+#include <qmf/engine/Query.h>
+#include <qmf/engine/Value.h>
+#include <qmf/engine/Message.h>
namespace qmf {
+namespace engine {
- class ConsoleEngine;
- class ConsoleEngineImpl;
+ class Console;
+ struct ConsoleImpl;
class BrokerProxyImpl;
class AgentProxy;
- class AgentProxyImpl;
- class MethodResponseImpl;
- class QueryResponseImpl;
- class QueryContext;
+ struct AgentProxyImpl;
+ struct MethodResponseImpl;
+ struct QueryResponseImpl;
+ struct QueryContext;
/**
*
*/
class MethodResponse {
public:
- MethodResponse(MethodResponseImpl* impl);
+ MethodResponse(const MethodResponse& from);
~MethodResponse();
uint32_t getStatus() const;
const Value* getException() const;
const Value* getArgs() const;
private:
- friend class ConsoleEngineImpl;
+ friend struct MethodResponseImpl;
+ friend struct ConsoleImpl;
+ MethodResponse(MethodResponseImpl* impl);
MethodResponseImpl* impl;
};
@@ -61,7 +64,6 @@ namespace qmf {
*/
class QueryResponse {
public:
- QueryResponse(QueryResponseImpl* impl);
~QueryResponse();
uint32_t getStatus() const;
const Value* getException() const;
@@ -69,7 +71,9 @@ namespace qmf {
const Object* getObject(uint32_t idx) const;
private:
- friend class QueryContext;
+ friend struct QueryResponseImpl;
+ friend struct QueryContext;
+ QueryResponse(QueryResponseImpl* impl);
QueryResponseImpl *impl;
};
@@ -84,21 +88,20 @@ namespace qmf {
NEW_CLASS = 4,
OBJECT_UPDATE = 5,
EVENT_RECEIVED = 7,
- AGENT_HEARTBEAT = 8,
- METHOD_RESPONSE = 9
+ AGENT_HEARTBEAT = 8
};
EventKind kind;
AgentProxy* agent; // (AGENT_[ADDED|DELETED|HEARTBEAT])
char* name; // (NEW_PACKAGE)
- SchemaClassKey* classKey; // (NEW_CLASS)
+ const SchemaClassKey* classKey; // (NEW_CLASS)
Object* object; // (OBJECT_UPDATE)
void* context; // (OBJECT_UPDATE)
Event* event; // (EVENT_RECEIVED)
uint64_t timestamp; // (AGENT_HEARTBEAT)
- uint32_t methodHandle; // (METHOD_RESPONSE)
- MethodResponse* methodResponse; // (METHOD_RESPONSE)
QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ bool hasProps;
+ bool hasStats;
};
/**
@@ -113,15 +116,17 @@ namespace qmf {
UNBIND = 14,
SETUP_COMPLETE = 15,
STABLE = 16,
- QUERY_COMPLETE = 17
+ QUERY_COMPLETE = 17,
+ METHOD_RESPONSE = 18
};
EventKind kind;
- char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND)
- char* exchange; // ([UN]BIND)
- char* bindingKey; // ([UN]BIND)
- void* context; // (QUERY_COMPLETE)
- QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND)
+ char* exchange; // ([UN]BIND)
+ char* bindingKey; // ([UN]BIND)
+ void* context; // (QUERY_COMPLETE, METHOD_RESPONSE)
+ QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ MethodResponse* methodResponse; // (METHOD_RESPONSE)
};
/**
@@ -129,12 +134,17 @@ namespace qmf {
*/
class AgentProxy {
public:
- AgentProxy(AgentProxyImpl* impl);
~AgentProxy();
const char* getLabel() const;
+ uint32_t getBrokerBank() const;
+ uint32_t getAgentBank() const;
private:
+ friend struct StaticContext;
+ friend struct QueryContext;
+ friend struct AgentProxyImpl;
friend class BrokerProxyImpl;
+ AgentProxy(AgentProxyImpl* impl);
AgentProxyImpl* impl;
};
@@ -143,7 +153,7 @@ namespace qmf {
*/
class BrokerProxy {
public:
- BrokerProxy(ConsoleEngine& console);
+ BrokerProxy(Console& console);
~BrokerProxy();
void sessionOpened(SessionHandle& sh);
@@ -162,7 +172,8 @@ namespace qmf {
void sendQuery(const Query& query, void* context, const AgentProxy* agent = 0);
private:
- friend class ConsoleEngineImpl;
+ friend struct ConsoleImpl;
+ friend struct StaticContext;
BrokerProxyImpl* impl;
};
@@ -180,10 +191,10 @@ namespace qmf {
userBindings(false) {}
};
- class ConsoleEngine {
+ class Console {
public:
- ConsoleEngine(const ConsoleSettings& settings = ConsoleSettings());
- ~ConsoleEngine();
+ Console(const ConsoleSettings& settings = ConsoleSettings());
+ ~Console();
bool getEvent(ConsoleEvent& event) const;
void popEvent();
@@ -213,10 +224,12 @@ namespace qmf {
private:
friend class BrokerProxyImpl;
- friend class AgentProxyImpl;
- ConsoleEngineImpl* impl;
+ friend struct AgentProxyImpl;
+ friend struct StaticContext;
+ ConsoleImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Event.h b/qpid/cpp/include/qmf/engine/Event.h
index f20c6d2fb1..50ab5c1200 100644
--- a/qpid/cpp/src/qmf/Event.h
+++ b/qpid/cpp/include/qmf/engine/Event.h
@@ -1,5 +1,5 @@
-#ifndef _QmfEvent_
-#define _QmfEvent_
+#ifndef _QmfEngineEvent_
+#define _QmfEngineEvent_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -21,10 +21,12 @@
*/
namespace qmf {
+namespace engine {
class Event {
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Message.h b/qpid/cpp/include/qmf/engine/Message.h
index 52b8ba72d3..1e95cc6afe 100644
--- a/qpid/cpp/src/qmf/Message.h
+++ b/qpid/cpp/include/qmf/engine/Message.h
@@ -1,5 +1,5 @@
-#ifndef _QmfMessage_
-#define _QmfMessage_
+#ifndef _QmfEngineMessage_
+#define _QmfEngineMessage_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -23,6 +23,7 @@
#include "qpid/sys/IntegerTypes.h"
namespace qmf {
+namespace engine {
struct Message {
char* body;
@@ -35,5 +36,6 @@ namespace qmf {
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Object.h b/qpid/cpp/include/qmf/engine/Object.h
index 9cb3224d9b..ad67cfdb95 100644
--- a/qpid/cpp/src/qmf/Object.h
+++ b/qpid/cpp/include/qmf/engine/Object.h
@@ -1,5 +1,5 @@
-#ifndef _QmfObject_
-#define _QmfObject_
+#ifndef _QmfEngineObject_
+#define _QmfEngineObject_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,17 +20,17 @@
* under the License.
*/
-#include <qmf/Schema.h>
-#include <qmf/ObjectId.h>
-#include <qmf/Value.h>
+#include <qmf/engine/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Value.h>
namespace qmf {
+namespace engine {
struct ObjectImpl;
class Object {
public:
Object(const SchemaObjectClass* type);
- Object(ObjectImpl* impl);
Object(const Object& from);
virtual ~Object();
@@ -38,11 +38,19 @@ namespace qmf {
const ObjectId* getObjectId() const;
void setObjectId(ObjectId* oid);
const SchemaObjectClass* getClass() const;
- Value* getValue(char* key) const;
-
+ Value* getValue(const char* key) const;
+ void invokeMethod(const char* methodName, const Value* inArgs, void* context) const;
+ bool isDeleted() const;
+ void merge(const Object& from);
+
+ private:
+ friend struct ObjectImpl;
+ friend class AgentImpl;
+ Object(ObjectImpl* impl);
ObjectImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ObjectId.h b/qpid/cpp/include/qmf/engine/ObjectId.h
index e894e0b39c..2055972c00 100644
--- a/qpid/cpp/src/qmf/ObjectId.h
+++ b/qpid/cpp/include/qmf/engine/ObjectId.h
@@ -1,5 +1,5 @@
-#ifndef _QmfObjectId_
-#define _QmfObjectId_
+#ifndef _QmfEngineObjectId_
+#define _QmfEngineObjectId_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -23,6 +23,7 @@
#include <qpid/sys/IntegerTypes.h>
namespace qmf {
+namespace engine {
// TODO: Add to/from string and << operator
@@ -31,13 +32,17 @@ namespace qmf {
public:
ObjectId();
ObjectId(const ObjectId& from);
- ObjectId(ObjectIdImpl* impl);
~ObjectId();
uint64_t getObjectNum() const;
uint32_t getObjectNumHi() const;
uint32_t getObjectNumLo() const;
bool isDurable() const;
+ const char* str() const;
+ uint8_t getFlags() const;
+ uint16_t getSequence() const;
+ uint32_t getBrokerBank() const;
+ uint32_t getAgentBank() const;
bool operator==(const ObjectId& other) const;
bool operator<(const ObjectId& other) const;
@@ -45,9 +50,18 @@ namespace qmf {
bool operator<=(const ObjectId& other) const;
bool operator>=(const ObjectId& other) const;
+ private:
+ friend struct ObjectIdImpl;
+ friend struct ObjectImpl;
+ friend class BrokerProxyImpl;
+ friend struct QueryImpl;
+ friend struct ValueImpl;
+ friend class AgentImpl;
+ ObjectId(ObjectIdImpl* impl);
ObjectIdImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h b/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h
new file mode 100644
index 0000000000..70164c749f
--- /dev/null
+++ b/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QMF_ENGINE_IMPORT_EXPORT_H
+#define QMF_ENGINE_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+# if defined(QMF_EXPORT) || defined (qmfcommon_EXPORTS)
+# define QMFE_EXTERN __declspec(dllexport)
+# else
+# define QMFE_EXTERN __declspec(dllimport)
+# endif
+#else
+# define QMFE_EXTERN
+#endif
+
+#endif
diff --git a/qpid/cpp/src/qmf/Query.h b/qpid/cpp/include/qmf/engine/Query.h
index 875749862e..1b11ea83f2 100644
--- a/qpid/cpp/src/qmf/Query.h
+++ b/qpid/cpp/include/qmf/engine/Query.h
@@ -1,5 +1,5 @@
-#ifndef _QmfQuery_
-#define _QmfQuery_
+#ifndef _QmfEngineQuery_
+#define _QmfEngineQuery_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,16 +20,17 @@
* under the License.
*/
-#include <qmf/ObjectId.h>
-#include <qmf/Value.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Value.h>
namespace qmf {
+namespace engine {
- struct Object;
+ class Object;
struct QueryElementImpl;
struct QueryImpl;
struct QueryExpressionImpl;
- struct SchemaClassKey;
+ class SchemaClassKey;
enum ValueOper {
O_EQ = 1,
@@ -77,7 +78,7 @@ namespace qmf {
Query(const char* className, const char* packageName);
Query(const SchemaClassKey* key);
Query(const ObjectId* oid);
- Query(QueryImpl* impl);
+ Query(const Query& from);
~Query();
void setSelect(const QueryOperand* criterion);
@@ -96,9 +97,14 @@ namespace qmf {
const char* getOrderBy() const;
bool getDecreasing() const;
+ private:
+ friend struct QueryImpl;
+ friend class BrokerProxyImpl;
+ Query(QueryImpl* impl);
QueryImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ResilientConnection.h b/qpid/cpp/include/qmf/engine/ResilientConnection.h
index 03f1b9c0d5..359c8ea6ff 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.h
+++ b/qpid/cpp/include/qmf/engine/ResilientConnection.h
@@ -1,5 +1,5 @@
-#ifndef _QmfResilientConnection_
-#define _QmfResilientConnection_
+#ifndef _QmfEngineResilientConnection_
+#define _QmfEngineResilientConnection_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,11 +20,12 @@
* under the License.
*/
-#include <qmf/Message.h>
-#include <qmf/ConnectionSettings.h>
+#include <qmf/engine/Message.h>
+#include <qmf/engine/ConnectionSettings.h>
#include <string>
namespace qmf {
+namespace engine {
class ResilientConnectionImpl;
@@ -158,6 +159,7 @@ namespace qmf {
ResilientConnectionImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Schema.h b/qpid/cpp/include/qmf/engine/Schema.h
index 1123acc3b8..16f11a83f9 100644
--- a/qpid/cpp/src/qmf/Schema.h
+++ b/qpid/cpp/include/qmf/engine/Schema.h
@@ -1,5 +1,5 @@
-#ifndef _QmfSchema_
-#define _QmfSchema_
+#ifndef _QmfEngineSchema_
+#define _QmfEngineSchema_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,10 +20,11 @@
* under the License.
*/
-#include <qmf/Typecode.h>
+#include <qmf/engine/Typecode.h>
#include <qpid/sys/IntegerTypes.h>
namespace qmf {
+namespace engine {
enum Access { ACCESS_READ_CREATE = 1, ACCESS_READ_WRITE = 2, ACCESS_READ_ONLY = 3 };
enum Direction { DIR_IN = 1, DIR_OUT = 2, DIR_IN_OUT = 3 };
@@ -42,7 +43,7 @@ namespace qmf {
class SchemaArgument {
public:
SchemaArgument(const char* name, Typecode typecode);
- SchemaArgument(SchemaArgumentImpl* impl);
+ SchemaArgument(const SchemaArgument& from);
~SchemaArgument();
void setDirection(Direction dir);
void setUnit(const char* val);
@@ -53,6 +54,11 @@ namespace qmf {
const char* getUnit() const;
const char* getDesc() const;
+ private:
+ friend struct SchemaArgumentImpl;
+ friend struct SchemaMethodImpl;
+ friend struct SchemaEventClassImpl;
+ SchemaArgument(SchemaArgumentImpl* impl);
SchemaArgumentImpl* impl;
};
@@ -61,15 +67,20 @@ namespace qmf {
class SchemaMethod {
public:
SchemaMethod(const char* name);
- SchemaMethod(SchemaMethodImpl* impl);
+ SchemaMethod(const SchemaMethod& from);
~SchemaMethod();
- void addArgument(const SchemaArgument& argument);
+ void addArgument(const SchemaArgument* argument);
void setDesc(const char* desc);
const char* getName() const;
const char* getDesc() const;
int getArgumentCount() const;
const SchemaArgument* getArgument(int idx) const;
+ private:
+ friend struct SchemaMethodImpl;
+ friend struct SchemaObjectClassImpl;
+ friend class AgentImpl;
+ SchemaMethod(SchemaMethodImpl* impl);
SchemaMethodImpl* impl;
};
@@ -78,7 +89,7 @@ namespace qmf {
class SchemaProperty {
public:
SchemaProperty(const char* name, Typecode typecode);
- SchemaProperty(SchemaPropertyImpl* impl);
+ SchemaProperty(const SchemaProperty& from);
~SchemaProperty();
void setAccess(Access access);
void setIndex(bool val);
@@ -93,6 +104,10 @@ namespace qmf {
const char* getUnit() const;
const char* getDesc() const;
+ private:
+ friend struct SchemaPropertyImpl;
+ friend struct SchemaObjectClassImpl;
+ SchemaProperty(SchemaPropertyImpl* impl);
SchemaPropertyImpl* impl;
};
@@ -101,7 +116,7 @@ namespace qmf {
class SchemaStatistic {
public:
SchemaStatistic(const char* name, Typecode typecode);
- SchemaStatistic(SchemaStatisticImpl* impl);
+ SchemaStatistic(const SchemaStatistic& from);
~SchemaStatistic();
void setUnit(const char* val);
void setDesc(const char* desc);
@@ -110,6 +125,10 @@ namespace qmf {
const char* getUnit() const;
const char* getDesc() const;
+ private:
+ friend struct SchemaStatisticImpl;
+ friend struct SchemaObjectClassImpl;
+ SchemaStatistic(SchemaStatisticImpl* impl);
SchemaStatisticImpl* impl;
};
@@ -117,13 +136,22 @@ namespace qmf {
*/
class SchemaClassKey {
public:
- SchemaClassKey(SchemaClassKeyImpl* impl);
+ SchemaClassKey(const SchemaClassKey& from);
~SchemaClassKey();
const char* getPackageName() const;
const char* getClassName() const;
const uint8_t* getHash() const;
+ const char* asString() const;
+
+ bool operator==(const SchemaClassKey& other) const;
+ bool operator<(const SchemaClassKey& other) const;
+ private:
+ friend struct SchemaClassKeyImpl;
+ friend class BrokerProxyImpl;
+ friend struct ConsoleImpl;
+ SchemaClassKey(SchemaClassKeyImpl* impl);
SchemaClassKeyImpl* impl;
};
@@ -132,11 +160,11 @@ namespace qmf {
class SchemaObjectClass {
public:
SchemaObjectClass(const char* package, const char* name);
- SchemaObjectClass(SchemaObjectClassImpl* impl);
+ SchemaObjectClass(const SchemaObjectClass& from);
~SchemaObjectClass();
- void addProperty(const SchemaProperty& property);
- void addStatistic(const SchemaStatistic& statistic);
- void addMethod(const SchemaMethod& method);
+ void addProperty(const SchemaProperty* property);
+ void addStatistic(const SchemaStatistic* statistic);
+ void addMethod(const SchemaMethod* method);
const SchemaClassKey* getClassKey() const;
int getPropertyCount() const;
@@ -146,6 +174,11 @@ namespace qmf {
const SchemaStatistic* getStatistic(int idx) const;
const SchemaMethod* getMethod(int idx) const;
+ private:
+ friend struct SchemaObjectClassImpl;
+ friend class BrokerProxyImpl;
+ friend class AgentImpl;
+ SchemaObjectClass(SchemaObjectClassImpl* impl);
SchemaObjectClassImpl* impl;
};
@@ -154,18 +187,24 @@ namespace qmf {
class SchemaEventClass {
public:
SchemaEventClass(const char* package, const char* name);
- SchemaEventClass(SchemaEventClassImpl* impl);
+ SchemaEventClass(const SchemaEventClass& from);
~SchemaEventClass();
- void addArgument(const SchemaArgument& argument);
+ void addArgument(const SchemaArgument* argument);
void setDesc(const char* desc);
const SchemaClassKey* getClassKey() const;
int getArgumentCount() const;
const SchemaArgument* getArgument(int idx) const;
+ private:
+ friend struct SchemaEventClassImpl;
+ friend class BrokerProxyImpl;
+ friend class AgentImpl;
+ SchemaEventClass(SchemaEventClassImpl* impl);
SchemaEventClassImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Typecode.h b/qpid/cpp/include/qmf/engine/Typecode.h
index 94614d2977..613f96a483 100644
--- a/qpid/cpp/src/qmf/Typecode.h
+++ b/qpid/cpp/include/qmf/engine/Typecode.h
@@ -1,5 +1,5 @@
-#ifndef _QmfTypecode_
-#define _QmfTypecode_
+#ifndef _QmfEngineTypecode_
+#define _QmfEngineTypecode_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -21,6 +21,7 @@
*/
namespace qmf {
+namespace engine {
enum Typecode {
TYPE_UINT8 = 1,
@@ -46,6 +47,7 @@ namespace qmf {
TYPE_ARRAY = 22
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Value.h b/qpid/cpp/include/qmf/engine/Value.h
index bb946d31d3..8eae382caf 100644
--- a/qpid/cpp/src/qmf/Value.h
+++ b/qpid/cpp/include/qmf/engine/Value.h
@@ -1,5 +1,5 @@
-#ifndef _QmfValue_
-#define _QmfValue_
+#ifndef _QmfEngineValue_
+#define _QmfEngineValue_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,10 +20,11 @@
* under the License.
*/
-#include <qmf/ObjectId.h>
-#include <qmf/Typecode.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Typecode.h>
namespace qmf {
+namespace engine {
class Object;
struct ValueImpl;
@@ -31,8 +32,8 @@ namespace qmf {
class Value {
public:
// Value();
+ Value(const Value& from);
Value(Typecode t, Typecode arrayType = TYPE_UINT8);
- Value(ValueImpl* impl);
~Value();
Typecode getType() const;
@@ -80,7 +81,7 @@ namespace qmf {
void setUuid(const uint8_t* val);
bool isObject() const;
- Object* asObject() const;
+ const Object* asObject() const;
void setObject(Object* val);
bool isMap() const;
@@ -105,9 +106,16 @@ namespace qmf {
void appendToArray(Value* val);
void deleteArrayItem(uint32_t idx);
+ private:
+ friend struct ValueImpl;
+ friend class BrokerProxyImpl;
+ friend struct ObjectImpl;
+ friend class AgentImpl;
+ Value(ValueImpl* impl);
ValueImpl* impl;
};
}
+}
#endif
diff --git a/qpid/cpp/include/qpid/client/QueueOptions.h b/qpid/cpp/include/qpid/client/QueueOptions.h
index 9418cb092d..f8a4963f06 100644
--- a/qpid/cpp/include/qpid/client/QueueOptions.h
+++ b/qpid/cpp/include/qpid/client/QueueOptions.h
@@ -90,7 +90,22 @@ class QueueOptions: public framing::FieldTable
* Turns on event generation for this queue (either enqueue only
* or for enqueue and dequeue events); the events can then be
* processed by a regsitered broker plugin.
+ *
+ * DEPRECATED
+ *
+ * This is confusing to anyone who sees only the function call
+ * and not the variable name / doxygen. Consider the following call:
+ *
+ * options.enableQueueEvents(false);
+ *
+ * It looks like it disables queue events, but what it really does is
+ * enable both enqueue and dequeue events.
+ *
+ * Use setInt() instead:
+ *
+ * options.setInt("qpid.queue_event_generation", 2);
*/
+
QPID_CLIENT_EXTERN void enableQueueEvents(bool enqueueOnly);
static QPID_CLIENT_EXTERN const std::string strMaxCountKey;
diff --git a/qpid/cpp/include/qpid/messaging/ListContent.h b/qpid/cpp/include/qpid/messaging/ListContent.h
new file mode 100644
index 0000000000..1c4e13716d
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/ListContent.h
@@ -0,0 +1,90 @@
+#ifndef QPID_MESSAGING_LISTCONTENT_H
+#define QPID_MESSAGING_LISTCONTENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListContentImpl;
+class Message;
+
+/**
+ * Allows message content to be manipulated as a list.
+ */
+class ListContent
+{
+ public:
+ typedef Variant::List::iterator iterator;
+ typedef Variant::List::reverse_iterator reverse_iterator;
+ typedef Variant::List::const_iterator const_iterator;
+ typedef Variant::List::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN ListContent(Message&);
+ QPID_CLIENT_EXTERN ~ListContent();
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN iterator begin();
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN iterator end();
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN reverse_iterator rbegin();
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+ QPID_CLIENT_EXTERN reverse_iterator rend();
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const Variant& front() const;
+ QPID_CLIENT_EXTERN Variant& front();
+ QPID_CLIENT_EXTERN const Variant& back() const;
+ QPID_CLIENT_EXTERN Variant& back();
+
+ QPID_CLIENT_EXTERN void push_front(const Variant&);
+ QPID_CLIENT_EXTERN void push_back(const Variant&);
+
+ QPID_CLIENT_EXTERN void pop_front();
+ QPID_CLIENT_EXTERN void pop_back();
+
+ QPID_CLIENT_EXTERN iterator insert(iterator position, const Variant&);
+ QPID_CLIENT_EXTERN void insert(iterator position, size_t n, const Variant&);
+ QPID_CLIENT_EXTERN iterator erase(iterator position);
+ QPID_CLIENT_EXTERN iterator erase(iterator first, iterator last);
+ QPID_CLIENT_EXTERN void clear();
+
+ QPID_CLIENT_EXTERN void encode();
+
+ QPID_CLIENT_EXTERN const Variant::List& asList() const;
+ QPID_CLIENT_EXTERN Variant::List& asList();
+ private:
+ ListContentImpl* impl;
+
+ QPID_CLIENT_EXTERN ListContent& operator=(const ListContent&);
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListContent& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_LISTCONTENT_H*/
diff --git a/qpid/cpp/include/qpid/messaging/ListView.h b/qpid/cpp/include/qpid/messaging/ListView.h
new file mode 100644
index 0000000000..4970a20072
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/ListView.h
@@ -0,0 +1,67 @@
+#ifndef QPID_MESSAGING_LISTVIEW_H
+#define QPID_MESSAGING_LISTVIEW_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListViewImpl;
+class Message;
+
+/**
+ * Provides a view of message content as a list
+ */
+class ListView
+{
+ public:
+ typedef Variant::List::const_iterator const_iterator;
+ typedef Variant::List::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN ListView(const Message&);
+ QPID_CLIENT_EXTERN ~ListView();
+ QPID_CLIENT_EXTERN ListView& operator=(const ListView&);
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const Variant& front() const;
+ QPID_CLIENT_EXTERN const Variant& back() const;
+
+ QPID_CLIENT_EXTERN const Variant::List& asList() const;
+ private:
+ ListViewImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListView& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_LISTVIEW_H*/
diff --git a/qpid/cpp/include/qpid/messaging/MapContent.h b/qpid/cpp/include/qpid/messaging/MapContent.h
new file mode 100644
index 0000000000..b05cb31295
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/MapContent.h
@@ -0,0 +1,90 @@
+#ifndef QPID_MESSAGING_MAPCONTENT_H
+#define QPID_MESSAGING_MAPCONTENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+#include <map>
+#include <string>
+
+namespace qpid {
+namespace messaging {
+
+class MapContentImpl;
+class Message;
+
+/**
+ * Allows message content to be manipulated as a map
+ */
+class MapContent
+{
+ public:
+ typedef std::string key_type;
+ typedef std::pair<std::string, Variant> value_type;
+ typedef std::map<key_type, Variant>::const_iterator const_iterator;
+ typedef std::map<key_type, Variant>::iterator iterator;
+ typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator;
+ typedef std::map<key_type, Variant>::reverse_iterator reverse_iterator;
+
+ QPID_CLIENT_EXTERN MapContent(Message&);
+ QPID_CLIENT_EXTERN ~MapContent();
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+ QPID_CLIENT_EXTERN iterator begin();
+ QPID_CLIENT_EXTERN iterator end();
+ QPID_CLIENT_EXTERN reverse_iterator rbegin();
+ QPID_CLIENT_EXTERN reverse_iterator rend();
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const_iterator find(const key_type&) const;
+ QPID_CLIENT_EXTERN iterator find(const key_type&);
+ QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const;
+ QPID_CLIENT_EXTERN Variant& operator[](const key_type&);
+
+ QPID_CLIENT_EXTERN std::pair<iterator,bool> insert(const value_type&);
+ QPID_CLIENT_EXTERN iterator insert(iterator position, const value_type&);
+ QPID_CLIENT_EXTERN void erase(iterator position);
+ QPID_CLIENT_EXTERN void erase(iterator first, iterator last);
+ QPID_CLIENT_EXTERN size_t erase(const key_type&);
+ QPID_CLIENT_EXTERN void clear();
+
+ QPID_CLIENT_EXTERN void encode();
+
+ QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const;
+ QPID_CLIENT_EXTERN std::map<key_type, Variant>& asMap();
+ private:
+ MapContentImpl* impl;
+
+ QPID_CLIENT_EXTERN MapContent& operator=(const MapContent&);
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapContent& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MAPCONTENT_H*/
diff --git a/qpid/cpp/include/qpid/messaging/MapView.h b/qpid/cpp/include/qpid/messaging/MapView.h
new file mode 100644
index 0000000000..910dfca5c2
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/MapView.h
@@ -0,0 +1,70 @@
+#ifndef QPID_MESSAGING_MAPVIEW_H
+#define QPID_MESSAGING_MAPVIEW_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+#include <map>
+#include <string>
+
+namespace qpid {
+namespace messaging {
+
+class MapViewImpl;
+class Message;
+
+/**
+ * Provides a view of message content as a list
+ */
+class MapView
+{
+ public:
+ typedef std::string key_type;
+ typedef std::pair<key_type, Variant> value_type;
+ typedef std::map<key_type, Variant>::const_iterator const_iterator;
+ typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN MapView(const Message&);
+ QPID_CLIENT_EXTERN ~MapView();
+ QPID_CLIENT_EXTERN MapView& operator=(const MapView&);
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const_iterator find(const key_type&) const;
+ QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const;
+
+ QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const;
+ private:
+ MapViewImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapView& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MAPVIEW_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Message.h b/qpid/cpp/include/qpid/messaging/Message.h
index e68d8a1141..4477d5a2e9 100644
--- a/qpid/cpp/include/qpid/messaging/Message.h
+++ b/qpid/cpp/include/qpid/messaging/Message.h
@@ -24,7 +24,6 @@
#include <string>
#include "qpid/messaging/Variant.h"
-#include "qpid/messaging/MessageContent.h"
#include "qpid/client/ClientImportExport.h"
namespace qpid {
@@ -62,22 +61,11 @@ class Message
QPID_CLIENT_EXTERN const VariantMap& getHeaders() const;
QPID_CLIENT_EXTERN VariantMap& getHeaders();
- QPID_CLIENT_EXTERN const std::string& getBytes() const;
- QPID_CLIENT_EXTERN std::string& getBytes();
- QPID_CLIENT_EXTERN void setBytes(const std::string&);
- QPID_CLIENT_EXTERN void setBytes(const char* chars, size_t count);
- QPID_CLIENT_EXTERN const char* getRawContent() const;
- QPID_CLIENT_EXTERN size_t getContentSize() const;
-
-
- QPID_CLIENT_EXTERN MessageContent& getContent();
- QPID_CLIENT_EXTERN const MessageContent& getContent() const;
- QPID_CLIENT_EXTERN void setContent(const std::string& s);
- QPID_CLIENT_EXTERN void setContent(const Variant::Map&);
- QPID_CLIENT_EXTERN void setContent(const Variant::List&);
-
- QPID_CLIENT_EXTERN void encode(Codec&);
- QPID_CLIENT_EXTERN void decode(Codec&);
+ QPID_CLIENT_EXTERN const std::string& getContent() const;
+ QPID_CLIENT_EXTERN std::string& getContent();
+ QPID_CLIENT_EXTERN void setContent(const std::string&);
+ QPID_CLIENT_EXTERN void setContent(const char* chars, size_t count);
+ QPID_CLIENT_EXTERN void getContent(std::pair<const char*, size_t>& content) const;
private:
MessageImpl* impl;
diff --git a/qpid/cpp/include/qpid/messaging/MessageContent.h b/qpid/cpp/include/qpid/messaging/MessageContent.h
deleted file mode 100644
index 7c3a636c07..0000000000
--- a/qpid/cpp/include/qpid/messaging/MessageContent.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef QPID_MESSAGING_MESSAGECONTENT_H
-#define QPID_MESSAGING_MESSAGECONTENT_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/messaging/Variant.h"
-#include <string>
-#include "qpid/client/ClientImportExport.h"
-
-namespace qpid {
-namespace messaging {
-
-/**
- *
- */
-class MessageContent
-{
- public:
- QPID_CLIENT_EXTERN virtual ~MessageContent() {}
-
- virtual const std::string& asString() const = 0;
- virtual std::string& asString() = 0;
-
- virtual const char* asChars() const = 0;
- virtual size_t size() const = 0;
-
- virtual const Variant::Map& asMap() const = 0;
- virtual Variant::Map& asMap() = 0;
- virtual bool isMap() const = 0;
-
- virtual const Variant::List& asList() const = 0;
- virtual Variant::List& asList() = 0;
- virtual bool isList() const = 0;
-
- virtual void clear() = 0;
-
- virtual Variant& operator[](const std::string&) = 0;
-
-
- virtual std::ostream& print(std::ostream& out) const = 0;
-
-
- //operator<< for variety of types... (is this a good idea?)
- virtual MessageContent& operator<<(const std::string&) = 0;
- virtual MessageContent& operator<<(const char*) = 0;
- virtual MessageContent& operator<<(bool) = 0;
- virtual MessageContent& operator<<(int8_t) = 0;
- virtual MessageContent& operator<<(int16_t) = 0;
- virtual MessageContent& operator<<(int32_t) = 0;
- virtual MessageContent& operator<<(int64_t) = 0;
- virtual MessageContent& operator<<(uint8_t) = 0;
- virtual MessageContent& operator<<(uint16_t) = 0;
- virtual MessageContent& operator<<(uint32_t) = 0;
- virtual MessageContent& operator<<(uint64_t) = 0;
- virtual MessageContent& operator<<(double) = 0;
- virtual MessageContent& operator<<(float) = 0;
-
- //assignment from string, map and list
- virtual MessageContent& operator=(const std::string&) = 0;
- virtual MessageContent& operator=(const char*) = 0;
- virtual MessageContent& operator=(const Variant::Map&) = 0;
- virtual MessageContent& operator=(const Variant::List&) = 0;
-
- private:
-};
-
-QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MessageContent& content);
-
-}} // namespace qpid::messaging
-
-#endif /*!QPID_MESSAGING_MESSAGECONTENT_H*/
diff --git a/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h b/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h
index 6ffd3d8383..79cb950275 100644
--- a/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h
+++ b/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h
@@ -27,6 +27,7 @@
struct timespec;
struct timeval;
+struct addrinfo;
namespace qpid {
namespace sys {
@@ -36,6 +37,10 @@ struct timespec& toTimespec(struct timespec& ts, const Duration& t);
struct timeval& toTimeval(struct timeval& tv, const Duration& t);
Duration toTime(const struct timespec& ts);
+// Private SocketAddress details
+class SocketAddress;
+const struct addrinfo& getAddrInfo(const SocketAddress&);
+
// Private fd related implementation details
class IOHandlePrivate {
public:
diff --git a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h
index 47b1d16a76..7b2c57ad8e 100755
--- a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h
+++ b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h
@@ -21,6 +21,8 @@
*
*/
+#include <BaseTsd.h> /* Windows system types */
+
typedef unsigned char uint8_t;
typedef char int8_t;
typedef unsigned short uint16_t;
@@ -32,7 +34,7 @@ typedef __int64 int64_t;
// Visual Studio doesn't define other common types, so set them up here too.
typedef int pid_t;
-typedef int ssize_t;
+typedef SSIZE_T ssize_t;
typedef unsigned int uint;
#endif /*!QPID_SYS_WINDOWS_INTEGERTYPES_H*/
diff --git a/qpid/cpp/managementgen/CMakeLists.txt b/qpid/cpp/managementgen/CMakeLists.txt
index 8d053e3e08..2511b745a3 100644
--- a/qpid/cpp/managementgen/CMakeLists.txt
+++ b/qpid/cpp/managementgen/CMakeLists.txt
@@ -20,18 +20,7 @@ project(qpidc-qmfgen)
cmake_minimum_required(VERSION 2.4.0 FATAL_ERROR)
install(PROGRAMS qmf-gen DESTINATION managementgen
- COMPONENT all-source)
-install(FILES qmfgen/__init__.py
- qmfgen/generate.py
- qmfgen/schema.py
- qmfgen/templates/Args.h
- qmfgen/templates/Class.cpp
- qmfgen/templates/Class.h
- qmfgen/templates/Event.cpp
- qmfgen/templates/Event.h
- qmfgen/templates/Makefile.mk
- qmfgen/templates/Package.cpp
- qmfgen/templates/Package.h
- qmfgen/management-types.xml
- DESTINATION managementgen
- COMPONENT all-source)
+ COMPONENT ${QPID_COMPONENT_QMF})
+install(DIRECTORY qmfgen DESTINATION managementgen
+ COMPONENT ${QPID_COMPONENT_QMF}
+ PATTERN ".svn" EXCLUDE PATTERN "*.pyc" EXCLUDE)
diff --git a/qpid/cpp/packaging/NSIS/qpid-icon.ico b/qpid/cpp/packaging/NSIS/qpid-icon.ico
new file mode 100644
index 0000000000..112f5d8f1f
--- /dev/null
+++ b/qpid/cpp/packaging/NSIS/qpid-icon.ico
Binary files differ
diff --git a/qpid/cpp/packaging/NSIS/qpid-icon.png b/qpid/cpp/packaging/NSIS/qpid-icon.png
new file mode 100644
index 0000000000..d9bcc5657f
--- /dev/null
+++ b/qpid/cpp/packaging/NSIS/qpid-icon.png
Binary files differ
diff --git a/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp b/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp
new file mode 100644
index 0000000000..1dac04c685
--- /dev/null
+++ b/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp
Binary files differ
diff --git a/qpid/cpp/packaging/NSIS/qpid-install-banner.png b/qpid/cpp/packaging/NSIS/qpid-install-banner.png
new file mode 100644
index 0000000000..be70d02ee6
--- /dev/null
+++ b/qpid/cpp/packaging/NSIS/qpid-install-banner.png
Binary files differ
diff --git a/qpid/cpp/rubygen/framing.0-10/structs.rb b/qpid/cpp/rubygen/framing.0-10/structs.rb
index 809e453381..c3684aea66 100755
--- a/qpid/cpp/rubygen/framing.0-10/structs.rb
+++ b/qpid/cpp/rubygen/framing.0-10/structs.rb
@@ -381,9 +381,10 @@ EOS
else
inheritance = ": public AMQMethodBody"
end
+ else
+ public_api("qpid/framing/#{classname}.h") # Non-method structs are public
end
- public_api("qpid/framing/#{classname}.h")
h_file("qpid/framing/#{classname}.h") {
if (s.kind_of? AmqpMethod)
gen <<EOS
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index 786facced9..6deacbbece 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -118,19 +118,6 @@ if (ENABLE_VALGRIND AND NOT VALGRIND)
message(STATUS "Can't locate the valgrind command; no run-time error detection")
endif (ENABLE_VALGRIND AND NOT VALGRIND)
-set(QPIDC_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING
- "Directory to install library files")
-set(QPIDC_INSTALL_CONFDIR ${CMAKE_INSTALL_PREFIX}/etc CACHE STRING
- "Directory to install configuration files")
-set(QPIDC_MODULE_DIR ${QPIDC_INSTALL_LIBDIR}/qpid/client CACHE STRING
- "Directory to load client plug-in modules from")
-set(QPIDD_MODULE_DIR ${QPIDC_INSTALL_LIBDIR}/qpid/daemon CACHE STRING
- "Directory to load broker plug-in modules from")
-set(QPIDC_CONF_FILE ${QPIDC_INSTALL_CONFDIR}/qpid/qpidc.conf CACHE STRING
- "Name of the Qpid client configuration file")
-set(QPIDD_CONF_FILE ${QPIDC_INSTALL_CONFDIR}/qpid/qpidd.conf CACHE STRING
- "Name of the Qpid broker configuration file")
-
option(ENABLE_WARNINGS "Enable lots of compiler warnings (recommended)" ON)
if (ENABLE_WARNINGS AND CMAKE_COMPILER_IS_GNUCXX)
# Warnings: Enable as many as possible, keep the code clean. Please
@@ -272,6 +259,9 @@ if (BUILD_XML)
PREFIX ""
LINK_FLAGS -Wl,--no-undefined)
endif (CMAKE_COMPILER_IS_GNUCXX)
+ install (TARGETS xml RUNTIME
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
set(xml_tests XmlClientSessionTest)
@@ -301,6 +291,9 @@ if (BUILD_ACL)
PREFIX ""
LINK_FLAGS -Wl,--no-undefined)
endif (CMAKE_COMPILER_IS_GNUCXX)
+ install (TARGETS acl
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
endif (BUILD_ACL)
# Check for optional cluster support requirements
@@ -329,7 +322,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows)
)
endif (MSVC)
- set (libqpidcommon_platform_SOURCES
+ set (qpidcommon_platform_SOURCES
qpid/log/windows/SinkOptions.cpp
qpid/sys/windows/AsynchIO.cpp
qpid/sys/windows/FileSysDir.cpp
@@ -346,15 +339,22 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows)
qpid/sys/windows/Time.cpp
qpid/sys/windows/uuid.cpp
)
- set (libqpidcommon_platform_LIBS
+ set (qpidcommon_platform_LIBS
rpcrt4 ws2_32
)
- set (libqpidbroker_platform_SOURCES
+ set (qpidcommon_platform_INSTALL_HEADERS
+ ../include/qpid/sys/windows/Condition.h
+ ../include/qpid/sys/windows/IntegerTypes.h
+ ../include/qpid/sys/windows/Mutex.h
+ ../include/qpid/sys/windows/Time.h
+ ../include/qpid/sys/windows/check.h
+ )
+ set (qpidbroker_platform_SOURCES
qpid/broker/windows/BrokerDefaults.cpp
qpid/broker/windows/SaslAuthenticator.cpp
)
- set (libqpidclient_platform_SOURCES
+ set (qpidclient_platform_SOURCES
qpid/client/windows/SaslFactory.cpp
)
@@ -375,7 +375,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows)
set (qpid_poller_module qpid/sys/solaris/ECFPoller.cpp)
endif (CMAKE_SYSTEM_NAME STREQUAL SunOS)
- set (libqpidcommon_platform_SOURCES
+ set (qpidcommon_platform_SOURCES
qpid/sys/posix/AsynchIO.cpp
qpid/sys/posix/Fork.cpp
qpid/sys/posix/FileSysDir.cpp
@@ -394,14 +394,22 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows)
${qpid_poller_module}
)
- set (libqpidcommon_platform_LIBS
+ set (qpidcommon_platform_LIBS
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
uuid
${CMAKE_DL_LIBS}
)
+ set (qpidcommon_platform_INSTALL_HEADERS
+ ../include/qpid/sys/posix/Condition.h
+ ../include/qpid/sys/posix/IntegerTypes.h
+ ../include/qpid/sys/posix/Mutex.h
+ ../include/qpid/sys/posix/PrivatePosix.h
+ ../include/qpid/sys/posix/Time.h
+ ../include/qpid/sys/posix/check.h
+ )
- set (libqpidbroker_platform_SOURCES
+ set (qpidbroker_platform_SOURCES
qpid/broker/Daemon.cpp
qpid/broker/SaslAuthenticator.cpp
qpid/broker/SignalHandler.h
@@ -409,7 +417,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows)
qpid/broker/posix/BrokerDefaults.cpp
)
- set (libqpidclient_platform_SOURCES
+ set (qpidclient_platform_SOURCES
qpid/client/SaslFactory.cpp
)
@@ -418,9 +426,9 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows)
)
endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
-set (libqpidcommon_SOURCES
+set (qpidcommon_SOURCES
${rgen_framing_srcs}
- ${libqpidcommon_platform_SOURCES}
+ ${qpidcommon_platform_SOURCES}
${qpidcommon_sasl_source}
qpid/assert.cpp
qpid/Address.cpp
@@ -476,19 +484,23 @@ set (libqpidcommon_SOURCES
qpid/sys/Shlib.cpp
qpid/sys/Timer.cpp
)
-add_library (qpidcommon SHARED ${libqpidcommon_SOURCES})
+
+add_library (qpidcommon SHARED ${qpidcommon_SOURCES})
if (CLOCK_GETTIME_IN_RT)
- set (libqpidcommon_platform_LIBS ${libqpidcommon_platform_LIBS} rt)
+ set (qpidcommon_platform_LIBS ${qpidcommon_platform_LIBS} rt)
endif (CLOCK_GETTIME_IN_RT)
target_link_libraries (qpidcommon
- ${libqpidcommon_platform_LIBS}
+ ${qpidcommon_platform_LIBS}
${qpidcommon_sasl_lib})
set_target_properties (qpidcommon PROPERTIES
VERSION ${qpidc_version})
+install (TARGETS qpidcommon
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_COMMON})
-set (libqpidclient_SOURCES
+set (qpidclient_SOURCES
${rgen_client_srcs}
- ${libqpidclient_platform_SOURCES}
+ ${qpidclient_platform_SOURCES}
qpid/client/Bounds.cpp
qpid/client/Completion.cpp
qpid/client/Connection.cpp
@@ -527,6 +539,10 @@ set (libqpidclient_SOURCES
qpid/messaging/Connection.cpp
qpid/messaging/ConnectionImpl.h
qpid/messaging/Filter.cpp
+ qpid/messaging/ListContent.cpp
+ qpid/messaging/ListView.cpp
+ qpid/messaging/MapContent.cpp
+ qpid/messaging/MapView.cpp
qpid/messaging/Message.cpp
qpid/messaging/MessageImpl.h
qpid/messaging/MessageImpl.cpp
@@ -558,13 +574,100 @@ set (libqpidclient_SOURCES
qpid/client/amqp0_10/SenderImpl.h
qpid/client/amqp0_10/SenderImpl.cpp
)
-add_library (qpidclient SHARED ${libqpidclient_SOURCES})
+set (qpidclient_INSTALL_HEADERS
+ ../include/qpid/Address.h
+ ../include/qpid/CommonImportExport.h
+ ../include/qpid/Exception.h
+ ../include/qpid/InlineAllocator.h
+ ../include/qpid/InlineVector.h
+ ../include/qpid/Msg.h
+ ../include/qpid/Options.h
+ ../include/qpid/RangeSet.h
+ ../include/qpid/SessionId.h
+ ../include/qpid/Url.h
+ ../include/qpid/client/AsyncSession.h
+ ../include/qpid/client/ClientImportExport.h
+ ../include/qpid/client/Completion.h
+ ../include/qpid/client/Connection.h
+ ../include/qpid/client/ConnectionSettings.h
+ ../include/qpid/client/FailoverManager.h
+ ../include/qpid/client/FlowControl.h
+ ../include/qpid/client/Future.h
+ ../include/qpid/client/FutureCompletion.h
+ ../include/qpid/client/FutureResult.h
+ ../include/qpid/client/Handle.h
+ ../include/qpid/client/LocalQueue.h
+ ../include/qpid/client/Message.h
+ ../include/qpid/client/MessageListener.h
+ ../include/qpid/client/MessageReplayTracker.h
+ ../include/qpid/client/QueueOptions.h
+ ../include/qpid/client/Session.h
+ ../include/qpid/client/SessionBase_0_10.h
+ ../include/qpid/client/Subscription.h
+ ../include/qpid/client/SubscriptionManager.h
+ ../include/qpid/client/SubscriptionSettings.h
+ ../include/qpid/client/TypedResult.h
+ ../include/qpid/framing/Array.h
+ ../include/qpid/framing/Buffer.h
+ ../include/qpid/framing/FieldTable.h
+ ../include/qpid/framing/FieldValue.h
+ ../include/qpid/framing/List.h
+ ../include/qpid/framing/ProtocolVersion.h
+ ../include/qpid/framing/SequenceNumber.h
+ ../include/qpid/framing/SequenceSet.h
+ ../include/qpid/framing/StructHelper.h
+ ../include/qpid/framing/Uuid.h
+ ../include/qpid/framing/amqp_types.h
+ ../include/qpid/framing/amqp_types_full.h
+ ../include/qpid/log/Logger.h
+ ../include/qpid/log/Options.h
+ ../include/qpid/log/Selector.h
+ ../include/qpid/log/SinkOptions.h
+ ../include/qpid/log/Statement.h
+ ../include/qpid/management/Args.h
+ ../include/qpid/management/Manageable.h
+ ../include/qpid/management/ManagementEvent.h
+ ../include/qpid/management/ManagementObject.h
+ ../include/qpid/sys/Condition.h
+ ../include/qpid/sys/IOHandle.h
+ ../include/qpid/sys/IntegerTypes.h
+ ../include/qpid/sys/Monitor.h
+ ../include/qpid/sys/Mutex.h
+ ../include/qpid/sys/Runnable.h
+ ../include/qpid/sys/StrError.h
+ ../include/qpid/sys/SystemInfo.h
+ ../include/qpid/sys/Thread.h
+ ../include/qpid/sys/Time.h
+ ../include/qpid/messaging/Address.h
+ ../include/qpid/messaging/Connection.h
+ ../include/qpid/messaging/Codec.h
+ ../include/qpid/messaging/Filter.h
+ ../include/qpid/messaging/ListContent.h
+ ../include/qpid/messaging/ListView.h
+ ../include/qpid/messaging/MapContent.h
+ ../include/qpid/messaging/MapView.h
+ ../include/qpid/messaging/Message.h
+ ../include/qpid/messaging/MessageListener.h
+ ../include/qpid/messaging/Sender.h
+ ../include/qpid/messaging/Receiver.h
+ ../include/qpid/messaging/Session.h
+ ../include/qpid/messaging/Variant.h
+ ../include/qpid/client/amqp0_10/Codecs.h
+)
+
+add_library (qpidclient SHARED ${qpidclient_SOURCES})
target_link_libraries (qpidclient qpidcommon)
set_target_properties (qpidclient PROPERTIES VERSION ${qpidc_version})
-
-set (libqpidbroker_SOURCES
+install (TARGETS qpidclient
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+install (DIRECTORY ../include/qpid DESTINATION ${QPID_INSTALL_INCLUDEDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE}
+ PATTERN ".svn" EXCLUDE)
+
+set (qpidbroker_SOURCES
${mgen_broker_cpp}
- ${libqpidbroker_platform_SOURCES}
+ ${qpidbroker_platform_SOURCES}
qpid/amqp_0_10/Connection.h
qpid/amqp_0_10/Connection.cpp
qpid/broker/Broker.cpp
@@ -629,12 +732,15 @@ set (libqpidbroker_SOURCES
qpid/management/ManagementExchange.cpp
qpid/sys/TCPIOPlugin.cpp
)
-add_library (qpidbroker SHARED ${libqpidbroker_SOURCES})
+add_library (qpidbroker SHARED ${qpidbroker_SOURCES})
target_link_libraries (qpidbroker qpidcommon)
set_target_properties (qpidbroker PROPERTIES VERSION ${qpidc_version})
if (MSVC)
set_target_properties (qpidbroker PROPERTIES COMPILE_FLAGS /wd4290)
endif (MSVC)
+install (TARGETS qpidbroker LIBRARY
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
set (qpidd_SOURCES
${qpidd_platform_SOURCES}
@@ -644,53 +750,65 @@ set (qpidd_SOURCES
add_executable (qpidd ${qpidd_SOURCES})
target_link_libraries (qpidd qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY})
+install (TARGETS qpidd RUNTIME
+ DESTINATION ${QPID_INSTALL_BINDIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
-# QMF agent library
-#module_hdr += \
-# qpid/agent/ManagementAgent.h \
-# qpid/agent/ManagementAgentImpl.h
-set (qmfagent_SOURCES
- qmf/AgentEngine.cpp
- qmf/AgentEngine.h
+# QMF library
+# Library Version Information (CURRENT.REVISION.AGE):
+#
+# CURRENT => API/ABI version. Bump this if the interface changes
+# REVISION => Version of underlying implementation.
+# Bump if implementation changes but API/ABI doesn't
+# AGE => Number of API/ABI versions this is backward compatible with
+set (qmf_version 1.0.0)
+set (qmfengine_version 1.0.0)
+
+set (qmf_SOURCES
qpid/agent/ManagementAgentImpl.cpp
qpid/agent/ManagementAgentImpl.h
)
-add_library (qmfagent SHARED ${qmfagent_SOURCES})
-target_link_libraries (qmfagent qmfcommon)
-set_target_properties (qmfagent PROPERTIES
- VERSION ${qpidc_version})
-
-set (qmfcommon_SOURCES
- qmf/ConnectionSettingsImpl.cpp
- qmf/ConnectionSettingsImpl.h
- qmf/ConsoleEngine.h
- qmf/Event.h
- qmf/Message.h
- qmf/MessageImpl.cpp
- qmf/MessageImpl.h
- qmf/Object.h
- qmf/ObjectId.h
- qmf/ObjectIdImpl.cpp
- qmf/ObjectIdImpl.h
- qmf/ObjectImpl.cpp
- qmf/ObjectImpl.h
- qmf/Query.h
- qmf/QueryImpl.cpp
- qmf/QueryImpl.h
- qmf/ResilientConnection.cpp
- qmf/ResilientConnection.h
- qmf/Schema.h
- qmf/SchemaImpl.cpp
- qmf/SchemaImpl.h
- qmf/Typecode.h
- qmf/Value.h
- qmf/ValueImpl.cpp
- qmf/ValueImpl.h
+add_library (qmf SHARED ${qmf_SOURCES})
+target_link_libraries (qmf qmfengine)
+set_target_properties (qmf PROPERTIES
+ VERSION ${qmf_version})
+install (TARGETS qmf LIBRARY
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
+
+set (qmfengine_SOURCES
+ qmf/engine/Agent.cpp
+ qmf/engine/BrokerProxyImpl.cpp
+ qmf/engine/BrokerProxyImpl.h
+ qmf/engine/ConnectionSettingsImpl.cpp
+ qmf/engine/ConnectionSettingsImpl.h
+ qmf/engine/ConsoleImpl.cpp
+ qmf/engine/ConsoleImpl.h
+ qmf/engine/MessageImpl.cpp
+ qmf/engine/MessageImpl.h
+ qmf/engine/ObjectIdImpl.cpp
+ qmf/engine/ObjectIdImpl.h
+ qmf/engine/ObjectImpl.cpp
+ qmf/engine/ObjectImpl.h
+ qmf/engine/Protocol.cpp
+ qmf/engine/Protocol.h
+ qmf/engine/QueryImpl.cpp
+ qmf/engine/QueryImpl.h
+ qmf/engine/ResilientConnection.cpp
+ qmf/engine/SequenceManager.cpp
+ qmf/engine/SequenceManager.h
+ qmf/engine/SchemaImpl.cpp
+ qmf/engine/SchemaImpl.h
+ qmf/engine/ValueImpl.cpp
+ qmf/engine/ValueImpl.h
)
-add_library (qmfcommon SHARED ${qmfcommon_SOURCES})
-target_link_libraries (qmfcommon qpidclient)
-set_target_properties (qmfcommon PROPERTIES
- VERSION ${qpidc_version})
+add_library (qmfengine SHARED ${qmfengine_SOURCES})
+target_link_libraries (qmfengine qpidclient)
+set_target_properties (qmfengine PROPERTIES
+ VERSION ${qmfengine_version})
+install (TARGETS qmfengine
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
# QMF console library
#module_hdr += \
@@ -737,6 +855,9 @@ add_library (qmfconsole SHARED ${qmfconsole_SOURCES})
target_link_libraries (qmfconsole qpidclient)
set_target_properties (qmfconsole PROPERTIES
VERSION ${qpidc_version})
+install (TARGETS qmfconsole
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
# A queue event listener plugin that creates messages on a replication
# queue corresponding to enqueue and dequeue events:
@@ -752,6 +873,9 @@ if (CMAKE_COMPILER_IS_GNUCXX)
set_target_properties(replicating_listener PROPERTIES
LINK_FLAGS -Wl,--no-undefined)
endif (CMAKE_COMPILER_IS_GNUCXX)
+install (TARGETS replicating_listener
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
# A custom exchange plugin that allows an exchange to be created that
# can process the messages from a replication queue (populated on the
@@ -769,6 +893,9 @@ if (CMAKE_COMPILER_IS_GNUCXX)
set_target_properties(replicating_exchange PROPERTIES
LINK_FLAGS -Wl,--no-undefined)
endif (CMAKE_COMPILER_IS_GNUCXX)
+install (TARGETS replicating_exchange
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
# This is only really needed until all the trunk builds (Linux, UNIX, Windows)
# are all on cmake only. This is because cmake builds always have a config.h
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 4988f3f031..a6b90d7bde 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -144,6 +144,7 @@ libqpidcommon_la_SOURCES += \
qpid/log/posix/SinkOptions.cpp \
qpid/sys/posix/IOHandle.cpp \
qpid/sys/posix/Socket.cpp \
+ qpid/sys/posix/SocketAddress.cpp \
qpid/sys/posix/AsynchIO.cpp \
qpid/sys/posix/FileSysDir.cpp \
qpid/sys/posix/LockFile.cpp \
@@ -456,6 +457,7 @@ libqpidcommon_la_SOURCES += \
qpid/sys/Shlib.h \
qpid/sys/ShutdownHandler.h \
qpid/sys/Socket.h \
+ qpid/sys/SocketAddress.h \
qpid/sys/StateMonitor.h \
qpid/sys/TimeoutHandler.h \
qpid/sys/Timer.cpp \
@@ -686,6 +688,10 @@ libqpidclient_la_SOURCES = \
qpid/messaging/Address.cpp \
qpid/messaging/Connection.cpp \
qpid/messaging/Filter.cpp \
+ qpid/messaging/ListContent.cpp \
+ qpid/messaging/ListView.cpp \
+ qpid/messaging/MapContent.cpp \
+ qpid/messaging/MapView.cpp \
qpid/messaging/Message.cpp \
qpid/messaging/MessageImpl.h \
qpid/messaging/MessageImpl.cpp \
@@ -790,8 +796,11 @@ nobase_include_HEADERS += \
../include/qpid/messaging/Connection.h \
../include/qpid/messaging/Codec.h \
../include/qpid/messaging/Filter.h \
+ ../include/qpid/messaging/ListContent.h \
+ ../include/qpid/messaging/ListView.h \
+ ../include/qpid/messaging/MapContent.h \
+ ../include/qpid/messaging/MapView.h \
../include/qpid/messaging/Message.h \
- ../include/qpid/messaging/MessageContent.h \
../include/qpid/messaging/MessageListener.h \
../include/qpid/messaging/Sender.h \
../include/qpid/messaging/Receiver.h \
diff --git a/qpid/cpp/src/cluster.mk b/qpid/cpp/src/cluster.mk
index d90a06e1e2..1a8812d169 100644
--- a/qpid/cpp/src/cluster.mk
+++ b/qpid/cpp/src/cluster.mk
@@ -82,8 +82,7 @@ cluster_la_SOURCES = \
qpid/cluster/PollerDispatch.h \
qpid/cluster/ProxyInputHandler.h \
qpid/cluster/Quorum.h \
- qpid/cluster/types.h \
- qpid/sys/LatencyTracker.h
+ qpid/cluster/types.h
cluster_la_LIBADD= -lcpg $(libcman) libqpidbroker.la libqpidclient.la
cluster_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing
diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk
index 54110ebaf7..2d034cf7c4 100644
--- a/qpid/cpp/src/qmf.mk
+++ b/qpid/cpp/src/qmf.mk
@@ -20,12 +20,14 @@
#
# qmf library makefile fragment, to be included in Makefile.am
#
-lib_LTLIBRARIES += \
- libqmfcommon.la \
- libqmfagent.la
+lib_LTLIBRARIES += \
+ libqmf.la \
+ libqmfengine.la
-# Public header files
-nobase_include_HEADERS += \
+#
+# Public headers for the QMF API
+#
+QMF_API = \
../include/qpid/agent/ManagementAgent.h \
../include/qpid/agent/QmfAgentImportExport.h \
../include/qmf/Agent.h \
@@ -34,42 +36,78 @@ nobase_include_HEADERS += \
../include/qmf/ConnectionSettings.h \
../include/qmf/AgentObject.h
-libqmfcommon_la_SOURCES = \
- qmf/ConnectionSettingsImpl.cpp \
- qmf/ConnectionSettingsImpl.h \
- qmf/ConsoleEngine.cpp \
- qmf/ConsoleEngine.h \
- qmf/Event.h \
- qmf/Message.h \
- qmf/MessageImpl.cpp \
- qmf/MessageImpl.h \
- qmf/Object.h \
- qmf/ObjectId.h \
- qmf/ObjectIdImpl.cpp \
- qmf/ObjectIdImpl.h \
- qmf/ObjectImpl.cpp \
- qmf/ObjectImpl.h \
- qmf/Protocol.cpp \
- qmf/Protocol.h \
- qmf/Query.h \
- qmf/QueryImpl.cpp \
- qmf/QueryImpl.h \
- qmf/ResilientConnection.cpp \
- qmf/ResilientConnection.h \
- qmf/SequenceManager.cpp \
- qmf/SequenceManager.h \
- qmf/Schema.h \
- qmf/SchemaImpl.cpp \
- qmf/SchemaImpl.h \
- qmf/Typecode.h \
- qmf/Value.h \
- qmf/ValueImpl.cpp \
- qmf/ValueImpl.h
+#
+# Public headers for the QMF Engine API
+#
+QMF_ENGINE_API = \
+ ../include/qmf/engine/Agent.h \
+ ../include/qmf/engine/ConnectionSettings.h \
+ ../include/qmf/engine/Console.h \
+ ../include/qmf/engine/Event.h \
+ ../include/qmf/engine/Message.h \
+ ../include/qmf/engine/Object.h \
+ ../include/qmf/engine/ObjectId.h \
+ ../include/qmf/engine/QmfEngineImportExport.h \
+ ../include/qmf/engine/Query.h \
+ ../include/qmf/engine/ResilientConnection.h \
+ ../include/qmf/engine/Schema.h \
+ ../include/qmf/engine/Typecode.h \
+ ../include/qmf/engine/Value.h
+
+# Public header files
+nobase_include_HEADERS += \
+ $(QMF_API) \
+ $(QMF_ENGINE_API)
-libqmfagent_la_SOURCES = \
- qmf/AgentEngine.cpp \
- qmf/AgentEngine.h \
- qpid/agent/ManagementAgentImpl.cpp \
+libqmf_la_SOURCES = \
+ $(QMF_API) \
+ qpid/agent/ManagementAgentImpl.cpp \
qpid/agent/ManagementAgentImpl.h
-libqmfagent_la_LIBADD = libqpidclient.la libqmfcommon.la
+libqmfengine_la_SOURCES = \
+ $(QMF_ENGINE_API) \
+ qmf/engine/Agent.cpp \
+ qmf/engine/BrokerProxyImpl.cpp \
+ qmf/engine/BrokerProxyImpl.h \
+ qmf/engine/ConnectionSettingsImpl.cpp \
+ qmf/engine/ConnectionSettingsImpl.h \
+ qmf/engine/ConsoleImpl.cpp \
+ qmf/engine/ConsoleImpl.h \
+ qmf/engine/MessageImpl.cpp \
+ qmf/engine/MessageImpl.h \
+ qmf/engine/ObjectIdImpl.cpp \
+ qmf/engine/ObjectIdImpl.h \
+ qmf/engine/ObjectImpl.cpp \
+ qmf/engine/ObjectImpl.h \
+ qmf/engine/Protocol.cpp \
+ qmf/engine/Protocol.h \
+ qmf/engine/QueryImpl.cpp \
+ qmf/engine/QueryImpl.h \
+ qmf/engine/ResilientConnection.cpp \
+ qmf/engine/SequenceManager.cpp \
+ qmf/engine/SequenceManager.h \
+ qmf/engine/SchemaImpl.cpp \
+ qmf/engine/SchemaImpl.h \
+ qmf/engine/ValueImpl.cpp \
+ qmf/engine/ValueImpl.h
+
+libqmf_la_LIBADD = libqmfengine.la
+libqmfengine_la_LIBADD = libqpidclient.la
+
+# Library Version Information:
+#
+# CURRENT => API/ABI version. Bump this if the interface changes
+# REVISION => Version of underlying implementation.
+# Bump if implementation changes but API/ABI doesn't
+# AGE => Number of API/ABI versions this is backward compatible with
+#
+QMF_CURRENT = 1
+QMF_REVISION = 0
+QMF_AGE = 0
+
+QMF_ENGINE_CURRENT = 1
+QMF_ENGINE_REVISION = 0
+QMF_ENGINE_AGE = 0
+
+libqmf_la_LDFLAGS = -version-info $(QMF_CURRENT):$(QMF_REVISION):$(QMF_AGE)
+libqmfengine_la_LDFLAGS = -version-info $(QMF_ENGINE_CURRENT):$(QMF_ENGINE_REVISION):$(QMF_ENGINE_AGE)
diff --git a/qpid/cpp/src/qmf/ConsoleEngine.cpp b/qpid/cpp/src/qmf/ConsoleEngine.cpp
deleted file mode 100644
index e7991328ee..0000000000
--- a/qpid/cpp/src/qmf/ConsoleEngine.cpp
+++ /dev/null
@@ -1,1091 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "qmf/ConsoleEngine.h"
-#include "qmf/MessageImpl.h"
-#include "qmf/SchemaImpl.h"
-#include "qmf/Typecode.h"
-#include "qmf/ObjectImpl.h"
-#include "qmf/ObjectIdImpl.h"
-#include "qmf/QueryImpl.h"
-#include "qmf/ValueImpl.h"
-#include "qmf/Protocol.h"
-#include "qmf/SequenceManager.h"
-#include <qpid/framing/Buffer.h>
-#include <qpid/framing/Uuid.h>
-#include <qpid/framing/FieldTable.h>
-#include <qpid/framing/FieldValue.h>
-#include <qpid/sys/Mutex.h>
-#include <qpid/log/Statement.h>
-#include <qpid/sys/Time.h>
-#include <qpid/sys/SystemInfo.h>
-#include <string.h>
-#include <string>
-#include <deque>
-#include <map>
-#include <vector>
-#include <iostream>
-#include <fstream>
-#include <boost/shared_ptr.hpp>
-
-using namespace std;
-using namespace qmf;
-using namespace qpid::framing;
-using namespace qpid::sys;
-
-namespace qmf {
-
- struct MethodResponseImpl {
- typedef boost::shared_ptr<MethodResponseImpl> Ptr;
- MethodResponse* envelope;
- uint32_t status;
- auto_ptr<Value> exception;
- auto_ptr<Value> arguments;
-
- MethodResponseImpl(Buffer& buf);
- ~MethodResponseImpl() { delete envelope; }
- uint32_t getStatus() const { return status; }
- const Value* getException() const { return exception.get(); }
- const Value* getArgs() const { return arguments.get(); }
- };
-
- struct QueryResponseImpl {
- typedef boost::shared_ptr<QueryResponseImpl> Ptr;
- QueryResponse *envelope;
- uint32_t status;
- auto_ptr<Value> exception;
- vector<ObjectImpl::Ptr> results;
-
- QueryResponseImpl() : envelope(new QueryResponse(this)), status(0) {}
- ~QueryResponseImpl() { delete envelope; }
- uint32_t getStatus() const { return status; }
- const Value* getException() const { return exception.get(); }
- uint32_t getObjectCount() const { return results.size(); }
- const Object* getObject(uint32_t idx) const;
- };
-
- struct ConsoleEventImpl {
- typedef boost::shared_ptr<ConsoleEventImpl> Ptr;
- ConsoleEvent::EventKind kind;
- boost::shared_ptr<AgentProxyImpl> agent;
- string name;
- boost::shared_ptr<SchemaClassKey> classKey;
- Object* object;
- void* context;
- Event* event;
- uint64_t timestamp;
- uint32_t methodHandle;
- MethodResponseImpl::Ptr methodResponse;
-
- ConsoleEventImpl(ConsoleEvent::EventKind k) :
- kind(k), object(0), context(0), event(0), timestamp(0), methodHandle(0) {}
- ~ConsoleEventImpl() {}
- ConsoleEvent copy();
- };
-
- struct BrokerEventImpl {
- typedef boost::shared_ptr<BrokerEventImpl> Ptr;
- BrokerEvent::EventKind kind;
- string name;
- string exchange;
- string bindingKey;
- void* context;
- QueryResponseImpl::Ptr queryResponse;
-
- BrokerEventImpl(BrokerEvent::EventKind k) : kind(k) {}
- ~BrokerEventImpl() {}
- BrokerEvent copy();
- };
-
- struct AgentProxyImpl {
- typedef boost::shared_ptr<AgentProxyImpl> Ptr;
- AgentProxy* envelope;
- ConsoleEngineImpl* console;
- BrokerProxyImpl* broker;
- uint32_t agentBank;
- string label;
-
- AgentProxyImpl(ConsoleEngineImpl* c, BrokerProxyImpl* b, uint32_t ab, const string& l) :
- envelope(new AgentProxy(this)), console(c), broker(b), agentBank(ab), label(l) {}
- ~AgentProxyImpl() {}
- const string& getLabel() const { return label; }
- };
-
- class BrokerProxyImpl {
- public:
- typedef boost::shared_ptr<BrokerProxyImpl> Ptr;
-
- BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console);
- ~BrokerProxyImpl() {}
-
- void sessionOpened(SessionHandle& sh);
- void sessionClosed();
- void startProtocol();
-
- void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
- void handleRcvMessage(Message& message);
- bool getXmtMessage(Message& item) const;
- void popXmt();
-
- bool getEvent(BrokerEvent& event) const;
- void popEvent();
-
- uint32_t agentCount() const;
- const AgentProxy* getAgent(uint32_t idx) const;
- void sendQuery(const Query& query, void* context, const AgentProxy* agent);
- void sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent);
-
- void addBinding(const string& exchange, const string& key);
- void staticRelease() { decOutstanding(); }
-
- private:
- friend class StaticContext;
- friend class QueryContext;
- mutable Mutex lock;
- BrokerProxy* envelope;
- ConsoleEngineImpl* console;
- string queueName;
- Uuid brokerId;
- SequenceManager seqMgr;
- uint32_t requestsOutstanding;
- bool topicBound;
- vector<AgentProxyImpl::Ptr> agentList;
- deque<MessageImpl::Ptr> xmtQueue;
- deque<BrokerEventImpl::Ptr> eventQueue;
-
-# define MA_BUFFER_SIZE 65536
- char outputBuffer[MA_BUFFER_SIZE];
-
- BrokerEventImpl::Ptr eventDeclareQueue(const string& queueName);
- BrokerEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key);
- BrokerEventImpl::Ptr eventSetupComplete();
- BrokerEventImpl::Ptr eventStable();
- BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponseImpl::Ptr response);
-
- void handleBrokerResponse(Buffer& inBuffer, uint32_t seq);
- void handlePackageIndication(Buffer& inBuffer, uint32_t seq);
- void handleCommandComplete(Buffer& inBuffer, uint32_t seq);
- void handleClassIndication(Buffer& inBuffer, uint32_t seq);
- void handleMethodResponse(Buffer& inBuffer, uint32_t seq);
- void handleHeartbeatIndication(Buffer& inBuffer, uint32_t seq);
- void handleEventIndication(Buffer& inBuffer, uint32_t seq);
- void handleSchemaResponse(Buffer& inBuffer, uint32_t seq);
- ObjectImpl::Ptr handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat);
- void incOutstandingLH();
- void decOutstanding();
- };
-
- struct StaticContext : public SequenceContext {
- StaticContext(BrokerProxyImpl& b) : broker(b) {}
- ~StaticContext() {}
- void reserve() {}
- void release() { broker.staticRelease(); }
- bool handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer);
- BrokerProxyImpl& broker;
- };
-
- struct QueryContext : public SequenceContext {
- QueryContext(BrokerProxyImpl& b, void* u) :
- broker(b), userContext(u), requestsOutstanding(0), queryResponse(new QueryResponseImpl()) {}
- ~QueryContext() {}
- void reserve();
- void release();
- bool handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer);
-
- mutable Mutex lock;
- BrokerProxyImpl& broker;
- void* userContext;
- uint32_t requestsOutstanding;
- QueryResponseImpl::Ptr queryResponse;
- };
-
- class ConsoleEngineImpl {
- public:
- ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& settings = ConsoleSettings());
- ~ConsoleEngineImpl();
-
- bool getEvent(ConsoleEvent& event) const;
- void popEvent();
-
- void addConnection(BrokerProxy& broker, void* context);
- void delConnection(BrokerProxy& broker);
-
- uint32_t packageCount() const;
- const string& getPackageName(uint32_t idx) const;
-
- uint32_t classCount(const char* packageName) const;
- const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
-
- ClassKind getClassKind(const SchemaClassKey* key) const;
- const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
- const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
-
- void bindPackage(const char* packageName);
- void bindClass(const SchemaClassKey* key);
- void bindClass(const char* packageName, const char* className);
-
- /*
- void startSync(const Query& query, void* context, SyncQuery& sync);
- void touchSync(SyncQuery& sync);
- void endSync(SyncQuery& sync);
- */
-
- private:
- friend class BrokerProxyImpl;
- ConsoleEngine* envelope;
- const ConsoleSettings& settings;
- mutable Mutex lock;
- deque<ConsoleEventImpl::Ptr> eventQueue;
- vector<BrokerProxyImpl*> brokerList;
- vector<pair<string, string> > bindingList; // exchange/key (empty exchange => QMF_EXCHANGE)
-
- // Declare a compare class for the class maps that compares the dereferenced
- // class key pointers. The default behavior would be to compare the pointer
- // addresses themselves.
- struct KeyCompare {
- bool operator()(const SchemaClassKeyImpl* left, const SchemaClassKeyImpl* right) const {
- return *left < *right;
- }
- };
-
- typedef map<const SchemaClassKeyImpl*, SchemaObjectClassImpl::Ptr, KeyCompare> ObjectClassList;
- typedef map<const SchemaClassKeyImpl*, SchemaEventClassImpl::Ptr, KeyCompare> EventClassList;
- typedef map<string, pair<ObjectClassList, EventClassList> > PackageList;
-
- PackageList packages;
-
- void learnPackage(const string& packageName);
- void learnClass(SchemaObjectClassImpl::Ptr cls);
- void learnClass(SchemaEventClassImpl::Ptr cls);
- bool haveClass(const SchemaClassKeyImpl& key) const;
- SchemaObjectClassImpl::Ptr getSchema(const SchemaClassKeyImpl& key) const;
- };
-}
-
-namespace {
- const char* QMF_EXCHANGE = "qpid.management";
- const char* DIR_EXCHANGE = "amq.direct";
- const char* BROKER_KEY = "broker";
- const char* BROKER_PACKAGE = "org.apache.qpid.broker";
- const char* AGENT_CLASS = "agent";
- const char* BROKER_AGENT_KEY = "agent.1.0";
-}
-
-const Object* QueryResponseImpl::getObject(uint32_t idx) const
-{
- vector<ObjectImpl::Ptr>::const_iterator iter = results.begin();
-
- while (idx > 0) {
- if (iter == results.end())
- return 0;
- iter++;
- idx--;
- }
-
- return (*iter)->envelope;
-}
-
-#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
-
-ConsoleEvent ConsoleEventImpl::copy()
-{
- ConsoleEvent item;
-
- ::memset(&item, 0, sizeof(ConsoleEvent));
- item.kind = kind;
- item.agent = agent.get() ? agent->envelope : 0;
- item.classKey = classKey.get();
- item.object = object;
- item.context = context;
- item.event = event;
- item.timestamp = timestamp;
- item.methodHandle = methodHandle;
- item.methodResponse = methodResponse.get() ? methodResponse->envelope : 0;
-
- STRING_REF(name);
-
- return item;
-}
-
-BrokerEvent BrokerEventImpl::copy()
-{
- BrokerEvent item;
-
- ::memset(&item, 0, sizeof(BrokerEvent));
- item.kind = kind;
-
- STRING_REF(name);
- STRING_REF(exchange);
- STRING_REF(bindingKey);
- item.context = context;
- item.queryResponse = queryResponse.get() ? queryResponse->envelope : 0;
-
- return item;
-}
-
-BrokerProxyImpl::BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console) :
- envelope(e), console(_console.impl)
-{
- stringstream qn;
- qpid::TcpAddress addr;
-
- SystemInfo::getLocalHostname(addr);
- qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId();
- queueName = qn.str();
-
- seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this)));
-}
-
-void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/)
-{
- Mutex::ScopedLock _lock(lock);
- agentList.clear();
- eventQueue.clear();
- xmtQueue.clear();
- eventQueue.push_back(eventDeclareQueue(queueName));
- eventQueue.push_back(eventBind(DIR_EXCHANGE, queueName, queueName));
- eventQueue.push_back(eventSetupComplete());
-
- // TODO: Store session handle
-}
-
-void BrokerProxyImpl::sessionClosed()
-{
- Mutex::ScopedLock _lock(lock);
- agentList.clear();
- eventQueue.clear();
- xmtQueue.clear();
-}
-
-void BrokerProxyImpl::startProtocol()
-{
- Mutex::ScopedLock _lock(lock);
- char rawbuffer[512];
- Buffer buffer(rawbuffer, 512);
-
- agentList.push_back(AgentProxyImpl::Ptr(new AgentProxyImpl(console, this, 0, "Agent embedded in broker")));
-
- requestsOutstanding = 1;
- topicBound = false;
- uint32_t sequence(seqMgr.reserve());
- Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence);
- sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
- QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence);
-}
-
-void BrokerProxyImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
-{
- uint32_t length = buf.getPosition();
- MessageImpl::Ptr message(new MessageImpl);
-
- buf.reset();
- buf.getRawData(message->body, length);
- message->destination = destination;
- message->routingKey = routingKey;
- message->replyExchange = DIR_EXCHANGE;
- message->replyKey = queueName;
-
- xmtQueue.push_back(message);
-}
-
-void BrokerProxyImpl::handleRcvMessage(Message& message)
-{
- Buffer inBuffer(message.body, message.length);
- uint8_t opcode;
- uint32_t sequence;
-
- while (Protocol::checkHeader(inBuffer, &opcode, &sequence))
- seqMgr.dispatch(opcode, sequence, inBuffer);
-}
-
-bool BrokerProxyImpl::getXmtMessage(Message& item) const
-{
- Mutex::ScopedLock _lock(lock);
- if (xmtQueue.empty())
- return false;
- item = xmtQueue.front()->copy();
- return true;
-}
-
-void BrokerProxyImpl::popXmt()
-{
- Mutex::ScopedLock _lock(lock);
- if (!xmtQueue.empty())
- xmtQueue.pop_front();
-}
-
-bool BrokerProxyImpl::getEvent(BrokerEvent& event) const
-{
- Mutex::ScopedLock _lock(lock);
- if (eventQueue.empty())
- return false;
- event = eventQueue.front()->copy();
- return true;
-}
-
-void BrokerProxyImpl::popEvent()
-{
- Mutex::ScopedLock _lock(lock);
- if (!eventQueue.empty())
- eventQueue.pop_front();
-}
-
-uint32_t BrokerProxyImpl::agentCount() const
-{
- Mutex::ScopedLock _lock(lock);
- return agentList.size();
-}
-
-const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const
-{
- Mutex::ScopedLock _lock(lock);
- for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin();
- iter != agentList.end(); iter++)
- if (idx-- == 0)
- return (*iter)->envelope;
- return 0;
-}
-
-void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent)
-{
- SequenceContext::Ptr queryContext(new QueryContext(*this, context));
- Mutex::ScopedLock _lock(lock);
- if (agent != 0) {
- sendGetRequestLH(queryContext, query, agent->impl);
- } else {
- // TODO (optimization) only send queries to agents that have the requested class+package
- for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin();
- iter != agentList.end(); iter++) {
- sendGetRequestLH(queryContext, query, (*iter).get());
- }
- }
-}
-
-void BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent)
-{
- stringstream key;
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t sequence(seqMgr.reserve(queryContext));
-
- Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
- query.impl->encode(outBuffer);
- key << "agent.1." << agent->agentBank;
- sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
- QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str());
-}
-
-void BrokerProxyImpl::addBinding(const string& exchange, const string& key)
-{
- eventQueue.push_back(eventBind(exchange, queueName, key));
-}
-
-BrokerEventImpl::Ptr BrokerProxyImpl::eventDeclareQueue(const string& queueName)
-{
- BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::DECLARE_QUEUE));
- event->name = queueName;
- return event;
-}
-
-BrokerEventImpl::Ptr BrokerProxyImpl::eventBind(const string& exchange, const string& queue, const string& key)
-{
- BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::BIND));
- event->name = queue;
- event->exchange = exchange;
- event->bindingKey = key;
-
- return event;
-}
-
-BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete()
-{
- BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::SETUP_COMPLETE));
- return event;
-}
-
-BrokerEventImpl::Ptr BrokerProxyImpl::eventStable()
-{
- BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
- return event;
-}
-
-BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponseImpl::Ptr response)
-{
- BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE));
- event->context = context;
- event->queryResponse = response;
- return event;
-}
-
-void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq)
-{
- brokerId.decode(inBuffer);
- QPID_LOG(trace, "RCVD BrokerResponse seq=" << seq << " brokerId=" << brokerId);
- Mutex::ScopedLock _lock(lock);
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t sequence(seqMgr.reserve());
- incOutstandingLH();
- Protocol::encodeHeader(outBuffer, Protocol::OP_PACKAGE_REQUEST, sequence);
- sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
- QPID_LOG(trace, "SENT PackageRequest seq=" << sequence);
-}
-
-void BrokerProxyImpl::handlePackageIndication(Buffer& inBuffer, uint32_t seq)
-{
- string package;
-
- inBuffer.getShortString(package);
- QPID_LOG(trace, "RCVD PackageIndication seq=" << seq << " package=" << package);
- console->learnPackage(package);
-
- Mutex::ScopedLock _lock(lock);
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t sequence(seqMgr.reserve());
- incOutstandingLH();
- Protocol::encodeHeader(outBuffer, Protocol::OP_CLASS_QUERY, sequence);
- outBuffer.putShortString(package);
- sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
- QPID_LOG(trace, "SENT ClassQuery seq=" << sequence << " package=" << package);
-}
-
-void BrokerProxyImpl::handleCommandComplete(Buffer& inBuffer, uint32_t seq)
-{
- string text;
- uint32_t code = inBuffer.getLong();
- inBuffer.getShortString(text);
- QPID_LOG(trace, "RCVD CommandComplete seq=" << seq << " code=" << code << " text=" << text);
-}
-
-void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq)
-{
- uint8_t kind = inBuffer.getOctet();
- SchemaClassKeyImpl classKey(inBuffer);
-
- QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey.str());
-
- if (!console->haveClass(classKey)) {
- Mutex::ScopedLock _lock(lock);
- incOutstandingLH();
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t sequence(seqMgr.reserve());
- Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence);
- classKey.encode(outBuffer);
- sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
- QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey.str());
- }
-}
-
-void BrokerProxyImpl::handleMethodResponse(Buffer& /*inBuffer*/, uint32_t /*seq*/)
-{
- // TODO
-}
-
-void BrokerProxyImpl::handleHeartbeatIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
-{
- // TODO
-}
-
-void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
-{
- // TODO
-}
-
-void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq)
-{
- SchemaObjectClassImpl::Ptr oClassPtr;
- SchemaEventClassImpl::Ptr eClassPtr;
- uint8_t kind = inBuffer.getOctet();
- const SchemaClassKeyImpl* key;
- if (kind == CLASS_OBJECT) {
- oClassPtr.reset(new SchemaObjectClassImpl(inBuffer));
- console->learnClass(oClassPtr);
- key = oClassPtr->getClassKey()->impl;
- QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->str());
-
- //
- // If we have just learned about the org.apache.qpid.broker:agent class, send a get
- // request for the current list of agents so we can have it on-hand before we declare
- // this session "stable".
- //
- if (key->getClassName() == AGENT_CLASS && key->getPackageName() == BROKER_PACKAGE) {
- Mutex::ScopedLock _lock(lock);
- incOutstandingLH();
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t sequence(seqMgr.reserve());
- Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
- FieldTable ft;
- ft.setString("_class", AGENT_CLASS);
- ft.setString("_package", BROKER_PACKAGE);
- ft.encode(outBuffer);
- sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY);
- QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY);
- }
- } else if (kind == CLASS_EVENT) {
- eClassPtr.reset(new SchemaEventClassImpl(inBuffer));
- console->learnClass(eClassPtr);
- key = eClassPtr->getClassKey()->impl;
- QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->str());
- }
- else {
- QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind);
- }
-}
-
-ObjectImpl::Ptr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat)
-{
- SchemaClassKeyImpl classKey(inBuffer);
- QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey.str());
-
- SchemaObjectClassImpl::Ptr schema = console->getSchema(classKey);
- if (schema.get() == 0) {
- QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey.str());
- return ObjectImpl::Ptr();
- }
-
- return ObjectImpl::Ptr(new ObjectImpl(schema->envelope, inBuffer, prop, stat, true));
-}
-
-void BrokerProxyImpl::incOutstandingLH()
-{
- requestsOutstanding++;
-}
-
-void BrokerProxyImpl::decOutstanding()
-{
- Mutex::ScopedLock _lock(lock);
- requestsOutstanding--;
- if (requestsOutstanding == 0 && !topicBound) {
- topicBound = true;
- for (vector<pair<string, string> >::const_iterator iter = console->bindingList.begin();
- iter != console->bindingList.end(); iter++) {
- string exchange(iter->first.empty() ? QMF_EXCHANGE : iter->first);
- string key(iter->second);
- eventQueue.push_back(eventBind(exchange, queueName, key));
- }
- eventQueue.push_back(eventStable());
- }
-}
-
-MethodResponseImpl::MethodResponseImpl(Buffer& buf) : envelope(new MethodResponse(this))
-{
- string text;
-
- status = buf.getLong();
- buf.getMediumString(text);
- exception.reset(new Value(TYPE_LSTR));
- exception->setString(text.c_str());
-
- // TODO: Parse schema-specific output arguments.
- arguments.reset(new Value(TYPE_MAP));
-}
-
-bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer)
-{
- bool completeContext = false;
- if (opcode == Protocol::OP_BROKER_RESPONSE) {
- broker.handleBrokerResponse(buffer, sequence);
- completeContext = true;
- }
- else if (opcode == Protocol::OP_COMMAND_COMPLETE) {
- broker.handleCommandComplete(buffer, sequence);
- completeContext = true;
- }
- else if (opcode == Protocol::OP_SCHEMA_RESPONSE) {
- broker.handleSchemaResponse(buffer, sequence);
- completeContext = true;
- }
- else if (opcode == Protocol::OP_PACKAGE_INDICATION)
- broker.handlePackageIndication(buffer, sequence);
- else if (opcode == Protocol::OP_CLASS_INDICATION)
- broker.handleClassIndication(buffer, sequence);
- else if (opcode == Protocol::OP_HEARTBEAT_INDICATION)
- broker.handleHeartbeatIndication(buffer, sequence);
- else if (opcode == Protocol::OP_EVENT_INDICATION)
- broker.handleEventIndication(buffer, sequence);
- else if (opcode == Protocol::OP_PROPERTY_INDICATION)
- broker.handleObjectIndication(buffer, sequence, true, false);
- else if (opcode == Protocol::OP_STATISTIC_INDICATION)
- broker.handleObjectIndication(buffer, sequence, false, true);
- else if (opcode == Protocol::OP_OBJECT_INDICATION)
- broker.handleObjectIndication(buffer, sequence, true, true);
- else {
- QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode);
- completeContext = true;
- }
-
- return completeContext;
-}
-
-void QueryContext::reserve()
-{
- Mutex::ScopedLock _lock(lock);
- requestsOutstanding++;
-}
-
-void QueryContext::release()
-{
- Mutex::ScopedLock _lock(lock);
- if (--requestsOutstanding == 0) {
- broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse));
- }
-}
-
-bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer)
-{
- bool completeContext = false;
- ObjectImpl::Ptr object;
-
- if (opcode == Protocol::OP_COMMAND_COMPLETE) {
- broker.handleCommandComplete(buffer, sequence);
- completeContext = true;
- }
- else if (opcode == Protocol::OP_OBJECT_INDICATION) {
- object = broker.handleObjectIndication(buffer, sequence, true, true);
- if (object.get() != 0)
- queryResponse->results.push_back(object);
- }
- else {
- QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
- completeContext = true;
- }
-
- return completeContext;
-}
-
-ConsoleEngineImpl::ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& s) :
- envelope(e), settings(s)
-{
- bindingList.push_back(pair<string, string>(string(), "schema.#"));
- if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
- bindingList.push_back(pair<string, string>(string(), "console.#"));
- } else {
- if (settings.rcvObjects && !settings.userBindings)
- bindingList.push_back(pair<string, string>(string(), "console.obj.#"));
- else
- bindingList.push_back(pair<string, string>(string(), "console.obj.*.*.org.apache.qpid.broker.agent"));
- if (settings.rcvEvents)
- bindingList.push_back(pair<string, string>(string(), "console.event.#"));
- if (settings.rcvHeartbeats)
- bindingList.push_back(pair<string, string>(string(), "console.heartbeat.#"));
- }
-}
-
-ConsoleEngineImpl::~ConsoleEngineImpl()
-{
- // This function intentionally left blank.
-}
-
-bool ConsoleEngineImpl::getEvent(ConsoleEvent& event) const
-{
- Mutex::ScopedLock _lock(lock);
- if (eventQueue.empty())
- return false;
- event = eventQueue.front()->copy();
- return true;
-}
-
-void ConsoleEngineImpl::popEvent()
-{
- Mutex::ScopedLock _lock(lock);
- if (!eventQueue.empty())
- eventQueue.pop_front();
-}
-
-void ConsoleEngineImpl::addConnection(BrokerProxy& broker, void* /*context*/)
-{
- Mutex::ScopedLock _lock(lock);
- brokerList.push_back(broker.impl);
-}
-
-void ConsoleEngineImpl::delConnection(BrokerProxy& broker)
-{
- Mutex::ScopedLock _lock(lock);
- for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
- iter != brokerList.end(); iter++)
- if (*iter == broker.impl) {
- brokerList.erase(iter);
- break;
- }
-}
-
-uint32_t ConsoleEngineImpl::packageCount() const
-{
- Mutex::ScopedLock _lock(lock);
- return packages.size();
-}
-
-const string& ConsoleEngineImpl::getPackageName(uint32_t idx) const
-{
- const static string empty;
-
- Mutex::ScopedLock _lock(lock);
- if (idx >= packages.size())
- return empty;
-
- PackageList::const_iterator iter = packages.begin();
- for (uint32_t i = 0; i < idx; i++) iter++;
- return iter->first;
-}
-
-uint32_t ConsoleEngineImpl::classCount(const char* packageName) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(packageName);
- if (pIter == packages.end())
- return 0;
-
- const ObjectClassList& oList = pIter->second.first;
- const EventClassList& eList = pIter->second.second;
-
- return oList.size() + eList.size();
-}
-
-const SchemaClassKey* ConsoleEngineImpl::getClass(const char* packageName, uint32_t idx) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(packageName);
- if (pIter == packages.end())
- return 0;
-
- const ObjectClassList& oList = pIter->second.first;
- const EventClassList& eList = pIter->second.second;
- uint32_t count = 0;
-
- for (ObjectClassList::const_iterator oIter = oList.begin();
- oIter != oList.end(); oIter++) {
- if (count == idx)
- return oIter->second->getClassKey();
- count++;
- }
-
- for (EventClassList::const_iterator eIter = eList.begin();
- eIter != eList.end(); eIter++) {
- if (count == idx)
- return eIter->second->getClassKey();
- count++;
- }
-
- return 0;
-}
-
-ClassKind ConsoleEngineImpl::getClassKind(const SchemaClassKey* key) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(key->getPackageName());
- if (pIter == packages.end())
- return CLASS_OBJECT;
-
- const EventClassList& eList = pIter->second.second;
- if (eList.find(key->impl) != eList.end())
- return CLASS_EVENT;
- return CLASS_OBJECT;
-}
-
-const SchemaObjectClass* ConsoleEngineImpl::getObjectClass(const SchemaClassKey* key) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(key->getPackageName());
- if (pIter == packages.end())
- return 0;
-
- const ObjectClassList& oList = pIter->second.first;
- ObjectClassList::const_iterator iter = oList.find(key->impl);
- if (iter == oList.end())
- return 0;
- return iter->second->envelope;
-}
-
-const SchemaEventClass* ConsoleEngineImpl::getEventClass(const SchemaClassKey* key) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(key->getPackageName());
- if (pIter == packages.end())
- return 0;
-
- const EventClassList& eList = pIter->second.second;
- EventClassList::const_iterator iter = eList.find(key->impl);
- if (iter == eList.end())
- return 0;
- return iter->second->envelope;
-}
-
-void ConsoleEngineImpl::bindPackage(const char* packageName)
-{
- stringstream key;
- key << "console.obj.*.*." << packageName << ".#";
- Mutex::ScopedLock _lock(lock);
- bindingList.push_back(pair<string, string>(string(), key.str()));
- for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
- iter != brokerList.end(); iter++)
- (*iter)->addBinding(QMF_EXCHANGE, key.str());
-}
-
-void ConsoleEngineImpl::bindClass(const SchemaClassKey* classKey)
-{
- stringstream key;
- key << "console.obj.*.*." << classKey->getPackageName() << "." << classKey->getClassName() << ".#";
- Mutex::ScopedLock _lock(lock);
- bindingList.push_back(pair<string, string>(string(), key.str()));
- for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
- iter != brokerList.end(); iter++)
- (*iter)->addBinding(QMF_EXCHANGE, key.str());
-}
-
-void ConsoleEngineImpl::bindClass(const char* packageName, const char* className)
-{
- stringstream key;
- key << "console.obj.*.*." << packageName << "." << className << ".#";
- Mutex::ScopedLock _lock(lock);
- bindingList.push_back(pair<string, string>(string(), key.str()));
- for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
- iter != brokerList.end(); iter++)
- (*iter)->addBinding(QMF_EXCHANGE, key.str());
-}
-
-/*
-void ConsoleEngineImpl::startSync(const Query& query, void* context, SyncQuery& sync)
-{
-}
-
-void ConsoleEngineImpl::touchSync(SyncQuery& sync)
-{
-}
-
-void ConsoleEngineImpl::endSync(SyncQuery& sync)
-{
-}
-*/
-
-void ConsoleEngineImpl::learnPackage(const string& packageName)
-{
- Mutex::ScopedLock _lock(lock);
- if (packages.find(packageName) == packages.end())
- packages.insert(pair<string, pair<ObjectClassList, EventClassList> >
- (packageName, pair<ObjectClassList, EventClassList>(ObjectClassList(), EventClassList())));
-}
-
-void ConsoleEngineImpl::learnClass(SchemaObjectClassImpl::Ptr cls)
-{
- Mutex::ScopedLock _lock(lock);
- const SchemaClassKey* key = cls->getClassKey();
- PackageList::iterator pIter = packages.find(key->getPackageName());
- if (pIter == packages.end())
- return;
-
- ObjectClassList& list = pIter->second.first;
- if (list.find(key->impl) == list.end())
- list[key->impl] = cls;
-}
-
-void ConsoleEngineImpl::learnClass(SchemaEventClassImpl::Ptr cls)
-{
- Mutex::ScopedLock _lock(lock);
- const SchemaClassKey* key = cls->getClassKey();
- PackageList::iterator pIter = packages.find(key->getPackageName());
- if (pIter == packages.end())
- return;
-
- EventClassList& list = pIter->second.second;
- if (list.find(key->impl) == list.end())
- list[key->impl] = cls;
-}
-
-bool ConsoleEngineImpl::haveClass(const SchemaClassKeyImpl& key) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(key.getPackageName());
- if (pIter == packages.end())
- return false;
-
- const ObjectClassList& oList = pIter->second.first;
- const EventClassList& eList = pIter->second.second;
-
- return oList.find(&key) != oList.end() || eList.find(&key) != eList.end();
-}
-
-SchemaObjectClassImpl::Ptr ConsoleEngineImpl::getSchema(const SchemaClassKeyImpl& key) const
-{
- Mutex::ScopedLock _lock(lock);
- PackageList::const_iterator pIter = packages.find(key.getPackageName());
- if (pIter == packages.end())
- return SchemaObjectClassImpl::Ptr();
-
- const ObjectClassList& oList = pIter->second.first;
- ObjectClassList::const_iterator iter = oList.find(&key);
- if (iter == oList.end())
- return SchemaObjectClassImpl::Ptr();
-
- return iter->second;
-}
-
-//==================================================================
-// Wrappers
-//==================================================================
-
-AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {}
-AgentProxy::~AgentProxy() { delete impl; }
-const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); }
-
-BrokerProxy::BrokerProxy(ConsoleEngine& console) : impl(new BrokerProxyImpl(this, console)) {}
-BrokerProxy::~BrokerProxy() { delete impl; }
-void BrokerProxy::sessionOpened(SessionHandle& sh) { impl->sessionOpened(sh); }
-void BrokerProxy::sessionClosed() { impl->sessionClosed(); }
-void BrokerProxy::startProtocol() { impl->startProtocol(); }
-void BrokerProxy::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
-bool BrokerProxy::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
-void BrokerProxy::popXmt() { impl->popXmt(); }
-bool BrokerProxy::getEvent(BrokerEvent& event) const { return impl->getEvent(event); }
-void BrokerProxy::popEvent() { impl->popEvent(); }
-uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); }
-const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); }
-void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); }
-
-MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {}
-MethodResponse::~MethodResponse() {}
-uint32_t MethodResponse::getStatus() const { return impl->getStatus(); }
-const Value* MethodResponse::getException() const { return impl->getException(); }
-const Value* MethodResponse::getArgs() const { return impl->getArgs(); }
-
-QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {}
-QueryResponse::~QueryResponse() {}
-uint32_t QueryResponse::getStatus() const { return impl->getStatus(); }
-const Value* QueryResponse::getException() const { return impl->getException(); }
-uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); }
-const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); }
-
-ConsoleEngine::ConsoleEngine(const ConsoleSettings& settings) : impl(new ConsoleEngineImpl(this, settings)) {}
-ConsoleEngine::~ConsoleEngine() { delete impl; }
-bool ConsoleEngine::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); }
-void ConsoleEngine::popEvent() { impl->popEvent(); }
-void ConsoleEngine::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); }
-void ConsoleEngine::delConnection(BrokerProxy& broker) { impl->delConnection(broker); }
-uint32_t ConsoleEngine::packageCount() const { return impl->packageCount(); }
-const char* ConsoleEngine::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); }
-uint32_t ConsoleEngine::classCount(const char* packageName) const { return impl->classCount(packageName); }
-const SchemaClassKey* ConsoleEngine::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); }
-ClassKind ConsoleEngine::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); }
-const SchemaObjectClass* ConsoleEngine::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); }
-const SchemaEventClass* ConsoleEngine::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); }
-void ConsoleEngine::bindPackage(const char* packageName) { impl->bindPackage(packageName); }
-void ConsoleEngine::bindClass(const SchemaClassKey* key) { impl->bindClass(key); }
-void ConsoleEngine::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); }
-//void ConsoleEngine::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); }
-//void ConsoleEngine::touchSync(SyncQuery& sync) { impl->touchSync(sync); }
-//void ConsoleEngine::endSync(SyncQuery& sync) { impl->endSync(sync); }
-
-
diff --git a/qpid/cpp/src/qmf/AgentEngine.cpp b/qpid/cpp/src/qmf/engine/Agent.cpp
index 9ea3be5907..c5d1bff2e0 100644
--- a/qpid/cpp/src/qmf/AgentEngine.cpp
+++ b/qpid/cpp/src/qmf/engine/Agent.cpp
@@ -17,15 +17,15 @@
* under the License.
*/
-#include "qmf/AgentEngine.h"
-#include "qmf/MessageImpl.h"
-#include "qmf/SchemaImpl.h"
-#include "qmf/Typecode.h"
-#include "qmf/ObjectImpl.h"
-#include "qmf/ObjectIdImpl.h"
-#include "qmf/QueryImpl.h"
-#include "qmf/ValueImpl.h"
-#include "qmf/Protocol.h"
+#include "qmf/engine/Agent.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/Uuid.h>
#include <qpid/framing/FieldTable.h>
@@ -40,13 +40,15 @@
#include <iostream>
#include <fstream>
#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid::framing;
using namespace qpid::sys;
namespace qmf {
+namespace engine {
struct AgentEventImpl {
typedef boost::shared_ptr<AgentEventImpl> Ptr;
@@ -61,7 +63,7 @@ namespace qmf {
boost::shared_ptr<Value> arguments;
string exchange;
string bindingKey;
- SchemaObjectClass* objectClass;
+ const SchemaObjectClass* objectClass;
AgentEventImpl(AgentEvent::EventKind k) :
kind(k), sequence(0), object(0), objectClass(0) {}
@@ -74,14 +76,14 @@ namespace qmf {
uint32_t sequence;
string exchange;
string key;
- SchemaMethodImpl* schemaMethod;
+ const SchemaMethod* schemaMethod;
AgentQueryContext() : schemaMethod(0) {}
};
- class AgentEngineImpl {
+ class AgentImpl : public boost::noncopyable {
public:
- AgentEngineImpl(char* label, bool internalStore);
- ~AgentEngineImpl();
+ AgentImpl(char* label, bool internalStore);
+ ~AgentImpl();
void setStoreDir(const char* path);
void setTransferDir(const char* path);
@@ -163,8 +165,8 @@ namespace qmf {
}
};
- typedef map<AgentClassKey, SchemaObjectClassImpl*, AgentClassKeyComp> ObjectClassMap;
- typedef map<AgentClassKey, SchemaEventClassImpl*, AgentClassKeyComp> EventClassMap;
+ typedef map<AgentClassKey, SchemaObjectClass*, AgentClassKeyComp> ObjectClassMap;
+ typedef map<AgentClassKey, SchemaEventClass*, AgentClassKeyComp> EventClassMap;
struct ClassMaps {
ObjectClassMap objectClasses;
@@ -180,7 +182,7 @@ namespace qmf {
boost::shared_ptr<ObjectId> oid);
AgentEventImpl::Ptr eventMethod(uint32_t num, const string& userId, const string& method,
boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
- SchemaObjectClass* objectClass);
+ const SchemaObjectClass* objectClass);
void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
void sendPackageIndicationLH(const string& packageName);
@@ -198,10 +200,11 @@ namespace qmf {
void handleConsoleAddedIndication();
};
}
+}
-const char* AgentEngineImpl::QMF_EXCHANGE = "qpid.management";
-const char* AgentEngineImpl::DIR_EXCHANGE = "amq.direct";
-const char* AgentEngineImpl::BROKER_KEY = "broker";
+const char* AgentImpl::QMF_EXCHANGE = "qpid.management";
+const char* AgentImpl::DIR_EXCHANGE = "amq.direct";
+const char* AgentImpl::BROKER_KEY = "broker";
#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
@@ -227,7 +230,7 @@ AgentEvent AgentEventImpl::copy()
return item;
}
-AgentEngineImpl::AgentEngineImpl(char* _label, bool i) :
+AgentImpl::AgentImpl(char* _label, bool i) :
label(_label), queueName("qmfa-"), internalStore(i), nextTransientId(1),
requestedBrokerBank(0), requestedAgentBank(0),
assignedBrokerBank(0), assignedAgentBank(0),
@@ -236,11 +239,11 @@ AgentEngineImpl::AgentEngineImpl(char* _label, bool i) :
queueName += label;
}
-AgentEngineImpl::~AgentEngineImpl()
+AgentImpl::~AgentImpl()
{
}
-void AgentEngineImpl::setStoreDir(const char* path)
+void AgentImpl::setStoreDir(const char* path)
{
Mutex::ScopedLock _lock(lock);
if (path)
@@ -249,7 +252,7 @@ void AgentEngineImpl::setStoreDir(const char* path)
storeDir.clear();
}
-void AgentEngineImpl::setTransferDir(const char* path)
+void AgentImpl::setTransferDir(const char* path)
{
Mutex::ScopedLock _lock(lock);
if (path)
@@ -258,7 +261,7 @@ void AgentEngineImpl::setTransferDir(const char* path)
transferDir.clear();
}
-void AgentEngineImpl::handleRcvMessage(Message& message)
+void AgentImpl::handleRcvMessage(Message& message)
{
Buffer inBuffer(message.body, message.length);
uint8_t opcode;
@@ -274,13 +277,13 @@ void AgentEngineImpl::handleRcvMessage(Message& message)
else if (opcode == Protocol::OP_GET_QUERY) handleGetQuery(inBuffer, sequence, replyToKey, userId);
else if (opcode == Protocol::OP_METHOD_REQUEST) handleMethodRequest(inBuffer, sequence, replyToKey, userId);
else {
- QPID_LOG(error, "AgentEngineImpl::handleRcvMessage invalid opcode=" << opcode);
+ QPID_LOG(error, "AgentImpl::handleRcvMessage invalid opcode=" << opcode);
break;
}
}
}
-bool AgentEngineImpl::getXmtMessage(Message& item) const
+bool AgentImpl::getXmtMessage(Message& item) const
{
Mutex::ScopedLock _lock(lock);
if (xmtQueue.empty())
@@ -289,14 +292,14 @@ bool AgentEngineImpl::getXmtMessage(Message& item) const
return true;
}
-void AgentEngineImpl::popXmt()
+void AgentImpl::popXmt()
{
Mutex::ScopedLock _lock(lock);
if (!xmtQueue.empty())
xmtQueue.pop_front();
}
-bool AgentEngineImpl::getEvent(AgentEvent& event) const
+bool AgentImpl::getEvent(AgentEvent& event) const
{
Mutex::ScopedLock _lock(lock);
if (eventQueue.empty())
@@ -305,14 +308,14 @@ bool AgentEngineImpl::getEvent(AgentEvent& event) const
return true;
}
-void AgentEngineImpl::popEvent()
+void AgentImpl::popEvent()
{
Mutex::ScopedLock _lock(lock);
if (!eventQueue.empty())
eventQueue.pop_front();
}
-void AgentEngineImpl::newSession()
+void AgentImpl::newSession()
{
Mutex::ScopedLock _lock(lock);
eventQueue.clear();
@@ -322,7 +325,7 @@ void AgentEngineImpl::newSession()
eventQueue.push_back(eventSetupComplete());
}
-void AgentEngineImpl::startProtocol()
+void AgentImpl::startProtocol()
{
Mutex::ScopedLock _lock(lock);
char rawbuffer[512];
@@ -338,7 +341,7 @@ void AgentEngineImpl::startProtocol()
" reqAgent=" << requestedAgentBank);
}
-void AgentEngineImpl::heartbeat()
+void AgentImpl::heartbeat()
{
Mutex::ScopedLock _lock(lock);
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
@@ -351,7 +354,7 @@ void AgentEngineImpl::heartbeat()
QPID_LOG(trace, "SENT HeartbeatIndication");
}
-void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
+void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
const Value& argMap)
{
Mutex::ScopedLock _lock(lock);
@@ -366,15 +369,15 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t
buffer.putLong(status);
buffer.putMediumString(text);
if (status == 0) {
- for (vector<SchemaArgumentImpl*>::const_iterator aIter = context->schemaMethod->arguments.begin();
- aIter != context->schemaMethod->arguments.end(); aIter++) {
- const SchemaArgumentImpl* schemaArg = *aIter;
- if (schemaArg->dir == DIR_OUT || schemaArg->dir == DIR_IN_OUT) {
- if (argMap.keyInMap(schemaArg->name.c_str())) {
- const Value* val = argMap.byKey(schemaArg->name.c_str());
+ for (vector<const SchemaArgument*>::const_iterator aIter = context->schemaMethod->impl->arguments.begin();
+ aIter != context->schemaMethod->impl->arguments.end(); aIter++) {
+ const SchemaArgument* schemaArg = *aIter;
+ if (schemaArg->getDirection() == DIR_OUT || schemaArg->getDirection() == DIR_IN_OUT) {
+ if (argMap.keyInMap(schemaArg->getName())) {
+ const Value* val = argMap.byKey(schemaArg->getName());
val->impl->encode(buffer);
} else {
- Value val(schemaArg->typecode);
+ Value val(schemaArg->getType());
val.impl->encode(buffer);
}
}
@@ -384,7 +387,7 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t
QPID_LOG(trace, "SENT MethodResponse seq=" << context->sequence << " status=" << status << " text=" << text);
}
-void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
+void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -406,7 +409,7 @@ void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop
QPID_LOG(trace, "SENT ContentIndication seq=" << context->sequence);
}
-void AgentEngineImpl::queryComplete(uint32_t sequence)
+void AgentImpl::queryComplete(uint32_t sequence)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -418,69 +421,67 @@ void AgentEngineImpl::queryComplete(uint32_t sequence)
sendCommandCompleteLH(context->exchange, context->key, context->sequence, 0, "OK");
}
-void AgentEngineImpl::registerClass(SchemaObjectClass* cls)
+void AgentImpl::registerClass(SchemaObjectClass* cls)
{
Mutex::ScopedLock _lock(lock);
- SchemaObjectClassImpl* impl = cls->impl;
- map<string, ClassMaps>::iterator iter = packages.find(impl->package);
+ map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName());
if (iter == packages.end()) {
- packages[impl->package] = ClassMaps();
- iter = packages.find(impl->getClassKey()->getPackageName());
+ packages[cls->getClassKey()->getPackageName()] = ClassMaps();
+ iter = packages.find(cls->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
- iter->second.objectClasses[key] = impl;
+ AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash());
+ iter->second.objectClasses[key] = cls;
// TODO: Indicate this schema if connected.
}
-void AgentEngineImpl::registerClass(SchemaEventClass* cls)
+void AgentImpl::registerClass(SchemaEventClass* cls)
{
Mutex::ScopedLock _lock(lock);
- SchemaEventClassImpl* impl = cls->impl;
- map<string, ClassMaps>::iterator iter = packages.find(impl->package);
+ map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName());
if (iter == packages.end()) {
- packages[impl->package] = ClassMaps();
- iter = packages.find(impl->getClassKey()->getPackageName());
+ packages[cls->getClassKey()->getPackageName()] = ClassMaps();
+ iter = packages.find(cls->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
- iter->second.eventClasses[key] = impl;
+ AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash());
+ iter->second.eventClasses[key] = cls;
// TODO: Indicate this schema if connected.
}
-const ObjectId* AgentEngineImpl::addObject(Object&, uint64_t)
+const ObjectId* AgentImpl::addObject(Object&, uint64_t)
{
Mutex::ScopedLock _lock(lock);
return 0;
}
-const ObjectId* AgentEngineImpl::allocObjectId(uint64_t persistId)
+const ObjectId* AgentImpl::allocObjectId(uint64_t persistId)
{
Mutex::ScopedLock _lock(lock);
uint16_t sequence = persistId ? 0 : bootSequence;
uint64_t objectNum = persistId ? persistId : nextObjectId++;
- ObjectIdImpl* oid = new ObjectIdImpl(&attachment, 0, sequence, objectNum);
- return oid->envelope;
+ ObjectId* oid = ObjectIdImpl::factory(&attachment, 0, sequence, objectNum);
+ return oid;
}
-const ObjectId* AgentEngineImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
+const ObjectId* AgentImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
{
return allocObjectId(((uint64_t) persistIdHi) << 32 | (uint64_t) persistIdLo);
}
-void AgentEngineImpl::raiseEvent(Event&)
+void AgentImpl::raiseEvent(Event&)
{
Mutex::ScopedLock _lock(lock);
}
-AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name)
+AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE));
event->name = name;
@@ -488,7 +489,7 @@ AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name)
return event;
}
-AgentEventImpl::Ptr AgentEngineImpl::eventBind(const string& exchange, const string& queue,
+AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& queue,
const string& key)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::BIND));
@@ -499,13 +500,13 @@ AgentEventImpl::Ptr AgentEngineImpl::eventBind(const string& exchange, const str
return event;
}
-AgentEventImpl::Ptr AgentEngineImpl::eventSetupComplete()
+AgentEventImpl::Ptr AgentImpl::eventSetupComplete()
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::SETUP_COMPLETE));
return event;
}
-AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& userId, const string& package,
+AgentEventImpl::Ptr AgentImpl::eventQuery(uint32_t num, const string& userId, const string& package,
const string& cls, boost::shared_ptr<ObjectId> oid)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::GET_QUERY));
@@ -518,9 +519,9 @@ AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& user
return event;
}
-AgentEventImpl::Ptr AgentEngineImpl::eventMethod(uint32_t num, const string& userId, const string& method,
+AgentEventImpl::Ptr AgentImpl::eventMethod(uint32_t num, const string& userId, const string& method,
boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
- SchemaObjectClass* objectClass)
+ const SchemaObjectClass* objectClass)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::METHOD_CALL));
event->sequence = num;
@@ -532,7 +533,7 @@ AgentEventImpl::Ptr AgentEngineImpl::eventMethod(uint32_t num, const string& use
return event;
}
-void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+void AgentImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
{
uint32_t length = buf.getPosition();
MessageImpl::Ptr message(new MessageImpl);
@@ -547,7 +548,7 @@ void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const
xmtQueue.push_back(message);
}
-void AgentEngineImpl::sendPackageIndicationLH(const string& packageName)
+void AgentImpl::sendPackageIndicationLH(const string& packageName)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION);
@@ -556,7 +557,7 @@ void AgentEngineImpl::sendPackageIndicationLH(const string& packageName)
QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName);
}
-void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key)
+void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION);
@@ -568,7 +569,7 @@ void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packag
QPID_LOG(trace, "SENT ClassIndication: package_name=" << packageName << " class_name=" << key.name);
}
-void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey,
+void AgentImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey,
uint32_t sequence, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
@@ -579,7 +580,7 @@ void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string
QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text);
}
-void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
+void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence);
@@ -605,7 +606,7 @@ void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, ui
QPID_LOG(trace, "SENT MethodResponse: errorCode=" << code << " text=" << fulltext);
}
-void AgentEngineImpl::handleAttachResponse(Buffer& inBuffer)
+void AgentImpl::handleAttachResponse(Buffer& inBuffer)
{
Mutex::ScopedLock _lock(lock);
@@ -652,17 +653,17 @@ void AgentEngineImpl::handleAttachResponse(Buffer& inBuffer)
}
}
-void AgentEngineImpl::handlePackageRequest(Buffer&)
+void AgentImpl::handlePackageRequest(Buffer&)
{
Mutex::ScopedLock _lock(lock);
}
-void AgentEngineImpl::handleClassQuery(Buffer&)
+void AgentImpl::handleClassQuery(Buffer&)
{
Mutex::ScopedLock _lock(lock);
}
-void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
+void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
const string& replyExchange, const string& replyKey)
{
Mutex::ScopedLock _lock(lock);
@@ -688,10 +689,10 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
ClassMaps cMap = pIter->second;
ObjectClassMap::iterator ocIter = cMap.objectClasses.find(key);
if (ocIter != cMap.objectClasses.end()) {
- SchemaObjectClassImpl* oImpl = ocIter->second;
+ SchemaObjectClass* oImpl = ocIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
- oImpl->encode(buffer);
+ oImpl->impl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name);
return;
@@ -699,10 +700,10 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
EventClassMap::iterator ecIter = cMap.eventClasses.find(key);
if (ecIter != cMap.eventClasses.end()) {
- SchemaEventClassImpl* eImpl = ecIter->second;
+ SchemaEventClass* eImpl = ecIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
- eImpl->encode(buffer);
+ eImpl->impl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name);
return;
@@ -711,7 +712,7 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
sendCommandCompleteLH(rExchange, rKey, sequence, 1, "class not found");
}
-void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId)
+void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId)
{
Mutex::ScopedLock _lock(lock);
FieldTable ft;
@@ -763,13 +764,12 @@ void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const
eventQueue.push_back(eventQuery(contextNum, userId, pname, cname, oid));
}
-void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId)
+void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId)
{
Mutex::ScopedLock _lock(lock);
string pname;
string method;
- ObjectIdImpl* oidImpl = new ObjectIdImpl(buffer);
- boost::shared_ptr<ObjectId> oid(oidImpl->envelope);
+ boost::shared_ptr<ObjectId> oid(ObjectIdImpl::factory(buffer));
buffer.getShortString(pname);
AgentClassKey classKey(buffer);
buffer.getShortString(method);
@@ -788,29 +788,29 @@ void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, con
return;
}
- const SchemaObjectClassImpl* schema = cIter->second;
- vector<SchemaMethodImpl*>::const_iterator mIter = schema->methods.begin();
- for (; mIter != schema->methods.end(); mIter++) {
- if ((*mIter)->name == method)
+ const SchemaObjectClass* schema = cIter->second;
+ vector<const SchemaMethod*>::const_iterator mIter = schema->impl->methods.begin();
+ for (; mIter != schema->impl->methods.end(); mIter++) {
+ if ((*mIter)->getName() == method)
break;
}
- if (mIter == schema->methods.end()) {
+ if (mIter == schema->impl->methods.end()) {
sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_METHOD, method);
return;
}
- SchemaMethodImpl* schemaMethod = *mIter;
+ const SchemaMethod* schemaMethod = *mIter;
boost::shared_ptr<Value> argMap(new Value(TYPE_MAP));
- ValueImpl* value;
- for (vector<SchemaArgumentImpl*>::const_iterator aIter = schemaMethod->arguments.begin();
- aIter != schemaMethod->arguments.end(); aIter++) {
- const SchemaArgumentImpl* schemaArg = *aIter;
- if (schemaArg->dir == DIR_IN || schemaArg->dir == DIR_IN_OUT)
- value = new ValueImpl(schemaArg->typecode, buffer);
+ Value* value;
+ for (vector<const SchemaArgument*>::const_iterator aIter = schemaMethod->impl->arguments.begin();
+ aIter != schemaMethod->impl->arguments.end(); aIter++) {
+ const SchemaArgument* schemaArg = *aIter;
+ if (schemaArg->getDirection() == DIR_IN || schemaArg->getDirection() == DIR_IN_OUT)
+ value = ValueImpl::factory(schemaArg->getType(), buffer);
else
- value = new ValueImpl(schemaArg->typecode);
- argMap->insert(schemaArg->name.c_str(), value->envelope);
+ value = ValueImpl::factory(schemaArg->getType());
+ argMap->insert(schemaArg->getName(), value);
}
AgentQueryContext::Ptr context(new AgentQueryContext);
@@ -821,10 +821,10 @@ void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, con
context->schemaMethod = schemaMethod;
contextMap[contextNum] = context;
- eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema->envelope));
+ eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema));
}
-void AgentEngineImpl::handleConsoleAddedIndication()
+void AgentImpl::handleConsoleAddedIndication()
{
Mutex::ScopedLock _lock(lock);
}
@@ -833,25 +833,25 @@ void AgentEngineImpl::handleConsoleAddedIndication()
// Wrappers
//==================================================================
-AgentEngine::AgentEngine(char* label, bool internalStore) { impl = new AgentEngineImpl(label, internalStore); }
-AgentEngine::~AgentEngine() { delete impl; }
-void AgentEngine::setStoreDir(const char* path) { impl->setStoreDir(path); }
-void AgentEngine::setTransferDir(const char* path) { impl->setTransferDir(path); }
-void AgentEngine::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
-bool AgentEngine::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
-void AgentEngine::popXmt() { impl->popXmt(); }
-bool AgentEngine::getEvent(AgentEvent& event) const { return impl->getEvent(event); }
-void AgentEngine::popEvent() { impl->popEvent(); }
-void AgentEngine::newSession() { impl->newSession(); }
-void AgentEngine::startProtocol() { impl->startProtocol(); }
-void AgentEngine::heartbeat() { impl->heartbeat(); }
-void AgentEngine::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments) { impl->methodResponse(sequence, status, text, arguments); }
-void AgentEngine::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { impl->queryResponse(sequence, object, prop, stat); }
-void AgentEngine::queryComplete(uint32_t sequence) { impl->queryComplete(sequence); }
-void AgentEngine::registerClass(SchemaObjectClass* cls) { impl->registerClass(cls); }
-void AgentEngine::registerClass(SchemaEventClass* cls) { impl->registerClass(cls); }
-const ObjectId* AgentEngine::addObject(Object& obj, uint64_t persistId) { return impl->addObject(obj, persistId); }
-const ObjectId* AgentEngine::allocObjectId(uint64_t persistId) { return impl->allocObjectId(persistId); }
-const ObjectId* AgentEngine::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return impl->allocObjectId(persistIdLo, persistIdHi); }
-void AgentEngine::raiseEvent(Event& event) { impl->raiseEvent(event); }
+Agent::Agent(char* label, bool internalStore) { impl = new AgentImpl(label, internalStore); }
+Agent::~Agent() { delete impl; }
+void Agent::setStoreDir(const char* path) { impl->setStoreDir(path); }
+void Agent::setTransferDir(const char* path) { impl->setTransferDir(path); }
+void Agent::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool Agent::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void Agent::popXmt() { impl->popXmt(); }
+bool Agent::getEvent(AgentEvent& event) const { return impl->getEvent(event); }
+void Agent::popEvent() { impl->popEvent(); }
+void Agent::newSession() { impl->newSession(); }
+void Agent::startProtocol() { impl->startProtocol(); }
+void Agent::heartbeat() { impl->heartbeat(); }
+void Agent::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments) { impl->methodResponse(sequence, status, text, arguments); }
+void Agent::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { impl->queryResponse(sequence, object, prop, stat); }
+void Agent::queryComplete(uint32_t sequence) { impl->queryComplete(sequence); }
+void Agent::registerClass(SchemaObjectClass* cls) { impl->registerClass(cls); }
+void Agent::registerClass(SchemaEventClass* cls) { impl->registerClass(cls); }
+const ObjectId* Agent::addObject(Object& obj, uint64_t persistId) { return impl->addObject(obj, persistId); }
+const ObjectId* Agent::allocObjectId(uint64_t persistId) { return impl->allocObjectId(persistId); }
+const ObjectId* Agent::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return impl->allocObjectId(persistIdLo, persistIdHi); }
+void Agent::raiseEvent(Event& event) { impl->raiseEvent(event); }
diff --git a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp
new file mode 100644
index 0000000000..1a2b3e6555
--- /dev/null
+++ b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp
@@ -0,0 +1,763 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/BrokerProxyImpl.h"
+#include "qmf/engine/ConsoleImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qpid/Address.h"
+#include "qpid/sys/SystemInfo.h"
+#include <qpid/log/Statement.h>
+#include <qpid/StringUtils.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+ const char* DIR_EXCHANGE = "amq.direct";
+ const char* BROKER_KEY = "broker";
+ const char* BROKER_PACKAGE = "org.apache.qpid.broker";
+ const char* AGENT_CLASS = "agent";
+ const char* BROKER_AGENT_KEY = "agent.1.0";
+}
+
+const Object* QueryResponseImpl::getObject(uint32_t idx) const
+{
+ vector<ObjectPtr>::const_iterator iter = results.begin();
+
+ while (idx > 0) {
+ if (iter == results.end())
+ return 0;
+ iter++;
+ idx--;
+ }
+
+ return iter->get();
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+BrokerEvent BrokerEventImpl::copy()
+{
+ BrokerEvent item;
+
+ ::memset(&item, 0, sizeof(BrokerEvent));
+ item.kind = kind;
+
+ STRING_REF(name);
+ STRING_REF(exchange);
+ STRING_REF(bindingKey);
+ item.context = context;
+ item.queryResponse = queryResponse.get();
+ item.methodResponse = methodResponse.get();
+
+ return item;
+}
+
+BrokerProxyImpl::BrokerProxyImpl(BrokerProxy& pub, Console& _console) : publicObject(pub), console(_console)
+{
+ stringstream qn;
+ qpid::TcpAddress addr;
+
+ SystemInfo::getLocalHostname(addr);
+ qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId();
+ queueName = qn.str();
+
+ seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this)));
+}
+
+void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+ eventQueue.push_back(eventDeclareQueue(queueName));
+ eventQueue.push_back(eventBind(DIR_EXCHANGE, queueName, queueName));
+ eventQueue.push_back(eventSetupComplete());
+
+ // TODO: Store session handle
+}
+
+void BrokerProxyImpl::sessionClosed()
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+}
+
+void BrokerProxyImpl::startProtocol()
+{
+ AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, 0, "Agent embedded in broker"));
+ {
+ Mutex::ScopedLock _lock(lock);
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ agentList[0] = agent;
+
+ requestsOutstanding = 1;
+ topicBound = false;
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence);
+ }
+
+ console.impl->eventAgentAdded(agent);
+}
+
+void BrokerProxyImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+{
+ uint32_t length = buf.getPosition();
+ MessageImpl::Ptr message(new MessageImpl);
+
+ buf.reset();
+ buf.getRawData(message->body, length);
+ message->destination = destination;
+ message->routingKey = routingKey;
+ message->replyExchange = DIR_EXCHANGE;
+ message->replyKey = queueName;
+
+ xmtQueue.push_back(message);
+}
+
+void BrokerProxyImpl::handleRcvMessage(Message& message)
+{
+ Buffer inBuffer(message.body, message.length);
+ uint8_t opcode;
+ uint32_t sequence;
+
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence))
+ seqMgr.dispatch(opcode, sequence, message.routingKey ? string(message.routingKey) : string(), inBuffer);
+}
+
+bool BrokerProxyImpl::getXmtMessage(Message& item) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (xmtQueue.empty())
+ return false;
+ item = xmtQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popXmt()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!xmtQueue.empty())
+ xmtQueue.pop_front();
+}
+
+bool BrokerProxyImpl::getEvent(BrokerEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+uint32_t BrokerProxyImpl::agentCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return agentList.size();
+}
+
+const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++)
+ if (idx-- == 0)
+ return iter->second.get();
+ return 0;
+}
+
+void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent)
+{
+ SequenceContext::Ptr queryContext(new QueryContext(*this, context));
+ Mutex::ScopedLock _lock(lock);
+ if (agent != 0) {
+ sendGetRequestLH(queryContext, query, agent);
+ } else {
+ // TODO (optimization) only send queries to agents that have the requested class+package
+ for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++) {
+ sendGetRequestLH(queryContext, query, iter->second.get());
+ }
+ }
+}
+
+void BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent)
+{
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(queryContext));
+ agent->impl->addSequence(sequence);
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ query.impl->encode(outBuffer);
+ key << "agent.1." << agent->impl->agentBank;
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str());
+}
+
+string BrokerProxyImpl::encodeMethodArguments(const SchemaMethod* schema, const Value* argmap, Buffer& buffer)
+{
+ int argCount = schema->getArgumentCount();
+
+ if (argmap == 0 || !argmap->isMap())
+ return string("Arguments must be in a map value");
+
+ for (int aIdx = 0; aIdx < argCount; aIdx++) {
+ const SchemaArgument* arg(schema->getArgument(aIdx));
+ if (arg->getDirection() == DIR_IN || arg->getDirection() == DIR_IN_OUT) {
+ if (argmap->keyInMap(arg->getName())) {
+ const Value* argVal(argmap->byKey(arg->getName()));
+ if (argVal->getType() != arg->getType())
+ return string("Argument is the wrong type: ") + arg->getName();
+ argVal->impl->encode(buffer);
+ } else {
+ Value defaultValue(arg->getType());
+ defaultValue.impl->encode(buffer);
+ }
+ }
+ }
+
+ return string();
+}
+
+void BrokerProxyImpl::sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls,
+ const string& methodName, const Value* args, void* userContext)
+{
+ int methodCount = cls->getMethodCount();
+ int idx;
+ for (idx = 0; idx < methodCount; idx++) {
+ const SchemaMethod* method = cls->getMethod(idx);
+ if (string(method->getName()) == methodName) {
+ Mutex::ScopedLock _lock(lock);
+ SequenceContext::Ptr methodContext(new MethodContext(*this, userContext, method));
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(methodContext));
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_METHOD_REQUEST, sequence);
+ oid->impl->encode(outBuffer);
+ cls->getClassKey()->impl->encode(outBuffer);
+ outBuffer.putShortString(methodName);
+
+ string argErrorString = encodeMethodArguments(method, args, outBuffer);
+ if (argErrorString.empty()) {
+ key << "agent.1." << oid->impl->getAgentBank();
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT MethodRequest seq=" << sequence << " method=" << methodName << " key=" << key.str());
+ } else {
+ MethodResponsePtr argError(MethodResponseImpl::factory(1, argErrorString));
+ eventQueue.push_back(eventMethodResponse(userContext, argError));
+ }
+ return;
+ }
+ }
+
+ MethodResponsePtr error(MethodResponseImpl::factory(1, string("Unknown method: ") + methodName));
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventMethodResponse(userContext, error));
+}
+
+void BrokerProxyImpl::addBinding(const string& exchange, const string& key)
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventDeclareQueue(const string& queueName)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::DECLARE_QUEUE));
+ event->name = queueName;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventBind(const string& exchange, const string& queue, const string& key)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::BIND));
+ event->name = queue;
+ event->exchange = exchange;
+ event->bindingKey = key;
+
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::SETUP_COMPLETE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventStable()
+{
+ QPID_LOG(trace, "Console Link to Broker Stable");
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponsePtr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE));
+ event->context = context;
+ event->queryResponse = response;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventMethodResponse(void* context, MethodResponsePtr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::METHOD_RESPONSE));
+ event->context = context;
+ event->methodResponse = response;
+ return event;
+}
+
+void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq)
+{
+ brokerId.decode(inBuffer);
+ QPID_LOG(trace, "RCVD BrokerResponse seq=" << seq << " brokerId=" << brokerId);
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_PACKAGE_REQUEST, sequence);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT PackageRequest seq=" << sequence);
+}
+
+void BrokerProxyImpl::handlePackageIndication(Buffer& inBuffer, uint32_t seq)
+{
+ string package;
+
+ inBuffer.getShortString(package);
+ QPID_LOG(trace, "RCVD PackageIndication seq=" << seq << " package=" << package);
+ console.impl->learnPackage(package);
+
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_CLASS_QUERY, sequence);
+ outBuffer.putShortString(package);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT ClassQuery seq=" << sequence << " package=" << package);
+}
+
+void BrokerProxyImpl::handleCommandComplete(Buffer& inBuffer, uint32_t seq)
+{
+ string text;
+ uint32_t code = inBuffer.getLong();
+ inBuffer.getShortString(text);
+ QPID_LOG(trace, "RCVD CommandComplete seq=" << seq << " code=" << code << " text=" << text);
+}
+
+void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq)
+{
+ uint8_t kind = inBuffer.getOctet();
+ auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer));
+
+ QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey->impl->str());
+
+ if (!console.impl->haveClass(classKey.get())) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence);
+ classKey->impl->encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey->impl->str());
+ }
+}
+
+MethodResponsePtr BrokerProxyImpl::handleMethodResponse(Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema)
+{
+ MethodResponsePtr response(MethodResponseImpl::factory(inBuffer, schema));
+
+ QPID_LOG(trace, "RCVD MethodResponse seq=" << seq << " status=" << response->getStatus() << " text=" <<
+ response->getException()->asString());
+
+ return response;
+}
+
+void BrokerProxyImpl::handleHeartbeatIndication(Buffer& inBuffer, uint32_t seq, const string& routingKey)
+{
+ vector<string> tokens = qpid::split(routingKey, ".");
+ uint32_t agentBank;
+ uint64_t timestamp;
+
+ if (routingKey.empty() || tokens.size() != 4)
+ agentBank = 0;
+ else
+ agentBank = ::atoi(tokens[3].c_str());
+
+ timestamp = inBuffer.getLongLong();
+ map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank);
+ if (iter != agentList.end()) {
+ console.impl->eventAgentHeartbeat(iter->second, timestamp);
+ }
+ QPID_LOG(trace, "RCVD HeartbeatIndication seq=" << seq << " agentBank=" << agentBank);
+}
+
+void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq)
+{
+ SchemaObjectClass* oClassPtr;
+ SchemaEventClass* eClassPtr;
+ uint8_t kind = inBuffer.getOctet();
+ const SchemaClassKey* key;
+ if (kind == CLASS_OBJECT) {
+ oClassPtr = SchemaObjectClassImpl::factory(inBuffer);
+ console.impl->learnClass(oClassPtr);
+ key = oClassPtr->getClassKey();
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->impl->str());
+
+ //
+ // If we have just learned about the org.apache.qpid.broker:agent class, send a get
+ // request for the current list of agents so we can have it on-hand before we declare
+ // this session "stable".
+ //
+ if (key->impl->getClassName() == AGENT_CLASS && key->impl->getPackageName() == BROKER_PACKAGE) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ FieldTable ft;
+ ft.setString("_class", AGENT_CLASS);
+ ft.setString("_package", BROKER_PACKAGE);
+ ft.encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY);
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY);
+ }
+ } else if (kind == CLASS_EVENT) {
+ eClassPtr = SchemaEventClassImpl::factory(inBuffer);
+ console.impl->learnClass(eClassPtr);
+ key = eClassPtr->getClassKey();
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->impl->str());
+ }
+ else {
+ QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind);
+ }
+}
+
+ObjectPtr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat)
+{
+ auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer));
+ QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey->impl->str());
+
+ SchemaObjectClass* schema = console.impl->getSchema(classKey.get());
+ if (schema == 0) {
+ QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey->impl->str());
+ return ObjectPtr();
+ }
+
+ ObjectPtr optr(ObjectImpl::factory(schema, this, inBuffer, prop, stat, true));
+ if (prop && classKey->impl->getPackageName() == BROKER_PACKAGE && classKey->impl->getClassName() == AGENT_CLASS) {
+ //
+ // We've intercepted information about a remote agent... update the agent list accordingly
+ //
+ updateAgentList(optr);
+ }
+ return optr;
+}
+
+void BrokerProxyImpl::updateAgentList(ObjectPtr obj)
+{
+ Value* value = obj->getValue("agentBank");
+ Mutex::ScopedLock _lock(lock);
+ if (value != 0 && value->isUint()) {
+ uint32_t agentBank = value->asUint();
+ if (obj->isDeleted()) {
+ map<uint32_t, AgentProxyPtr>::iterator iter = agentList.find(agentBank);
+ if (iter != agentList.end()) {
+ AgentProxyPtr agent(iter->second);
+ console.impl->eventAgentDeleted(agent);
+ agentList.erase(agentBank);
+ QPID_LOG(trace, "Agent at bank " << agentBank << " removed from agent list");
+
+ //
+ // Release all sequence numbers for requests in-flight to this agent.
+ // Since the agent is no longer connected, these requests would not
+ // otherwise complete.
+ //
+ agent->impl->releaseInFlight(seqMgr);
+ }
+ } else {
+ Value* str = obj->getValue("label");
+ string label;
+ if (str != 0 && str->isString())
+ label = str->asString();
+ map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank);
+ if (iter == agentList.end()) {
+ AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, agentBank, label));
+ agentList[agentBank] = agent;
+ console.impl->eventAgentAdded(agent);
+ QPID_LOG(trace, "Agent '" << label << "' found at bank " << agentBank);
+ }
+ }
+ }
+}
+
+void BrokerProxyImpl::incOutstandingLH()
+{
+ requestsOutstanding++;
+}
+
+void BrokerProxyImpl::decOutstanding()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding--;
+ if (requestsOutstanding == 0 && !topicBound) {
+ topicBound = true;
+ for (vector<pair<string, string> >::const_iterator iter = console.impl->bindingList.begin();
+ iter != console.impl->bindingList.end(); iter++) {
+ string exchange(iter->first.empty() ? QMF_EXCHANGE : iter->first);
+ string key(iter->second);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+ }
+ eventQueue.push_back(eventStable());
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(const MethodResponseImpl& from) :
+ status(from.status), schema(from.schema)
+{
+ if (from.exception.get())
+ exception.reset(new Value(*(from.exception)));
+ if (from.arguments.get())
+ arguments.reset(new Value(*(from.arguments)));
+}
+
+MethodResponseImpl::MethodResponseImpl(Buffer& buf, const SchemaMethod* s) : schema(s)
+{
+ string text;
+
+ status = buf.getLong();
+ buf.getMediumString(text);
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+
+ if (status != 0)
+ return;
+
+ arguments.reset(new Value(TYPE_MAP));
+ int argCount(schema->getArgumentCount());
+ for (int idx = 0; idx < argCount; idx++) {
+ const SchemaArgument* arg = schema->getArgument(idx);
+ if (arg->getDirection() == DIR_OUT || arg->getDirection() == DIR_IN_OUT) {
+ Value* value(ValueImpl::factory(arg->getType(), buf));
+ arguments->insert(arg->getName(), value);
+ }
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(uint32_t s, const string& text) : schema(0)
+{
+ status = s;
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+}
+
+MethodResponse* MethodResponseImpl::factory(Buffer& buf, const SchemaMethod* schema)
+{
+ MethodResponseImpl* impl(new MethodResponseImpl(buf, schema));
+ return new MethodResponse(impl);
+}
+
+MethodResponse* MethodResponseImpl::factory(uint32_t status, const std::string& text)
+{
+ MethodResponseImpl* impl(new MethodResponseImpl(status, text));
+ return new MethodResponse(impl);
+}
+
+bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& routingKey, Buffer& buffer)
+{
+ ObjectPtr object;
+ bool completeContext = false;
+
+ if (opcode == Protocol::OP_BROKER_RESPONSE) {
+ broker.handleBrokerResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_SCHEMA_RESPONSE) {
+ broker.handleSchemaResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_PACKAGE_INDICATION)
+ broker.handlePackageIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_CLASS_INDICATION)
+ broker.handleClassIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_HEARTBEAT_INDICATION)
+ broker.handleHeartbeatIndication(buffer, sequence, routingKey);
+ else if (opcode == Protocol::OP_EVENT_INDICATION)
+ broker.handleEventIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_PROPERTY_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, false);
+ broker.console.impl->eventObjectUpdate(object, true, false);
+ }
+ else if (opcode == Protocol::OP_STATISTIC_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, false, true);
+ broker.console.impl->eventObjectUpdate(object, false, true);
+ }
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, true);
+ broker.console.impl->eventObjectUpdate(object, true, true);
+ }
+ else {
+ QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void QueryContext::reserve()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding++;
+}
+
+void QueryContext::release()
+{
+ {
+ Mutex::ScopedLock _lock(lock);
+ if (--requestsOutstanding > 0)
+ return;
+ }
+
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse));
+}
+
+bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer)
+{
+ bool completeContext = false;
+ ObjectPtr object;
+
+ if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+
+ //
+ // Visit each agent and remove the sequence from that agent's in-flight list.
+ // This could be made more efficient because only one agent will have this sequence
+ // in its list.
+ //
+ map<uint32_t, AgentProxyPtr> copy;
+ {
+ Mutex::ScopedLock _block(broker.lock);
+ copy = broker.agentList;
+ }
+ for (map<uint32_t, AgentProxyPtr>::iterator iter = copy.begin(); iter != copy.end(); iter++)
+ iter->second->impl->delSequence(sequence);
+ }
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, true);
+ if (object.get() != 0)
+ queryResponse->impl->results.push_back(object);
+ }
+ else {
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void MethodContext::release()
+{
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventMethodResponse(userContext, methodResponse));
+}
+
+bool MethodContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer)
+{
+ if (opcode == Protocol::OP_METHOD_RESPONSE)
+ methodResponse = broker.handleMethodResponse(buffer, sequence, schema);
+ else
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+
+ return true;
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {}
+AgentProxy::~AgentProxy() { delete impl; }
+const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); }
+uint32_t AgentProxy::getBrokerBank() const { return impl->getBrokerBank(); }
+uint32_t AgentProxy::getAgentBank() const { return impl->getAgentBank(); }
+
+BrokerProxy::BrokerProxy(Console& console) : impl(new BrokerProxyImpl(*this, console)) {}
+BrokerProxy::~BrokerProxy() { delete impl; }
+void BrokerProxy::sessionOpened(SessionHandle& sh) { impl->sessionOpened(sh); }
+void BrokerProxy::sessionClosed() { impl->sessionClosed(); }
+void BrokerProxy::startProtocol() { impl->startProtocol(); }
+void BrokerProxy::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool BrokerProxy::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void BrokerProxy::popXmt() { impl->popXmt(); }
+bool BrokerProxy::getEvent(BrokerEvent& event) const { return impl->getEvent(event); }
+void BrokerProxy::popEvent() { impl->popEvent(); }
+uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); }
+const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); }
+void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); }
+
+MethodResponse::MethodResponse(const MethodResponse& from) : impl(new MethodResponseImpl(*(from.impl))) {}
+MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {}
+MethodResponse::~MethodResponse() {}
+uint32_t MethodResponse::getStatus() const { return impl->getStatus(); }
+const Value* MethodResponse::getException() const { return impl->getException(); }
+const Value* MethodResponse::getArgs() const { return impl->getArgs(); }
+
+QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {}
+QueryResponse::~QueryResponse() {}
+uint32_t QueryResponse::getStatus() const { return impl->getStatus(); }
+const Value* QueryResponse::getException() const { return impl->getException(); }
+uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); }
+const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); }
+
diff --git a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h
new file mode 100644
index 0000000000..798a5fdc76
--- /dev/null
+++ b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h
@@ -0,0 +1,239 @@
+#ifndef _QmfEngineBrokerProxyImpl_
+#define _QmfEngineBrokerProxyImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/Console.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "boost/shared_ptr.hpp"
+#include "boost/noncopyable.hpp"
+#include <memory>
+#include <string>
+#include <deque>
+#include <map>
+#include <set>
+#include <vector>
+
+namespace qmf {
+namespace engine {
+
+ typedef boost::shared_ptr<MethodResponse> MethodResponsePtr;
+ struct MethodResponseImpl {
+ uint32_t status;
+ const SchemaMethod* schema;
+ std::auto_ptr<Value> exception;
+ std::auto_ptr<Value> arguments;
+
+ MethodResponseImpl(const MethodResponseImpl& from);
+ MethodResponseImpl(qpid::framing::Buffer& buf, const SchemaMethod* schema);
+ MethodResponseImpl(uint32_t status, const std::string& text);
+ static MethodResponse* factory(qpid::framing::Buffer& buf, const SchemaMethod* schema);
+ static MethodResponse* factory(uint32_t status, const std::string& text);
+ ~MethodResponseImpl() {}
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ const Value* getArgs() const { return arguments.get(); }
+ };
+
+ typedef boost::shared_ptr<QueryResponse> QueryResponsePtr;
+ struct QueryResponseImpl {
+ uint32_t status;
+ std::auto_ptr<Value> exception;
+ std::vector<ObjectPtr> results;
+
+ QueryResponseImpl() : status(0) {}
+ static QueryResponse* factory() {
+ QueryResponseImpl* impl(new QueryResponseImpl());
+ return new QueryResponse(impl);
+ }
+ ~QueryResponseImpl() {}
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ uint32_t getObjectCount() const { return results.size(); }
+ const Object* getObject(uint32_t idx) const;
+ };
+
+ struct BrokerEventImpl {
+ typedef boost::shared_ptr<BrokerEventImpl> Ptr;
+ BrokerEvent::EventKind kind;
+ std::string name;
+ std::string exchange;
+ std::string bindingKey;
+ void* context;
+ QueryResponsePtr queryResponse;
+ MethodResponsePtr methodResponse;
+
+ BrokerEventImpl(BrokerEvent::EventKind k) : kind(k), context(0) {}
+ ~BrokerEventImpl() {}
+ BrokerEvent copy();
+ };
+
+ typedef boost::shared_ptr<AgentProxy> AgentProxyPtr;
+ struct AgentProxyImpl {
+ Console& console;
+ BrokerProxy& broker;
+ uint32_t agentBank;
+ std::string label;
+ std::set<uint32_t> inFlightSequences;
+
+ AgentProxyImpl(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) : console(c), broker(b), agentBank(ab), label(l) {}
+ static AgentProxy* factory(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) {
+ AgentProxyImpl* impl(new AgentProxyImpl(c, b, ab, l));
+ return new AgentProxy(impl);
+ }
+ ~AgentProxyImpl() {}
+ const std::string& getLabel() const { return label; }
+ uint32_t getBrokerBank() const { return 1; }
+ uint32_t getAgentBank() const { return agentBank; }
+ void addSequence(uint32_t seq) { inFlightSequences.insert(seq); }
+ void delSequence(uint32_t seq) { inFlightSequences.erase(seq); }
+ void releaseInFlight(SequenceManager& seqMgr) {
+ for (std::set<uint32_t>::iterator iter = inFlightSequences.begin(); iter != inFlightSequences.end(); iter++)
+ seqMgr.release(*iter);
+ inFlightSequences.clear();
+ }
+ };
+
+ class BrokerProxyImpl : public boost::noncopyable {
+ public:
+ BrokerProxyImpl(BrokerProxy& pub, Console& _console);
+ ~BrokerProxyImpl() {}
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void sendBufferLH(qpid::framing::Buffer& buf, const std::string& destination, const std::string& routingKey);
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+ void sendQuery(const Query& query, void* context, const AgentProxy* agent);
+ void sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent);
+ std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer);
+ void sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls, const std::string& method, const Value* args, void* context);
+
+ void addBinding(const std::string& exchange, const std::string& key);
+ void staticRelease() { decOutstanding(); }
+
+ private:
+ friend struct StaticContext;
+ friend struct QueryContext;
+ friend struct MethodContext;
+ BrokerProxy& publicObject;
+ mutable qpid::sys::Mutex lock;
+ Console& console;
+ std::string queueName;
+ qpid::framing::Uuid brokerId;
+ SequenceManager seqMgr;
+ uint32_t requestsOutstanding;
+ bool topicBound;
+ std::map<uint32_t, AgentProxyPtr> agentList;
+ std::deque<MessageImpl::Ptr> xmtQueue;
+ std::deque<BrokerEventImpl::Ptr> eventQueue;
+
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ BrokerEventImpl::Ptr eventDeclareQueue(const std::string& queueName);
+ BrokerEventImpl::Ptr eventBind(const std::string& exchange, const std::string& queue, const std::string& key);
+ BrokerEventImpl::Ptr eventSetupComplete();
+ BrokerEventImpl::Ptr eventStable();
+ BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponsePtr response);
+ BrokerEventImpl::Ptr eventMethodResponse(void* context, MethodResponsePtr response);
+
+ void handleBrokerResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handlePackageIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleCommandComplete(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleClassIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ MethodResponsePtr handleMethodResponse(qpid::framing::Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema);
+ void handleHeartbeatIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, const std::string& routingKey);
+ void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ ObjectPtr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat);
+ void updateAgentList(ObjectPtr obj);
+ void incOutstandingLH();
+ void decOutstanding();
+ };
+
+ //
+ // StaticContext is used to handle:
+ //
+ // 1) Responses to console-level requests (for schema info, etc.)
+ // 2) Unsolicited messages from agents (events, published updates, etc.)
+ //
+ struct StaticContext : public SequenceContext {
+ StaticContext(BrokerProxyImpl& b) : broker(b) {}
+ virtual ~StaticContext() {}
+ void reserve() {}
+ void release() { broker.staticRelease(); }
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+ BrokerProxyImpl& broker;
+ };
+
+ //
+ // QueryContext is used to track and handle responses associated with a single Get Query
+ //
+ struct QueryContext : public SequenceContext {
+ QueryContext(BrokerProxyImpl& b, void* u) :
+ broker(b), userContext(u), requestsOutstanding(0), queryResponse(QueryResponseImpl::factory()) {}
+ virtual ~QueryContext() {}
+ void reserve();
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+
+ mutable qpid::sys::Mutex lock;
+ BrokerProxyImpl& broker;
+ void* userContext;
+ uint32_t requestsOutstanding;
+ QueryResponsePtr queryResponse;
+ };
+
+ struct MethodContext : public SequenceContext {
+ MethodContext(BrokerProxyImpl& b, void* u, const SchemaMethod* s) : broker(b), userContext(u), schema(s) {}
+ virtual ~MethodContext() {}
+ void reserve() {}
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+
+ BrokerProxyImpl& broker;
+ void* userContext;
+ const SchemaMethod* schema;
+ MethodResponsePtr methodResponse;
+ };
+
+}
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp
index 034ab18395..2cd6af10f8 100644
--- a/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp
@@ -17,11 +17,11 @@
* under the License.
*/
-#include "qmf/ConnectionSettingsImpl.h"
-#include "qmf/Typecode.h"
+#include "qmf/engine/ConnectionSettingsImpl.h"
+#include "qmf/engine/Typecode.h"
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid;
const string attrProtocol("protocol");
@@ -43,19 +43,20 @@ const string attrMaxSsf("maxSsf");
const string attrRetryDelayMin("retryDelayMin");
const string attrRetryDelayMax("retryDelayMax");
const string attrRetryDelayFactor("retryDelayFactor");
+const string attrSendUserId("sendUserId");
-ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e) :
- envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2)
+ConnectionSettingsImpl::ConnectionSettingsImpl() :
+ retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true)
{
}
-ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e, const string& /*url*/) :
- envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2)
+ConnectionSettingsImpl::ConnectionSettingsImpl(const string& /*url*/) :
+ retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true)
{
// TODO: Parse the URL
}
-void ConnectionSettingsImpl::setAttr(const string& key, const Value& value)
+bool ConnectionSettingsImpl::setAttr(const string& key, const Value& value)
{
if (key == attrProtocol) clientSettings.protocol = value.asString();
else if (key == attrHost) clientSettings.host = value.asString();
@@ -77,6 +78,10 @@ void ConnectionSettingsImpl::setAttr(const string& key, const Value& value)
else if (key == attrRetryDelayMin) retryDelayMin = value.asUint();
else if (key == attrRetryDelayMax) retryDelayMax = value.asUint();
else if (key == attrRetryDelayFactor) retryDelayFactor = value.asUint();
+ else if (key == attrSendUserId) sendUserId = value.asBool();
+ else
+ return false;
+ return true;
}
Value ConnectionSettingsImpl::getAttr(const string& key) const
@@ -251,73 +256,18 @@ void ConnectionSettingsImpl::getRetrySettings(int* min, int* max, int* factor) c
// Wrappers
//==================================================================
-ConnectionSettings::ConnectionSettings(const ConnectionSettings& from)
-{
- impl = new ConnectionSettingsImpl(*from.impl);
-}
-
-ConnectionSettings::ConnectionSettings()
-{
- impl = new ConnectionSettingsImpl(this);
-}
-
-ConnectionSettings::ConnectionSettings(const char* url)
-{
- impl = new ConnectionSettingsImpl(this, url);
-}
-
-ConnectionSettings::~ConnectionSettings()
-{
- delete impl;
-}
-
-void ConnectionSettings::setAttr(const char* key, const Value& value)
-{
- impl->setAttr(key, value);
-}
-
-Value ConnectionSettings::getAttr(const char* key) const
-{
- return impl->getAttr(key);
-}
-
-const char* ConnectionSettings::getAttrString() const
-{
- return impl->getAttrString().c_str();
-}
-
-void ConnectionSettings::transportTcp(uint16_t port)
-{
- impl->transportTcp(port);
-}
-
-void ConnectionSettings::transportSsl(uint16_t port)
-{
- impl->transportSsl(port);
-}
-
-void ConnectionSettings::transportRdma(uint16_t port)
-{
- impl->transportRdma(port);
-}
-
-void ConnectionSettings::authAnonymous(const char* username)
-{
- impl->authAnonymous(username);
-}
-
-void ConnectionSettings::authPlain(const char* username, const char* password)
-{
- impl->authPlain(username, password);
-}
-
-void ConnectionSettings::authGssapi(const char* serviceName, uint32_t minSsf, uint32_t maxSsf)
-{
- impl->authGssapi(serviceName, minSsf, maxSsf);
-}
-
-void ConnectionSettings::setRetry(int delayMin, int delayMax, int delayFactor)
-{
- impl->setRetry(delayMin, delayMax, delayFactor);
-}
+ConnectionSettings::ConnectionSettings(const ConnectionSettings& from) { impl = new ConnectionSettingsImpl(*from.impl); }
+ConnectionSettings::ConnectionSettings() { impl = new ConnectionSettingsImpl(); }
+ConnectionSettings::ConnectionSettings(const char* url) { impl = new ConnectionSettingsImpl(url); }
+ConnectionSettings::~ConnectionSettings() { delete impl; }
+bool ConnectionSettings::setAttr(const char* key, const Value& value) { return impl->setAttr(key, value); }
+Value ConnectionSettings::getAttr(const char* key) const { return impl->getAttr(key); }
+const char* ConnectionSettings::getAttrString() const { return impl->getAttrString().c_str(); }
+void ConnectionSettings::transportTcp(uint16_t port) { impl->transportTcp(port); }
+void ConnectionSettings::transportSsl(uint16_t port) { impl->transportSsl(port); }
+void ConnectionSettings::transportRdma(uint16_t port) { impl->transportRdma(port); }
+void ConnectionSettings::authAnonymous(const char* username) { impl->authAnonymous(username); }
+void ConnectionSettings::authPlain(const char* username, const char* password) { impl->authPlain(username, password); }
+void ConnectionSettings::authGssapi(const char* serviceName, uint32_t minSsf, uint32_t maxSsf) { impl->authGssapi(serviceName, minSsf, maxSsf); }
+void ConnectionSettings::setRetry(int delayMin, int delayMax, int delayFactor) { impl->setRetry(delayMin, delayMax, delayFactor); }
diff --git a/qpid/cpp/src/qmf/ConnectionSettingsImpl.h b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h
index a177233cf3..98bf87868b 100644
--- a/qpid/cpp/src/qmf/ConnectionSettingsImpl.h
+++ b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfConnectionSettingsImpl_
-#define _QmfConnectionSettingsImpl_
+#ifndef _QmfEngineConnectionSettingsImpl_
+#define _QmfEngineConnectionSettingsImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,27 +20,28 @@
* under the License.
*/
-#include "qmf/ConnectionSettings.h"
-#include "qmf/Value.h"
+#include "qmf/engine/ConnectionSettings.h"
+#include "qmf/engine/Value.h"
#include "qpid/client/ConnectionSettings.h"
#include <string>
#include <map>
namespace qmf {
+namespace engine {
class ConnectionSettingsImpl {
- ConnectionSettings* envelope;
qpid::client::ConnectionSettings clientSettings;
mutable std::string attrString;
int retryDelayMin;
int retryDelayMax;
int retryDelayFactor;
+ bool sendUserId;
public:
- ConnectionSettingsImpl(ConnectionSettings* e);
- ConnectionSettingsImpl(ConnectionSettings* e, const std::string& url);
+ ConnectionSettingsImpl();
+ ConnectionSettingsImpl(const std::string& url);
~ConnectionSettingsImpl() {}
- void setAttr(const std::string& key, const Value& value);
+ bool setAttr(const std::string& key, const Value& value);
Value getAttr(const std::string& key) const;
const std::string& getAttrString() const;
void transportTcp(uint16_t port);
@@ -53,8 +54,10 @@ namespace qmf {
const qpid::client::ConnectionSettings& getClientSettings() const;
void getRetrySettings(int* delayMin, int* delayMax, int* delayFactor) const;
+ bool getSendUserId() const { return sendUserId; }
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp b/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp
new file mode 100644
index 0000000000..c2d1f51f2b
--- /dev/null
+++ b/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/ConsoleImpl.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/log/Statement.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+ConsoleEvent ConsoleEventImpl::copy()
+{
+ ConsoleEvent item;
+
+ ::memset(&item, 0, sizeof(ConsoleEvent));
+ item.kind = kind;
+ item.agent = agent.get();
+ item.classKey = classKey;
+ item.object = object.get();
+ item.context = context;
+ item.event = event;
+ item.timestamp = timestamp;
+ item.hasProps = hasProps;
+ item.hasStats = hasStats;
+
+ STRING_REF(name);
+
+ return item;
+}
+
+ConsoleImpl::ConsoleImpl(const ConsoleSettings& s) : settings(s)
+{
+ bindingList.push_back(pair<string, string>(string(), "schema.#"));
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingList.push_back(pair<string, string>(string(), "console.#"));
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingList.push_back(pair<string, string>(string(), "console.obj.#"));
+ else
+ bindingList.push_back(pair<string, string>(string(), "console.obj.*.*.org.apache.qpid.broker.agent"));
+ if (settings.rcvEvents)
+ bindingList.push_back(pair<string, string>(string(), "console.event.#"));
+ if (settings.rcvHeartbeats)
+ bindingList.push_back(pair<string, string>(string(), "console.heartbeat.#"));
+ }
+}
+
+ConsoleImpl::~ConsoleImpl()
+{
+ // This function intentionally left blank.
+}
+
+bool ConsoleImpl::getEvent(ConsoleEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void ConsoleImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void ConsoleImpl::addConnection(BrokerProxy& broker, void* /*context*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ brokerList.push_back(broker.impl);
+}
+
+void ConsoleImpl::delConnection(BrokerProxy& broker)
+{
+ Mutex::ScopedLock _lock(lock);
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ if (*iter == broker.impl) {
+ brokerList.erase(iter);
+ break;
+ }
+}
+
+uint32_t ConsoleImpl::packageCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return packages.size();
+}
+
+const string& ConsoleImpl::getPackageName(uint32_t idx) const
+{
+ const static string empty;
+
+ Mutex::ScopedLock _lock(lock);
+ if (idx >= packages.size())
+ return empty;
+
+ PackageList::const_iterator iter = packages.begin();
+ for (uint32_t i = 0; i < idx; i++) iter++;
+ return iter->first;
+}
+
+uint32_t ConsoleImpl::classCount(const char* packageName) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.size() + eList.size();
+}
+
+const SchemaClassKey* ConsoleImpl::getClass(const char* packageName, uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+ uint32_t count = 0;
+
+ for (ObjectClassList::const_iterator oIter = oList.begin();
+ oIter != oList.end(); oIter++) {
+ if (count == idx)
+ return oIter->second->getClassKey();
+ count++;
+ }
+
+ for (EventClassList::const_iterator eIter = eList.begin();
+ eIter != eList.end(); eIter++) {
+ if (count == idx)
+ return eIter->second->getClassKey();
+ count++;
+ }
+
+ return 0;
+}
+
+ClassKind ConsoleImpl::getClassKind(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return CLASS_OBJECT;
+
+ const EventClassList& eList = pIter->second.second;
+ if (eList.find(key) != eList.end())
+ return CLASS_EVENT;
+ return CLASS_OBJECT;
+}
+
+const SchemaObjectClass* ConsoleImpl::getObjectClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key);
+ if (iter == oList.end())
+ return 0;
+ return iter->second;
+}
+
+const SchemaEventClass* ConsoleImpl::getEventClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const EventClassList& eList = pIter->second.second;
+ EventClassList::const_iterator iter = eList.find(key);
+ if (iter == eList.end())
+ return 0;
+ return iter->second;
+}
+
+void ConsoleImpl::bindPackage(const char* packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleImpl::bindClass(const SchemaClassKey* classKey)
+{
+ stringstream key;
+ key << "console.obj.*.*." << classKey->getPackageName() << "." << classKey->getClassName() << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleImpl::bindClass(const char* packageName, const char* className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+/*
+void ConsoleImpl::startSync(const Query& query, void* context, SyncQuery& sync)
+{
+}
+
+void ConsoleImpl::touchSync(SyncQuery& sync)
+{
+}
+
+void ConsoleImpl::endSync(SyncQuery& sync)
+{
+}
+*/
+
+void ConsoleImpl::learnPackage(const string& packageName)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (packages.find(packageName) == packages.end()) {
+ packages.insert(pair<string, pair<ObjectClassList, EventClassList> >
+ (packageName, pair<ObjectClassList, EventClassList>(ObjectClassList(), EventClassList())));
+ eventNewPackage(packageName);
+ }
+}
+
+void ConsoleImpl::learnClass(SchemaObjectClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ ObjectClassList& list = pIter->second.first;
+ if (list.find(key) == list.end()) {
+ list[key] = cls;
+ eventNewClass(key);
+ }
+}
+
+void ConsoleImpl::learnClass(SchemaEventClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ EventClassList& list = pIter->second.second;
+ if (list.find(key) == list.end()) {
+ list[key] = cls;
+ eventNewClass(key);
+ }
+}
+
+bool ConsoleImpl::haveClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return false;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.find(key) != oList.end() || eList.find(key) != eList.end();
+}
+
+SchemaObjectClass* ConsoleImpl::getSchema(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key);
+ if (iter == oList.end())
+ return 0;
+
+ return iter->second;
+}
+
+void ConsoleImpl::eventAgentAdded(boost::shared_ptr<AgentProxy> agent)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_ADDED));
+ event->agent = agent;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventAgentDeleted(boost::shared_ptr<AgentProxy> agent)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_DELETED));
+ event->agent = agent;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventNewPackage(const string& packageName)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_PACKAGE));
+ event->name = packageName;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventNewClass(const SchemaClassKey* key)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_CLASS));
+ event->classKey = key;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventObjectUpdate(ObjectPtr object, bool prop, bool stat)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::OBJECT_UPDATE));
+ event->object = object;
+ event->hasProps = prop;
+ event->hasStats = stat;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_HEARTBEAT));
+ event->agent = agent;
+ event->timestamp = timestamp;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+Console::Console(const ConsoleSettings& settings) : impl(new ConsoleImpl(settings)) {}
+Console::~Console() { delete impl; }
+bool Console::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); }
+void Console::popEvent() { impl->popEvent(); }
+void Console::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); }
+void Console::delConnection(BrokerProxy& broker) { impl->delConnection(broker); }
+uint32_t Console::packageCount() const { return impl->packageCount(); }
+const char* Console::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); }
+uint32_t Console::classCount(const char* packageName) const { return impl->classCount(packageName); }
+const SchemaClassKey* Console::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); }
+ClassKind Console::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); }
+const SchemaObjectClass* Console::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); }
+const SchemaEventClass* Console::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); }
+void Console::bindPackage(const char* packageName) { impl->bindPackage(packageName); }
+void Console::bindClass(const SchemaClassKey* key) { impl->bindClass(key); }
+void Console::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); }
+//void Console::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); }
+//void Console::touchSync(SyncQuery& sync) { impl->touchSync(sync); }
+//void Console::endSync(SyncQuery& sync) { impl->endSync(sync); }
+
+
diff --git a/qpid/cpp/src/qmf/engine/ConsoleImpl.h b/qpid/cpp/src/qmf/engine/ConsoleImpl.h
new file mode 100644
index 0000000000..8f99c5e6b9
--- /dev/null
+++ b/qpid/cpp/src/qmf/engine/ConsoleImpl.h
@@ -0,0 +1,145 @@
+#ifndef _QmfEngineConsoleEngineImpl_
+#define _QmfEngineConsoleEngineImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/Console.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace qmf {
+namespace engine {
+
+ struct ConsoleEventImpl {
+ typedef boost::shared_ptr<ConsoleEventImpl> Ptr;
+ ConsoleEvent::EventKind kind;
+ boost::shared_ptr<AgentProxy> agent;
+ std::string name;
+ const SchemaClassKey* classKey;
+ boost::shared_ptr<Object> object;
+ void* context;
+ Event* event;
+ uint64_t timestamp;
+ bool hasProps;
+ bool hasStats;
+
+ ConsoleEventImpl(ConsoleEvent::EventKind k) :
+ kind(k), classKey(0), context(0), event(0), timestamp(0) {}
+ ~ConsoleEventImpl() {}
+ ConsoleEvent copy();
+ };
+
+ class ConsoleImpl : public boost::noncopyable {
+ public:
+ ConsoleImpl(const ConsoleSettings& settings = ConsoleSettings());
+ ~ConsoleImpl();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const std::string& getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ friend struct StaticContext;
+ const ConsoleSettings& settings;
+ mutable qpid::sys::Mutex lock;
+ std::deque<ConsoleEventImpl::Ptr> eventQueue;
+ std::vector<BrokerProxyImpl*> brokerList;
+ std::vector<std::pair<std::string, std::string> > bindingList; // exchange/key (empty exchange => QMF_EXCHANGE)
+
+ // Declare a compare class for the class maps that compares the dereferenced
+ // class key pointers. The default behavior would be to compare the pointer
+ // addresses themselves.
+ struct KeyCompare {
+ bool operator()(const SchemaClassKey* left, const SchemaClassKey* right) const {
+ return *left < *right;
+ }
+ };
+
+ typedef std::map<const SchemaClassKey*, SchemaObjectClass*, KeyCompare> ObjectClassList;
+ typedef std::map<const SchemaClassKey*, SchemaEventClass*, KeyCompare> EventClassList;
+ typedef std::map<std::string, std::pair<ObjectClassList, EventClassList> > PackageList;
+
+ PackageList packages;
+
+ void learnPackage(const std::string& packageName);
+ void learnClass(SchemaObjectClass* cls);
+ void learnClass(SchemaEventClass* cls);
+ bool haveClass(const SchemaClassKey* key) const;
+ SchemaObjectClass* getSchema(const SchemaClassKey* key) const;
+
+ void eventAgentAdded(boost::shared_ptr<AgentProxy> agent);
+ void eventAgentDeleted(boost::shared_ptr<AgentProxy> agent);
+ void eventNewPackage(const std::string& packageName);
+ void eventNewClass(const SchemaClassKey* key);
+ void eventObjectUpdate(ObjectPtr object, bool prop, bool stat);
+ void eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp);
+ };
+}
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/MessageImpl.cpp b/qpid/cpp/src/qmf/engine/MessageImpl.cpp
index f2625c7202..0047d3eb9d 100644
--- a/qpid/cpp/src/qmf/MessageImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/MessageImpl.cpp
@@ -17,11 +17,11 @@
* under the License.
*/
-#include "qmf/MessageImpl.h"
+#include "qmf/engine/MessageImpl.h"
#include <string.h>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
diff --git a/qpid/cpp/src/qmf/MessageImpl.h b/qpid/cpp/src/qmf/engine/MessageImpl.h
index 137f435699..b91291d2e4 100644
--- a/qpid/cpp/src/qmf/MessageImpl.h
+++ b/qpid/cpp/src/qmf/engine/MessageImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfMessageImpl_
-#define _QmfMessageImpl_
+#ifndef _QmfEngineMessageImpl_
+#define _QmfEngineMessageImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,11 +20,12 @@
* under the License.
*/
-#include "qmf/Message.h"
+#include "qmf/engine/Message.h"
#include <string>
#include <boost/shared_ptr.hpp>
namespace qmf {
+namespace engine {
struct MessageImpl {
typedef boost::shared_ptr<MessageImpl> Ptr;
@@ -38,5 +39,6 @@ namespace qmf {
Message copy();
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp
index c0618ccc49..b08ae2756c 100644
--- a/qpid/cpp/src/qmf/ObjectIdImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp
@@ -17,11 +17,11 @@
* under the License.
*/
-#include "qmf/ObjectIdImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
#include <stdlib.h>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using qpid::framing::Buffer;
@@ -32,13 +32,12 @@ void AgentAttachment::setBanks(uint32_t broker, uint32_t agent)
((uint64_t) (agent & 0x0fffffff));
}
-ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : envelope(new ObjectId(this)), agent(0)
+ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : agent(0)
{
decode(buffer);
}
-ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) :
- envelope(new ObjectId(this)), agent(a)
+ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) : agent(a)
{
first =
((uint64_t) (flags & 0x0f)) << 60 |
@@ -46,6 +45,18 @@ ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint
second = object;
}
+ObjectId* ObjectIdImpl::factory(Buffer& buffer)
+{
+ ObjectIdImpl* impl(new ObjectIdImpl(buffer));
+ return new ObjectId(impl);
+}
+
+ObjectId* ObjectIdImpl::factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object)
+{
+ ObjectIdImpl* impl(new ObjectIdImpl(agent, flags, seq, object));
+ return new ObjectId(impl);
+}
+
void ObjectIdImpl::decode(Buffer& buffer)
{
first = buffer.getLongLong();
@@ -100,13 +111,14 @@ void ObjectIdImpl::fromString(const std::string& repr)
agent = 0;
}
-std::string ObjectIdImpl::asString() const
+const string& ObjectIdImpl::asString() const
{
stringstream val;
- val << getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
+ val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
getAgentBank() << "-" << getObjectNum();
- return val.str();
+ repr = val.str();
+ return repr;
}
bool ObjectIdImpl::operator==(const ObjectIdImpl& other) const
@@ -135,58 +147,22 @@ bool ObjectIdImpl::operator>(const ObjectIdImpl& other) const
// Wrappers
//==================================================================
-ObjectId::ObjectId() : impl(new ObjectIdImpl(this)) {}
-
+ObjectId::ObjectId() : impl(new ObjectIdImpl()) {}
ObjectId::ObjectId(const ObjectId& from) : impl(new ObjectIdImpl(*(from.impl))) {}
-
ObjectId::ObjectId(ObjectIdImpl* i) : impl(i) {}
+ObjectId::~ObjectId() { delete impl; }
+uint64_t ObjectId::getObjectNum() const { return impl->getObjectNum(); }
+uint32_t ObjectId::getObjectNumHi() const { return impl->getObjectNumHi(); }
+uint32_t ObjectId::getObjectNumLo() const { return impl->getObjectNumLo(); }
+bool ObjectId::isDurable() const { return impl->isDurable(); }
+const char* ObjectId::str() const { return impl->asString().c_str(); }
+uint8_t ObjectId::getFlags() const { return impl->getFlags(); }
+uint16_t ObjectId::getSequence() const { return impl->getSequence(); }
+uint32_t ObjectId::getBrokerBank() const { return impl->getBrokerBank(); }
+uint32_t ObjectId::getAgentBank() const { return impl->getAgentBank(); }
+bool ObjectId::operator==(const ObjectId& other) const { return *impl == *other.impl; }
+bool ObjectId::operator<(const ObjectId& other) const { return *impl < *other.impl; }
+bool ObjectId::operator>(const ObjectId& other) const { return *impl > *other.impl; }
+bool ObjectId::operator<=(const ObjectId& other) const { return !(*impl > *other.impl); }
+bool ObjectId::operator>=(const ObjectId& other) const { return !(*impl < *other.impl); }
-ObjectId::~ObjectId()
-{
- delete impl;
-}
-
-uint64_t ObjectId::getObjectNum() const
-{
- return impl->getObjectNum();
-}
-
-uint32_t ObjectId::getObjectNumHi() const
-{
- return impl->getObjectNumHi();
-}
-
-uint32_t ObjectId::getObjectNumLo() const
-{
- return impl->getObjectNumLo();
-}
-
-bool ObjectId::isDurable() const
-{
- return impl->isDurable();
-}
-
-bool ObjectId::operator==(const ObjectId& other) const
-{
- return *impl == *other.impl;
-}
-
-bool ObjectId::operator<(const ObjectId& other) const
-{
- return *impl < *other.impl;
-}
-
-bool ObjectId::operator>(const ObjectId& other) const
-{
- return *impl > *other.impl;
-}
-
-bool ObjectId::operator<=(const ObjectId& other) const
-{
- return !(*impl > *other.impl);
-}
-
-bool ObjectId::operator>=(const ObjectId& other) const
-{
- return !(*impl < *other.impl);
-}
diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.h b/qpid/cpp/src/qmf/engine/ObjectIdImpl.h
index 38d231237f..d9871ac217 100644
--- a/qpid/cpp/src/qmf/ObjectIdImpl.h
+++ b/qpid/cpp/src/qmf/engine/ObjectIdImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfObjectIdImpl_
-#define _QmfObjectIdImpl_
+#ifndef _QmfEngineObjectIdImpl_
+#define _QmfEngineObjectIdImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,10 +20,11 @@
* under the License.
*/
-#include <qmf/ObjectId.h>
+#include <qmf/engine/ObjectId.h>
#include <qpid/framing/Buffer.h>
namespace qmf {
+namespace engine {
struct AgentAttachment {
uint64_t first;
@@ -34,19 +35,22 @@ namespace qmf {
};
struct ObjectIdImpl {
- ObjectId* envelope;
AgentAttachment* agent;
uint64_t first;
uint64_t second;
+ mutable std::string repr;
- ObjectIdImpl(ObjectId* e) : envelope(e), agent(0), first(0), second(0) {}
+ ObjectIdImpl() : agent(0), first(0), second(0) {}
ObjectIdImpl(qpid::framing::Buffer& buffer);
ObjectIdImpl(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object);
+ static ObjectId* factory(qpid::framing::Buffer& buffer);
+ static ObjectId* factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object);
+
void decode(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void fromString(const std::string& repr);
- std::string asString() const;
+ const std::string& asString() const;
uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; }
uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; }
uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; }
@@ -62,6 +66,7 @@ namespace qmf {
bool operator>(const ObjectIdImpl& other) const;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ObjectImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectImpl.cpp
index 1ea2d54527..cae0e0da68 100644
--- a/qpid/cpp/src/qmf/ObjectImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/ObjectImpl.cpp
@@ -17,18 +17,17 @@
* under the License.
*/
-#include "qmf/ObjectImpl.h"
-#include "qmf/ValueImpl.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/BrokerProxyImpl.h"
#include <qpid/sys/Time.h>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid::sys;
using qpid::framing::Buffer;
-ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) :
- envelope(e), objectClass(type), createTime(uint64_t(Duration(now()))),
- destroyTime(0), lastUpdatedTime(createTime)
+ObjectImpl::ObjectImpl(const SchemaObjectClass* type) : objectClass(type), broker(0), createTime(uint64_t(Duration(now()))), destroyTime(0), lastUpdatedTime(createTime)
{
int propCount = objectClass->getPropertyCount();
int statCount = objectClass->getStatisticCount();
@@ -45,8 +44,8 @@ ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) :
}
}
-ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop, bool stat, bool managed) :
- envelope(new Object(this)), objectClass(type), createTime(0), destroyTime(0), lastUpdatedTime(0)
+ObjectImpl::ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed) :
+ objectClass(type), broker(b), createTime(0), destroyTime(0), lastUpdatedTime(0)
{
int idx;
@@ -54,7 +53,7 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop,
lastUpdatedTime = buffer.getLongLong();
createTime = buffer.getLongLong();
destroyTime = buffer.getLongLong();
- objectId.reset(new ObjectIdImpl(buffer));
+ objectId.reset(ObjectIdImpl::factory(buffer));
}
if (prop) {
@@ -66,8 +65,8 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop,
if (excludes.count(prop->getName()) != 0) {
properties[prop->getName()] = ValuePtr(new Value(prop->getType()));
} else {
- ValueImpl* pval = new ValueImpl(prop->getType(), buffer);
- properties[prop->getName()] = ValuePtr(pval->envelope);
+ Value* pval = ValueImpl::factory(prop->getType(), buffer);
+ properties[prop->getName()] = ValuePtr(pval);
}
}
}
@@ -76,12 +75,18 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop,
int statCount = objectClass->getStatisticCount();
for (idx = 0; idx < statCount; idx++) {
const SchemaStatistic* stat = objectClass->getStatistic(idx);
- ValueImpl* sval = new ValueImpl(stat->getType(), buffer);
- statistics[stat->getName()] = ValuePtr(sval->envelope);
+ Value* sval = ValueImpl::factory(stat->getType(), buffer);
+ statistics[stat->getName()] = ValuePtr(sval);
}
}
}
+Object* ObjectImpl::factory(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed)
+{
+ ObjectImpl* impl(new ObjectImpl(type, b, buffer, prop, stat, managed));
+ return new Object(impl);
+}
+
ObjectImpl::~ObjectImpl()
{
}
@@ -107,6 +112,22 @@ Value* ObjectImpl::getValue(const string& key) const
return 0;
}
+void ObjectImpl::invokeMethod(const string& methodName, const Value* inArgs, void* context) const
+{
+ if (broker != 0 && objectId.get() != 0)
+ broker->sendMethodRequest(objectId.get(), objectClass, methodName, inArgs, context);
+}
+
+void ObjectImpl::merge(const Object& from)
+{
+ for (map<string, ValuePtr>::const_iterator piter = from.impl->properties.begin();
+ piter != from.impl->properties.end(); piter++)
+ properties[piter->first] = piter->second;
+ for (map<string, ValuePtr>::const_iterator siter = from.impl->statistics.begin();
+ siter != from.impl->statistics.end(); siter++)
+ statistics[siter->first] = siter->second;
+}
+
void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList)
{
int propCount = objectClass->getPropertyCount();
@@ -143,7 +164,7 @@ void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const
buffer.putLongLong(lastUpdatedTime);
buffer.putLongLong(createTime);
buffer.putLongLong(destroyTime);
- objectId->encode(buffer);
+ objectId->impl->encode(buffer);
}
void ObjectImpl::encodeProperties(qpid::framing::Buffer& buffer) const
@@ -196,7 +217,7 @@ void ObjectImpl::encodeStatistics(qpid::framing::Buffer& buffer) const
// Wrappers
//==================================================================
-Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(this, type)) {}
+Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(type)) {}
Object::Object(ObjectImpl* i) : impl(i) {}
Object::Object(const Object& from) : impl(new ObjectImpl(*(from.impl))) {}
Object::~Object() { delete impl; }
@@ -204,5 +225,8 @@ void Object::destroy() { impl->destroy(); }
const ObjectId* Object::getObjectId() const { return impl->getObjectId(); }
void Object::setObjectId(ObjectId* oid) { impl->setObjectId(oid); }
const SchemaObjectClass* Object::getClass() const { return impl->getClass(); }
-Value* Object::getValue(char* key) const { return impl->getValue(key); }
+Value* Object::getValue(const char* key) const { return impl->getValue(key); }
+void Object::invokeMethod(const char* m, const Value* a, void* c) const { impl->invokeMethod(m, a, c); }
+bool Object::isDeleted() const { return impl->isDeleted(); }
+void Object::merge(const Object& from) { impl->merge(from); }
diff --git a/qpid/cpp/src/qmf/ObjectImpl.h b/qpid/cpp/src/qmf/engine/ObjectImpl.h
index d69979e0da..ddd20bfea2 100644
--- a/qpid/cpp/src/qmf/ObjectImpl.h
+++ b/qpid/cpp/src/qmf/engine/ObjectImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfObjectImpl_
-#define _QmfObjectImpl_
+#ifndef _QmfEngineObjectImpl_
+#define _QmfEngineObjectImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
* under the License.
*/
-#include <qmf/Object.h>
-#include <qmf/ObjectIdImpl.h>
+#include <qmf/engine/Object.h>
+#include <qmf/engine/ObjectIdImpl.h>
#include <map>
#include <set>
#include <string>
@@ -30,28 +30,38 @@
#include <qpid/sys/Mutex.h>
namespace qmf {
+namespace engine {
+
+ class BrokerProxyImpl;
+
+ typedef boost::shared_ptr<Object> ObjectPtr;
struct ObjectImpl {
- typedef boost::shared_ptr<ObjectImpl> Ptr;
typedef boost::shared_ptr<Value> ValuePtr;
- Object* envelope;
const SchemaObjectClass* objectClass;
- boost::shared_ptr<ObjectIdImpl> objectId;
+ BrokerProxyImpl* broker;
+ boost::shared_ptr<ObjectId> objectId;
uint64_t createTime;
uint64_t destroyTime;
uint64_t lastUpdatedTime;
mutable std::map<std::string, ValuePtr> properties;
mutable std::map<std::string, ValuePtr> statistics;
- ObjectImpl(Object* e, const SchemaObjectClass* type);
- ObjectImpl(const SchemaObjectClass* type, qpid::framing::Buffer& buffer, bool prop, bool stat, bool managed);
+ ObjectImpl(const SchemaObjectClass* type);
+ ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer,
+ bool prop, bool stat, bool managed);
+ static Object* factory(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer,
+ bool prop, bool stat, bool managed);
~ObjectImpl();
void destroy();
- const ObjectId* getObjectId() const { return objectId.get() ? objectId->envelope : 0; }
- void setObjectId(ObjectId* oid) { objectId.reset(oid->impl); }
+ const ObjectId* getObjectId() const { return objectId.get(); }
+ void setObjectId(ObjectId* oid) { objectId.reset(oid); }
const SchemaObjectClass* getClass() const { return objectClass; }
Value* getValue(const std::string& key) const;
+ void invokeMethod(const std::string& methodName, const Value* inArgs, void* context) const;
+ bool isDeleted() const { return destroyTime != 0; }
+ void merge(const Object& from);
void parsePresenceMasks(qpid::framing::Buffer& buffer, std::set<std::string>& excludeList);
void encodeSchemaKey(qpid::framing::Buffer& buffer) const;
@@ -60,6 +70,7 @@ namespace qmf {
void encodeStatistics(qpid::framing::Buffer& buffer) const;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/Protocol.cpp b/qpid/cpp/src/qmf/engine/Protocol.cpp
index 0a3beeb276..6061b70a8d 100644
--- a/qpid/cpp/src/qmf/Protocol.cpp
+++ b/qpid/cpp/src/qmf/engine/Protocol.cpp
@@ -17,11 +17,11 @@
* under the License.
*/
-#include "qmf/Protocol.h"
+#include "qmf/engine/Protocol.h"
#include "qpid/framing/Buffer.h"
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid::framing;
diff --git a/qpid/cpp/src/qmf/Protocol.h b/qpid/cpp/src/qmf/engine/Protocol.h
index d5da08c1db..1cdfa60c84 100644
--- a/qpid/cpp/src/qmf/Protocol.h
+++ b/qpid/cpp/src/qmf/engine/Protocol.h
@@ -1,5 +1,5 @@
-#ifndef _QmfProtocol_
-#define _QmfProtocol_
+#ifndef _QmfEngineProtocol_
+#define _QmfEngineProtocol_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -29,6 +29,7 @@ namespace qpid {
}
namespace qmf {
+namespace engine {
class Protocol {
public:
@@ -62,6 +63,7 @@ namespace qmf {
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/QueryImpl.cpp b/qpid/cpp/src/qmf/engine/QueryImpl.cpp
index f75a9aa5d5..6f2beeee87 100644
--- a/qpid/cpp/src/qmf/QueryImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/QueryImpl.cpp
@@ -17,13 +17,13 @@
* under the License.
*/
-#include "qmf/QueryImpl.h"
-#include "qmf/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/FieldTable.h"
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid::framing;
bool QueryElementImpl::evaluate(const Object* /*object*/) const
@@ -45,6 +45,12 @@ QueryImpl::QueryImpl(Buffer& buffer)
// TODO
}
+Query* QueryImpl::factory(Buffer& buffer)
+{
+ QueryImpl* impl(new QueryImpl(buffer));
+ return new Query(impl);
+}
+
void QueryImpl::encode(Buffer& buffer) const
{
FieldTable ft;
@@ -69,14 +75,17 @@ QueryElement::QueryElement(const char* attrName, const Value* value, ValueOper o
QueryElement::QueryElement(QueryElementImpl* i) : impl(i) {}
QueryElement::~QueryElement() { delete impl; }
bool QueryElement::evaluate(const Object* object) const { return impl->evaluate(object); }
+
QueryExpression::QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2) : impl(new QueryExpressionImpl(oper, operand1, operand2)) {}
QueryExpression::QueryExpression(QueryExpressionImpl* i) : impl(i) {}
QueryExpression::~QueryExpression() { delete impl; }
bool QueryExpression::evaluate(const Object* object) const { return impl->evaluate(object); }
+
Query::Query(const char* className, const char* packageName) : impl(new QueryImpl(className, packageName)) {}
Query::Query(const SchemaClassKey* key) : impl(new QueryImpl(key)) {}
Query::Query(const ObjectId* oid) : impl(new QueryImpl(oid)) {}
Query::Query(QueryImpl* i) : impl(i) {}
+Query::Query(const Query& from) : impl(new QueryImpl(*(from.impl))) {}
Query::~Query() { delete impl; }
void Query::setSelect(const QueryOperand* criterion) { impl->setSelect(criterion); }
void Query::setLimit(uint32_t maxResults) { impl->setLimit(maxResults); }
diff --git a/qpid/cpp/src/qmf/QueryImpl.h b/qpid/cpp/src/qmf/engine/QueryImpl.h
index 4a56a457c0..2c64c6739c 100644
--- a/qpid/cpp/src/qmf/QueryImpl.h
+++ b/qpid/cpp/src/qmf/engine/QueryImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfQueryImpl_
-#define _QmfQueryImpl_
+#ifndef _QmfEngineQueryImpl_
+#define _QmfEngineQueryImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
* under the License.
*/
-#include "qmf/Query.h"
-#include "qmf/Schema.h"
+#include "qmf/engine/Query.h"
+#include "qmf/engine/Schema.h"
#include <string>
#include <boost/shared_ptr.hpp>
@@ -32,41 +32,39 @@ namespace qpid {
}
namespace qmf {
+namespace engine {
struct QueryElementImpl {
- QueryElementImpl(const std::string& a, const Value* v, ValueOper o) :
- envelope(new QueryElement(this)), attrName(a), value(v), oper(o) {}
+ QueryElementImpl(const std::string& a, const Value* v, ValueOper o) : attrName(a), value(v), oper(o) {}
~QueryElementImpl() {}
bool evaluate(const Object* object) const;
- QueryElement* envelope;
std::string attrName;
const Value* value;
ValueOper oper;
};
struct QueryExpressionImpl {
- QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) :
- envelope(new QueryExpression(this)), oper(o), left(operand1), right(operand2) {}
+ QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) : oper(o), left(operand1), right(operand2) {}
~QueryExpressionImpl() {}
bool evaluate(const Object* object) const;
- QueryExpression* envelope;
ExprOper oper;
const QueryOperand* left;
const QueryOperand* right;
};
struct QueryImpl {
- QueryImpl(Query* e) : envelope(e), select(0) {}
- QueryImpl(const std::string& c, const std::string& p) :
- envelope(new Query(this)), packageName(p), className(c) {}
- QueryImpl(const SchemaClassKey* key) :
- envelope(new Query(this)), packageName(key->getPackageName()), className(key->getClassName()) {}
- QueryImpl(const ObjectId* oid) :
- envelope(new Query(this)), oid(new ObjectId(*oid)) {}
+ // Constructors mapped to public
+ QueryImpl(const std::string& c, const std::string& p) : packageName(p), className(c), select(0), resultLimit(0) {}
+ QueryImpl(const SchemaClassKey* key) : packageName(key->getPackageName()), className(key->getClassName()), select(0), resultLimit(0) {}
+ QueryImpl(const ObjectId* oid) : oid(new ObjectId(*oid)), select(0), resultLimit(0) {}
+
+ // Factory constructors
QueryImpl(qpid::framing::Buffer& buffer);
+
~QueryImpl() {};
+ static Query* factory(qpid::framing::Buffer& buffer);
void setSelect(const QueryOperand* criterion) { select = criterion; }
void setLimit(uint32_t maxResults) { resultLimit = maxResults; }
@@ -88,7 +86,6 @@ namespace qmf {
void encode(qpid::framing::Buffer& buffer) const;
- Query* envelope;
std::string packageName;
std::string className;
boost::shared_ptr<ObjectId> oid;
@@ -98,5 +95,6 @@ namespace qmf {
bool orderDecreasing;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ResilientConnection.cpp b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp
index 7ec03cf4da..9502130288 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.cpp
+++ b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp
@@ -17,9 +17,9 @@
* under the License.
*/
-#include "qmf/ResilientConnection.h"
-#include "qmf/MessageImpl.h"
-#include "qmf/ConnectionSettingsImpl.h"
+#include "qmf/engine/ResilientConnection.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/ConnectionSettingsImpl.h"
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/MessageListener.h>
@@ -38,13 +38,15 @@
#include <vector>
#include <set>
#include <boost/intrusive_ptr.hpp>
+#include <boost/noncopyable.hpp>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid;
using qpid::sys::Mutex;
namespace qmf {
+namespace engine {
struct ResilientConnectionEventImpl {
ResilientConnectionEvent::EventKind kind;
void* sessionContext;
@@ -64,20 +66,19 @@ namespace qmf {
client::Connection& connection;
client::Session session;
client::SubscriptionManager* subscriptions;
+ string userId;
void* userContext;
vector<string> dests;
qpid::sys::Thread thread;
- RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) :
- connImpl(ci), name(n), connection(c), session(connection.newSession(name)),
- subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this) {}
+ RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc);
~RCSession();
void received(client::Message& msg);
void run();
void stop();
};
- class ResilientConnectionImpl : public qpid::sys::Runnable {
+ class ResilientConnectionImpl : public qpid::sys::Runnable, public boost::noncopyable {
public:
ResilientConnectionImpl(const ConnectionSettings& settings);
~ResilientConnectionImpl();
@@ -87,7 +88,7 @@ namespace qmf {
void popEvent();
bool createSession(const char* name, void* sessionContext, SessionHandle& handle);
void destroySession(SessionHandle handle);
- void sendMessage(SessionHandle handle, qmf::Message& message);
+ void sendMessage(SessionHandle handle, qmf::engine::Message& message);
void declareQueue(SessionHandle handle, char* queue);
void deleteQueue(SessionHandle handle, char* queue);
void bind(SessionHandle handle, char* exchange, char* queue, char* key);
@@ -120,6 +121,7 @@ namespace qmf {
set<RCSession::Ptr> sessions;
};
}
+}
ResilientConnectionEvent ResilientConnectionEventImpl::copy()
{
@@ -134,6 +136,14 @@ ResilientConnectionEvent ResilientConnectionEventImpl::copy()
return item;
}
+RCSession::RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) :
+ connImpl(ci), name(n), connection(c), session(connection.newSession(name)),
+ subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this)
+{
+ const qpid::client::ConnectionSettings& operSettings = connection.getNegotiatedSettings();
+ userId = operSettings.username;
+}
+
RCSession::~RCSession()
{
subscriptions->stop();
@@ -158,18 +168,23 @@ void RCSession::stop()
void RCSession::received(client::Message& msg)
{
- qmf::MessageImpl qmsg;
+ MessageImpl qmsg;
qmsg.body = msg.getData();
- qpid::framing::MessageProperties p = msg.getMessageProperties();
- if (p.hasReplyTo()) {
- const qpid::framing::ReplyTo& rt = p.getReplyTo();
+ qpid::framing::DeliveryProperties dp = msg.getDeliveryProperties();
+ if (dp.hasRoutingKey()) {
+ qmsg.routingKey = dp.getRoutingKey();
+ }
+
+ qpid::framing::MessageProperties mp = msg.getMessageProperties();
+ if (mp.hasReplyTo()) {
+ const qpid::framing::ReplyTo& rt = mp.getReplyTo();
qmsg.replyExchange = rt.getExchange();
qmsg.replyKey = rt.getRoutingKey();
}
- if (p.hasUserId()) {
- qmsg.userId = p.getUserId();
+ if (mp.hasUserId()) {
+ qmsg.userId = mp.getUserId();
}
connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg);
@@ -244,7 +259,7 @@ void ResilientConnectionImpl::destroySession(SessionHandle handle)
}
}
-void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& message)
+void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::engine::Message& message)
{
Mutex::ScopedLock _lock(lock);
RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
@@ -253,6 +268,8 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me
string data(message.body, message.length);
msg.getDeliveryProperties().setRoutingKey(message.routingKey);
msg.getMessageProperties().setReplyTo(qpid::framing::ReplyTo(message.replyExchange, message.replyKey));
+ if (settings.impl->getSendUserId())
+ msg.getMessageProperties().setUserId(sess->userId);
msg.setData(data);
try {
@@ -383,7 +400,7 @@ void ResilientConnectionImpl::sessionClosed(RCSession*)
void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind kind,
void* sessionContext,
- const qmf::MessageImpl& message,
+ const MessageImpl& message,
const string& errorText)
{
Mutex::ScopedLock _lock(lock);
@@ -440,7 +457,7 @@ void ResilientConnection::destroySession(SessionHandle handle)
impl->destroySession(handle);
}
-void ResilientConnection::sendMessage(SessionHandle handle, qmf::Message& message)
+void ResilientConnection::sendMessage(SessionHandle handle, qmf::engine::Message& message)
{
impl->sendMessage(handle, message);
}
diff --git a/qpid/cpp/src/qmf/SchemaImpl.cpp b/qpid/cpp/src/qmf/engine/SchemaImpl.cpp
index 3eb14c3952..e366a66826 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/SchemaImpl.cpp
@@ -17,7 +17,7 @@
* under the License.
*/
-#include "qmf/SchemaImpl.h"
+#include "qmf/engine/SchemaImpl.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/FieldTable.h>
#include <qpid/framing/Uuid.h>
@@ -26,7 +26,7 @@
#include <vector>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
using qpid::framing::Uuid;
@@ -81,7 +81,7 @@ bool SchemaHash::operator>(const SchemaHash& other) const
return ::memcmp(&hash, &other.hash, 16) > 0;
}
-SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgument(this))
+SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer)
{
FieldTable map;
map.decode(buffer);
@@ -99,6 +99,12 @@ SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgu
dir = DIR_IN_OUT;
}
+SchemaArgument* SchemaArgumentImpl::factory(Buffer& buffer)
+{
+ SchemaArgumentImpl* impl(new SchemaArgumentImpl(buffer));
+ return new SchemaArgument(impl);
+}
+
void SchemaArgumentImpl::encode(Buffer& buffer) const
{
FieldTable map;
@@ -128,7 +134,7 @@ void SchemaArgumentImpl::updateHash(SchemaHash& hash) const
hash.update(description);
}
-SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) : envelope(new SchemaMethod(this))
+SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer)
{
FieldTable map;
int argCount;
@@ -139,11 +145,17 @@ SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) : envelope(new SchemaMethod(t
description = map.getAsString("desc");
for (int idx = 0; idx < argCount; idx++) {
- SchemaArgumentImpl* arg = new SchemaArgumentImpl(buffer);
- addArgument(*arg->envelope);
+ SchemaArgument* arg = SchemaArgumentImpl::factory(buffer);
+ addArgument(arg);
}
}
+SchemaMethod* SchemaMethodImpl::factory(Buffer& buffer)
+{
+ SchemaMethodImpl* impl(new SchemaMethodImpl(buffer));
+ return new SchemaMethod(impl);
+}
+
void SchemaMethodImpl::encode(Buffer& buffer) const
{
FieldTable map;
@@ -154,23 +166,23 @@ void SchemaMethodImpl::encode(Buffer& buffer) const
map.setString("desc", description);
map.encode(buffer);
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++)
- (*iter)->encode(buffer);
+ (*iter)->impl->encode(buffer);
}
-void SchemaMethodImpl::addArgument(const SchemaArgument& argument)
+void SchemaMethodImpl::addArgument(const SchemaArgument* argument)
{
- arguments.push_back(argument.impl);
+ arguments.push_back(argument);
}
const SchemaArgument* SchemaMethodImpl::getArgument(int idx) const
{
int count = 0;
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++, count++)
if (idx == count)
- return (*iter)->envelope;
+ return (*iter);
return 0;
}
@@ -178,12 +190,12 @@ void SchemaMethodImpl::updateHash(SchemaHash& hash) const
{
hash.update(name);
hash.update(description);
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++)
- (*iter)->updateHash(hash);
+ (*iter)->impl->updateHash(hash);
}
-SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) : envelope(new SchemaProperty(this))
+SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer)
{
FieldTable map;
map.decode(buffer);
@@ -197,6 +209,12 @@ SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) : envelope(new SchemaProp
description = map.getAsString("desc");
}
+SchemaProperty* SchemaPropertyImpl::factory(Buffer& buffer)
+{
+ SchemaPropertyImpl* impl(new SchemaPropertyImpl(buffer));
+ return new SchemaProperty(impl);
+}
+
void SchemaPropertyImpl::encode(Buffer& buffer) const
{
FieldTable map;
@@ -225,7 +243,7 @@ void SchemaPropertyImpl::updateHash(SchemaHash& hash) const
hash.update(description);
}
-SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) : envelope(new SchemaStatistic(this))
+SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer)
{
FieldTable map;
map.decode(buffer);
@@ -236,6 +254,12 @@ SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) : envelope(new SchemaSt
description = map.getAsString("desc");
}
+SchemaStatistic* SchemaStatisticImpl::factory(Buffer& buffer)
+{
+ SchemaStatisticImpl* impl(new SchemaStatisticImpl(buffer));
+ return new SchemaStatistic(impl);
+}
+
void SchemaStatisticImpl::encode(Buffer& buffer) const
{
FieldTable map;
@@ -258,16 +282,26 @@ void SchemaStatisticImpl::updateHash(SchemaHash& hash) const
hash.update(description);
}
-SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) :
- envelope(new SchemaClassKey(this)), package(p), name(n), hash(h) {}
+SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) : package(p), name(n), hash(h) {}
-SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) :
- envelope(new SchemaClassKey(this)), package(packageContainer), name(nameContainer), hash(hashContainer)
+SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) : package(packageContainer), name(nameContainer), hash(hashContainer)
{
buffer.getShortString(packageContainer);
buffer.getShortString(nameContainer);
hashContainer.decode(buffer);
-}
+}
+
+SchemaClassKey* SchemaClassKeyImpl::factory(const string& package, const string& name, const SchemaHash& hash)
+{
+ SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(package, name, hash));
+ return new SchemaClassKey(impl);
+}
+
+SchemaClassKey* SchemaClassKeyImpl::factory(Buffer& buffer)
+{
+ SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(buffer));
+ return new SchemaClassKey(impl);
+}
void SchemaClassKeyImpl::encode(Buffer& buffer) const
{
@@ -292,16 +326,16 @@ bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const
return hash < other.hash;
}
-string SchemaClassKeyImpl::str() const
+const string& SchemaClassKeyImpl::str() const
{
Uuid printableHash(hash.get());
stringstream str;
str << package << ":" << name << "(" << printableHash << ")";
- return str.str();
+ repr = str.str();
+ return repr;
}
-SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) :
- envelope(new SchemaObjectClass(this)), hasHash(true), classKey(package, name, hash)
+SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash))
{
buffer.getShortString(package);
buffer.getShortString(name);
@@ -313,21 +347,27 @@ SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) :
uint16_t methodCount = buffer.getShort();
for (uint16_t idx = 0; idx < propCount; idx++) {
- SchemaPropertyImpl* property = new SchemaPropertyImpl(buffer);
- addProperty(*property->envelope);
+ const SchemaProperty* property = SchemaPropertyImpl::factory(buffer);
+ addProperty(property);
}
for (uint16_t idx = 0; idx < statCount; idx++) {
- SchemaStatisticImpl* statistic = new SchemaStatisticImpl(buffer);
- addStatistic(*statistic->envelope);
+ const SchemaStatistic* statistic = SchemaStatisticImpl::factory(buffer);
+ addStatistic(statistic);
}
for (uint16_t idx = 0; idx < methodCount; idx++) {
- SchemaMethodImpl* method = new SchemaMethodImpl(buffer);
- addMethod(*method->envelope);
+ SchemaMethod* method = SchemaMethodImpl::factory(buffer);
+ addMethod(method);
}
}
+SchemaObjectClass* SchemaObjectClassImpl::factory(Buffer& buffer)
+{
+ SchemaObjectClassImpl* impl(new SchemaObjectClassImpl(buffer));
+ return new SchemaObjectClass(impl);
+}
+
void SchemaObjectClassImpl::encode(Buffer& buffer) const
{
buffer.putOctet((uint8_t) CLASS_OBJECT);
@@ -339,15 +379,15 @@ void SchemaObjectClassImpl::encode(Buffer& buffer) const
buffer.putShort((uint16_t) statistics.size());
buffer.putShort((uint16_t) methods.size());
- for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin();
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
iter != properties.end(); iter++)
- (*iter)->encode(buffer);
- for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin();
+ (*iter)->impl->encode(buffer);
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
iter != statistics.end(); iter++)
- (*iter)->encode(buffer);
- for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin();
+ (*iter)->impl->encode(buffer);
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
iter != methods.end(); iter++)
- (*iter)->encode(buffer);
+ (*iter)->impl->encode(buffer);
}
const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const
@@ -356,67 +396,66 @@ const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const
hasHash = true;
hash.update(package);
hash.update(name);
- for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin();
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
iter != properties.end(); iter++)
- (*iter)->updateHash(hash);
- for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin();
+ (*iter)->impl->updateHash(hash);
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
iter != statistics.end(); iter++)
- (*iter)->updateHash(hash);
- for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin();
+ (*iter)->impl->updateHash(hash);
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
iter != methods.end(); iter++)
- (*iter)->updateHash(hash);
+ (*iter)->impl->updateHash(hash);
}
- return classKey.envelope;
+ return classKey.get();
}
-void SchemaObjectClassImpl::addProperty(const SchemaProperty& property)
+void SchemaObjectClassImpl::addProperty(const SchemaProperty* property)
{
- properties.push_back(property.impl);
+ properties.push_back(property);
}
-void SchemaObjectClassImpl::addStatistic(const SchemaStatistic& statistic)
+void SchemaObjectClassImpl::addStatistic(const SchemaStatistic* statistic)
{
- statistics.push_back(statistic.impl);
+ statistics.push_back(statistic);
}
-void SchemaObjectClassImpl::addMethod(const SchemaMethod& method)
+void SchemaObjectClassImpl::addMethod(const SchemaMethod* method)
{
- methods.push_back(method.impl);
+ methods.push_back(method);
}
const SchemaProperty* SchemaObjectClassImpl::getProperty(int idx) const
{
int count = 0;
- for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin();
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
iter != properties.end(); iter++, count++)
if (idx == count)
- return (*iter)->envelope;
+ return *iter;
return 0;
}
const SchemaStatistic* SchemaObjectClassImpl::getStatistic(int idx) const
{
int count = 0;
- for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin();
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
iter != statistics.end(); iter++, count++)
if (idx == count)
- return (*iter)->envelope;
+ return *iter;
return 0;
}
const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const
{
int count = 0;
- for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin();
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
iter != methods.end(); iter++, count++)
if (idx == count)
- return (*iter)->envelope;
+ return *iter;
return 0;
}
-SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) :
- envelope(new SchemaEventClass(this)), hasHash(true), classKey(package, name, hash)
+SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash))
{
buffer.getShortString(package);
buffer.getShortString(name);
@@ -426,11 +465,17 @@ SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) :
uint16_t argCount = buffer.getShort();
for (uint16_t idx = 0; idx < argCount; idx++) {
- SchemaArgumentImpl* argument = new SchemaArgumentImpl(buffer);
- addArgument(*argument->envelope);
+ SchemaArgument* argument = SchemaArgumentImpl::factory(buffer);
+ addArgument(argument);
}
}
+SchemaEventClass* SchemaEventClassImpl::factory(Buffer& buffer)
+{
+ SchemaEventClassImpl* impl(new SchemaEventClassImpl(buffer));
+ return new SchemaEventClass(impl);
+}
+
void SchemaEventClassImpl::encode(Buffer& buffer) const
{
buffer.putOctet((uint8_t) CLASS_EVENT);
@@ -439,9 +484,9 @@ void SchemaEventClassImpl::encode(Buffer& buffer) const
hash.encode(buffer);
buffer.putShort((uint16_t) arguments.size());
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++)
- (*iter)->encode(buffer);
+ (*iter)->impl->encode(buffer);
}
const SchemaClassKey* SchemaEventClassImpl::getClassKey() const
@@ -450,25 +495,25 @@ const SchemaClassKey* SchemaEventClassImpl::getClassKey() const
hasHash = true;
hash.update(package);
hash.update(name);
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++)
- (*iter)->updateHash(hash);
+ (*iter)->impl->updateHash(hash);
}
- return classKey.envelope;
+ return classKey.get();
}
-void SchemaEventClassImpl::addArgument(const SchemaArgument& argument)
+void SchemaEventClassImpl::addArgument(const SchemaArgument* argument)
{
- arguments.push_back(argument.impl);
+ arguments.push_back(argument);
}
const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const
{
int count = 0;
- for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin();
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
iter != arguments.end(); iter++, count++)
if (idx == count)
- return (*iter)->envelope;
+ return (*iter);
return 0;
}
@@ -477,8 +522,9 @@ const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const
// Wrappers
//==================================================================
-SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(this, name, typecode); }
+SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(name, typecode); }
SchemaArgument::SchemaArgument(SchemaArgumentImpl* i) : impl(i) {}
+SchemaArgument::SchemaArgument(const SchemaArgument& from) : impl(new SchemaArgumentImpl(*(from.impl))) {}
SchemaArgument::~SchemaArgument() { delete impl; }
void SchemaArgument::setDirection(Direction dir) { impl->setDirection(dir); }
void SchemaArgument::setUnit(const char* val) { impl->setUnit(val); }
@@ -488,17 +534,21 @@ Typecode SchemaArgument::getType() const { return impl->getType(); }
Direction SchemaArgument::getDirection() const { return impl->getDirection(); }
const char* SchemaArgument::getUnit() const { return impl->getUnit().c_str(); }
const char* SchemaArgument::getDesc() const { return impl->getDesc().c_str(); }
-SchemaMethod::SchemaMethod(const char* name) { impl = new SchemaMethodImpl(this, name); }
+
+SchemaMethod::SchemaMethod(const char* name) : impl(new SchemaMethodImpl(name)) {}
SchemaMethod::SchemaMethod(SchemaMethodImpl* i) : impl(i) {}
+SchemaMethod::SchemaMethod(const SchemaMethod& from) : impl(new SchemaMethodImpl(*(from.impl))) {}
SchemaMethod::~SchemaMethod() { delete impl; }
-void SchemaMethod::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaMethod::addArgument(const SchemaArgument* argument) { impl->addArgument(argument); }
void SchemaMethod::setDesc(const char* desc) { impl->setDesc(desc); }
const char* SchemaMethod::getName() const { return impl->getName().c_str(); }
const char* SchemaMethod::getDesc() const { return impl->getDesc().c_str(); }
int SchemaMethod::getArgumentCount() const { return impl->getArgumentCount(); }
const SchemaArgument* SchemaMethod::getArgument(int idx) const { return impl->getArgument(idx); }
-SchemaProperty::SchemaProperty(const char* name, Typecode typecode) { impl = new SchemaPropertyImpl(this, name, typecode); }
+
+SchemaProperty::SchemaProperty(const char* name, Typecode typecode) : impl(new SchemaPropertyImpl(name, typecode)) {}
SchemaProperty::SchemaProperty(SchemaPropertyImpl* i) : impl(i) {}
+SchemaProperty::SchemaProperty(const SchemaProperty& from) : impl(new SchemaPropertyImpl(*(from.impl))) {}
SchemaProperty::~SchemaProperty() { delete impl; }
void SchemaProperty::setAccess(Access access) { impl->setAccess(access); }
void SchemaProperty::setIndex(bool val) { impl->setIndex(val); }
@@ -512,8 +562,10 @@ bool SchemaProperty::isIndex() const { return impl->isIndex(); }
bool SchemaProperty::isOptional() const { return impl->isOptional(); }
const char* SchemaProperty::getUnit() const { return impl->getUnit().c_str(); }
const char* SchemaProperty::getDesc() const { return impl->getDesc().c_str(); }
-SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) { impl = new SchemaStatisticImpl(this, name, typecode); }
+
+SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) : impl(new SchemaStatisticImpl(name, typecode)) {}
SchemaStatistic::SchemaStatistic(SchemaStatisticImpl* i) : impl(i) {}
+SchemaStatistic::SchemaStatistic(const SchemaStatistic& from) : impl(new SchemaStatisticImpl(*(from.impl))) {}
SchemaStatistic::~SchemaStatistic() { delete impl; }
void SchemaStatistic::setUnit(const char* val) { impl->setUnit(val); }
void SchemaStatistic::setDesc(const char* desc) { impl->setDesc(desc); }
@@ -521,17 +573,24 @@ const char* SchemaStatistic::getName() const { return impl->getName().c_str(); }
Typecode SchemaStatistic::getType() const { return impl->getType(); }
const char* SchemaStatistic::getUnit() const { return impl->getUnit().c_str(); }
const char* SchemaStatistic::getDesc() const { return impl->getDesc().c_str(); }
+
SchemaClassKey::SchemaClassKey(SchemaClassKeyImpl* i) : impl(i) {}
+SchemaClassKey::SchemaClassKey(const SchemaClassKey& from) : impl(new SchemaClassKeyImpl(*(from.impl))) {}
SchemaClassKey::~SchemaClassKey() { delete impl; }
const char* SchemaClassKey::getPackageName() const { return impl->getPackageName().c_str(); }
const char* SchemaClassKey::getClassName() const { return impl->getClassName().c_str(); }
const uint8_t* SchemaClassKey::getHash() const { return impl->getHash(); }
-SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) { impl = new SchemaObjectClassImpl(this, package, name); }
+const char* SchemaClassKey::asString() const { return impl->str().c_str(); }
+bool SchemaClassKey::operator==(const SchemaClassKey& other) const { return *impl == *(other.impl); }
+bool SchemaClassKey::operator<(const SchemaClassKey& other) const { return *impl < *(other.impl); }
+
+SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) : impl(new SchemaObjectClassImpl(package, name)) {}
SchemaObjectClass::SchemaObjectClass(SchemaObjectClassImpl* i) : impl(i) {}
+SchemaObjectClass::SchemaObjectClass(const SchemaObjectClass& from) : impl(new SchemaObjectClassImpl(*(from.impl))) {}
SchemaObjectClass::~SchemaObjectClass() { delete impl; }
-void SchemaObjectClass::addProperty(const SchemaProperty& property) { impl->addProperty(property); }
-void SchemaObjectClass::addStatistic(const SchemaStatistic& statistic) { impl->addStatistic(statistic); }
-void SchemaObjectClass::addMethod(const SchemaMethod& method) { impl->addMethod(method); }
+void SchemaObjectClass::addProperty(const SchemaProperty* property) { impl->addProperty(property); }
+void SchemaObjectClass::addStatistic(const SchemaStatistic* statistic) { impl->addStatistic(statistic); }
+void SchemaObjectClass::addMethod(const SchemaMethod* method) { impl->addMethod(method); }
const SchemaClassKey* SchemaObjectClass::getClassKey() const { return impl->getClassKey(); }
int SchemaObjectClass::getPropertyCount() const { return impl->getPropertyCount(); }
int SchemaObjectClass::getStatisticCount() const { return impl->getStatisticCount(); }
@@ -539,10 +598,12 @@ int SchemaObjectClass::getMethodCount() const { return impl->getMethodCount(); }
const SchemaProperty* SchemaObjectClass::getProperty(int idx) const { return impl->getProperty(idx); }
const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const { return impl->getStatistic(idx); }
const SchemaMethod* SchemaObjectClass::getMethod(int idx) const { return impl->getMethod(idx); }
-SchemaEventClass::SchemaEventClass(const char* package, const char* name) { impl = new SchemaEventClassImpl(this, package, name); }
+
+SchemaEventClass::SchemaEventClass(const char* package, const char* name) : impl(new SchemaEventClassImpl(package, name)) {}
SchemaEventClass::SchemaEventClass(SchemaEventClassImpl* i) : impl(i) {}
+SchemaEventClass::SchemaEventClass(const SchemaEventClass& from) : impl(new SchemaEventClassImpl(*(from.impl))) {}
SchemaEventClass::~SchemaEventClass() { delete impl; }
-void SchemaEventClass::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaEventClass::addArgument(const SchemaArgument* argument) { impl->addArgument(argument); }
void SchemaEventClass::setDesc(const char* desc) { impl->setDesc(desc); }
const SchemaClassKey* SchemaEventClass::getClassKey() const { return impl->getClassKey(); }
int SchemaEventClass::getArgumentCount() const { return impl->getArgumentCount(); }
diff --git a/qpid/cpp/src/qmf/SchemaImpl.h b/qpid/cpp/src/qmf/engine/SchemaImpl.h
index 035d99aecd..af3a1d98e4 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.h
+++ b/qpid/cpp/src/qmf/engine/SchemaImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfSchemaImpl_
-#define _QmfSchemaImpl_
+#ifndef _QmfEngineSchemaImpl_
+#define _QmfEngineSchemaImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,13 +20,13 @@
* under the License.
*/
-#include "qmf/Schema.h"
-#include <boost/shared_ptr.hpp>
+#include "qmf/engine/Schema.h"
#include <string>
#include <vector>
#include <qpid/framing/Buffer.h>
namespace qmf {
+namespace engine {
// TODO: Destructors for schema classes
// TODO: Add "frozen" attribute for schema classes so they can't be modified after
@@ -52,16 +52,15 @@ namespace qmf {
};
struct SchemaArgumentImpl {
- SchemaArgument* envelope;
std::string name;
Typecode typecode;
Direction dir;
std::string unit;
std::string description;
- SchemaArgumentImpl(SchemaArgument* e, const char* n, Typecode t) :
- envelope(e), name(n), typecode(t), dir(DIR_IN) {}
+ SchemaArgumentImpl(const char* n, Typecode t) : name(n), typecode(t), dir(DIR_IN) {}
SchemaArgumentImpl(qpid::framing::Buffer& buffer);
+ static SchemaArgument* factory(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void setDirection(Direction d) { dir = d; }
void setUnit(const char* val) { unit = val; }
@@ -75,15 +74,15 @@ namespace qmf {
};
struct SchemaMethodImpl {
- SchemaMethod* envelope;
std::string name;
std::string description;
- std::vector<SchemaArgumentImpl*> arguments;
+ std::vector<const SchemaArgument*> arguments;
- SchemaMethodImpl(SchemaMethod* e, const char* n) : envelope(e), name(n) {}
+ SchemaMethodImpl(const char* n) : name(n) {}
SchemaMethodImpl(qpid::framing::Buffer& buffer);
+ static SchemaMethod* factory(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
- void addArgument(const SchemaArgument& argument);
+ void addArgument(const SchemaArgument* argument);
void setDesc(const char* desc) { description = desc; }
const std::string& getName() const { return name; }
const std::string& getDesc() const { return description; }
@@ -93,7 +92,6 @@ namespace qmf {
};
struct SchemaPropertyImpl {
- SchemaProperty* envelope;
std::string name;
Typecode typecode;
Access access;
@@ -102,10 +100,9 @@ namespace qmf {
std::string unit;
std::string description;
- SchemaPropertyImpl(SchemaProperty* e, const char* n, Typecode t) :
- envelope(e), name(n), typecode(t), access(ACCESS_READ_ONLY),
- index(false), optional(false) {}
+ SchemaPropertyImpl(const char* n, Typecode t) : name(n), typecode(t), access(ACCESS_READ_ONLY), index(false), optional(false) {}
SchemaPropertyImpl(qpid::framing::Buffer& buffer);
+ static SchemaProperty* factory(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void setAccess(Access a) { access = a; }
void setIndex(bool val) { index = val; }
@@ -123,15 +120,14 @@ namespace qmf {
};
struct SchemaStatisticImpl {
- SchemaStatistic* envelope;
std::string name;
Typecode typecode;
std::string unit;
std::string description;
- SchemaStatisticImpl(SchemaStatistic* e, const char* n, Typecode t) :
- envelope(e), name(n), typecode(t) {}
+ SchemaStatisticImpl(const char* n, Typecode t) : name(n), typecode(t) {}
SchemaStatisticImpl(qpid::framing::Buffer& buffer);
+ static SchemaStatistic* factory(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void setUnit(const char* val) { unit = val; }
void setDesc(const char* desc) { description = desc; }
@@ -143,10 +139,10 @@ namespace qmf {
};
struct SchemaClassKeyImpl {
- const SchemaClassKey* envelope;
const std::string& package;
const std::string& name;
const SchemaHash& hash;
+ mutable std::string repr;
// The *Container elements are only used if there isn't an external place to
// store these values.
@@ -156,6 +152,8 @@ namespace qmf {
SchemaClassKeyImpl(const std::string& package, const std::string& name, const SchemaHash& hash);
SchemaClassKeyImpl(qpid::framing::Buffer& buffer);
+ static SchemaClassKey* factory(const std::string& package, const std::string& name, const SchemaHash& hash);
+ static SchemaClassKey* factory(qpid::framing::Buffer& buffer);
const std::string& getPackageName() const { return package; }
const std::string& getClassName() const { return name; }
@@ -164,28 +162,28 @@ namespace qmf {
void encode(qpid::framing::Buffer& buffer) const;
bool operator==(const SchemaClassKeyImpl& other) const;
bool operator<(const SchemaClassKeyImpl& other) const;
- std::string str() const;
+ const std::string& str() const;
};
struct SchemaObjectClassImpl {
- typedef boost::shared_ptr<SchemaObjectClassImpl> Ptr;
- SchemaObjectClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
- SchemaClassKeyImpl classKey;
- std::vector<SchemaPropertyImpl*> properties;
- std::vector<SchemaStatisticImpl*> statistics;
- std::vector<SchemaMethodImpl*> methods;
+ std::auto_ptr<SchemaClassKey> classKey;
+ std::vector<const SchemaProperty*> properties;
+ std::vector<const SchemaStatistic*> statistics;
+ std::vector<const SchemaMethod*> methods;
- SchemaObjectClassImpl(SchemaObjectClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
+ SchemaObjectClassImpl(const char* p, const char* n) :
+ package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {}
SchemaObjectClassImpl(qpid::framing::Buffer& buffer);
+ static SchemaObjectClass* factory(qpid::framing::Buffer& buffer);
+
void encode(qpid::framing::Buffer& buffer) const;
- void addProperty(const SchemaProperty& property);
- void addStatistic(const SchemaStatistic& statistic);
- void addMethod(const SchemaMethod& method);
+ void addProperty(const SchemaProperty* property);
+ void addStatistic(const SchemaStatistic* statistic);
+ void addMethod(const SchemaMethod* method);
const SchemaClassKey* getClassKey() const;
int getPropertyCount() const { return properties.size(); }
@@ -197,21 +195,21 @@ namespace qmf {
};
struct SchemaEventClassImpl {
- typedef boost::shared_ptr<SchemaEventClassImpl> Ptr;
- SchemaEventClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
- SchemaClassKeyImpl classKey;
+ std::auto_ptr<SchemaClassKey> classKey;
std::string description;
- std::vector<SchemaArgumentImpl*> arguments;
+ std::vector<const SchemaArgument*> arguments;
- SchemaEventClassImpl(SchemaEventClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
+ SchemaEventClassImpl(const char* p, const char* n) :
+ package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {}
SchemaEventClassImpl(qpid::framing::Buffer& buffer);
+ static SchemaEventClass* factory(qpid::framing::Buffer& buffer);
+
void encode(qpid::framing::Buffer& buffer) const;
- void addArgument(const SchemaArgument& argument);
+ void addArgument(const SchemaArgument* argument);
void setDesc(const char* desc) { description = desc; }
const SchemaClassKey* getClassKey() const;
@@ -219,6 +217,7 @@ namespace qmf {
const SchemaArgument* getArgument(int idx) const;
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/SequenceManager.cpp b/qpid/cpp/src/qmf/engine/SequenceManager.cpp
index 3171e66fac..4a4644a8b9 100644
--- a/qpid/cpp/src/qmf/SequenceManager.cpp
+++ b/qpid/cpp/src/qmf/engine/SequenceManager.cpp
@@ -17,10 +17,10 @@
* under the License.
*/
-#include "qmf/SequenceManager.h"
+#include "qmf/engine/SequenceManager.h"
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using namespace qpid::sys;
SequenceManager::SequenceManager() : nextSequence(1) {}
@@ -68,14 +68,14 @@ void SequenceManager::releaseAll()
contextMap.clear();
}
-void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer)
+void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, const string& routingKey, qpid::framing::Buffer& buffer)
{
Mutex::ScopedLock _lock(lock);
bool done;
if (sequence == 0) {
if (unsolicitedContext.get() != 0) {
- done = unsolicitedContext->handleMessage(opcode, sequence, buffer);
+ done = unsolicitedContext->handleMessage(opcode, sequence, routingKey, buffer);
if (done)
unsolicitedContext->release();
}
@@ -85,7 +85,7 @@ void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, qpid::framing:
map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence);
if (iter != contextMap.end()) {
if (iter->second != 0) {
- done = iter->second->handleMessage(opcode, sequence, buffer);
+ done = iter->second->handleMessage(opcode, sequence, routingKey, buffer);
if (done) {
iter->second->release();
contextMap.erase(iter);
diff --git a/qpid/cpp/src/qmf/SequenceManager.h b/qpid/cpp/src/qmf/engine/SequenceManager.h
index bbfd0728a7..9e47e38610 100644
--- a/qpid/cpp/src/qmf/SequenceManager.h
+++ b/qpid/cpp/src/qmf/engine/SequenceManager.h
@@ -1,5 +1,5 @@
-#ifndef _QmfSequenceManager_
-#define _QmfSequenceManager_
+#ifndef _QmfEngineSequenceManager_
+#define _QmfEngineSequenceManager_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -31,6 +31,7 @@ namespace qpid {
}
namespace qmf {
+namespace engine {
class SequenceContext {
public:
@@ -39,7 +40,7 @@ namespace qmf {
virtual ~SequenceContext() {}
virtual void reserve() = 0;
- virtual bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer) = 0;
+ virtual bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer) = 0;
virtual void release() = 0;
};
@@ -51,7 +52,7 @@ namespace qmf {
uint32_t reserve(SequenceContext::Ptr ctx = SequenceContext::Ptr());
void release(uint32_t sequence);
void releaseAll();
- void dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer);
+ void dispatch(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
private:
mutable qpid::sys::Mutex lock;
@@ -61,6 +62,7 @@ namespace qmf {
};
}
+}
#endif
diff --git a/qpid/cpp/src/qmf/ValueImpl.cpp b/qpid/cpp/src/qmf/engine/ValueImpl.cpp
index f42c85eb33..f80bdab866 100644
--- a/qpid/cpp/src/qmf/ValueImpl.cpp
+++ b/qpid/cpp/src/qmf/engine/ValueImpl.cpp
@@ -17,14 +17,14 @@
* under the License.
*/
-#include "qmf/ValueImpl.h"
+#include "qmf/engine/ValueImpl.h"
#include <qpid/framing/FieldTable.h>
using namespace std;
-using namespace qmf;
+using namespace qmf::engine;
using qpid::framing::Buffer;
-ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typecode(t)
+ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t)
{
uint64_t first;
uint64_t second;
@@ -42,8 +42,8 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typec
case TYPE_BOOL : value.boolVal = (buf.getOctet() != 0); break;
case TYPE_FLOAT : value.floatVal = buf.getFloat(); break;
case TYPE_DOUBLE : value.doubleVal = buf.getDouble(); break;
- case TYPE_INT8 : value.s32 = (int32_t) buf.getOctet(); break;
- case TYPE_INT16 : value.s32 = (int32_t) buf.getShort(); break;
+ case TYPE_INT8 : value.s32 = (int32_t) ((int8_t) buf.getOctet()); break;
+ case TYPE_INT16 : value.s32 = (int32_t) ((int16_t) buf.getShort()); break;
case TYPE_INT32 : value.s32 = (int32_t) buf.getLong(); break;
case TYPE_INT64 : value.s64 = buf.getLongLong(); break;
case TYPE_UUID : buf.getBin128(value.uuidVal); break;
@@ -67,11 +67,27 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typec
}
}
-ValueImpl::ValueImpl(Typecode t) : envelope(new Value(this)), typecode(t)
+ValueImpl::ValueImpl(Typecode t, Typecode at) : typecode(t), valid(false), arrayTypecode(at)
+{
+}
+
+ValueImpl::ValueImpl(Typecode t) : typecode(t)
{
::memset(&value, 0, sizeof(value));
}
+Value* ValueImpl::factory(Typecode t, Buffer& b)
+{
+ ValueImpl* impl(new ValueImpl(t, b));
+ return new Value(impl);
+}
+
+Value* ValueImpl::factory(Typecode t)
+{
+ ValueImpl* impl(new ValueImpl(t));
+ return new Value(impl);
+}
+
ValueImpl::~ValueImpl()
{
}
@@ -113,9 +129,9 @@ bool ValueImpl::keyInMap(const char* key) const
Value* ValueImpl::byKey(const char* key)
{
if (keyInMap(key)) {
- map<std::string, VPtr>::iterator iter = mapVal.find(key);
+ map<std::string, Value>::iterator iter = mapVal.find(key);
if (iter != mapVal.end())
- return iter->second.get();
+ return &iter->second;
}
return 0;
}
@@ -123,9 +139,9 @@ Value* ValueImpl::byKey(const char* key)
const Value* ValueImpl::byKey(const char* key) const
{
if (keyInMap(key)) {
- map<std::string, VPtr>::const_iterator iter = mapVal.find(key);
+ map<std::string, Value>::const_iterator iter = mapVal.find(key);
if (iter != mapVal.end())
- return iter->second.get();
+ return &iter->second;
}
return 0;
}
@@ -137,12 +153,13 @@ void ValueImpl::deleteKey(const char* key)
void ValueImpl::insert(const char* key, Value* val)
{
- mapVal[key] = VPtr(val);
+ pair<string, Value> entry(key, *val);
+ mapVal.insert(entry);
}
const char* ValueImpl::key(uint32_t idx) const
{
- map<std::string, VPtr>::const_iterator iter = mapVal.begin();
+ map<std::string, Value>::const_iterator iter = mapVal.begin();
for (uint32_t i = 0; i < idx; i++) {
if (iter == mapVal.end())
break;
@@ -186,293 +203,64 @@ void ValueImpl::deleteArrayItem(uint32_t)
// Wrappers
//==================================================================
-Value::Value(Typecode t, Typecode at)
-{
- impl = new ValueImpl(this, t, at);
-}
-
-Value::Value(ValueImpl* i)
-{
- impl = i;
-}
-
-Value::~Value()
-{
- delete impl;
-}
-
-Typecode Value::getType() const
-{
- return impl->getType();
-}
-
-bool Value::isNull() const
-{
- return impl->isNull();
-}
-
-void Value::setNull()
-{
- impl->setNull();
-}
-
-bool Value::isObjectId() const
-{
- return impl->isObjectId();
-}
-
-const ObjectId& Value::asObjectId() const
-{
- return impl->asObjectId();
-}
-
-void Value::setObjectId(const ObjectId& oid)
-{
- impl->setObjectId(oid);
-}
-
-bool Value::isUint() const
-{
- return impl->isUint();
-}
-
-uint32_t Value::asUint() const
-{
- return impl->asUint();
-}
-
-void Value::setUint(uint32_t val)
-{
- impl->setUint(val);
-}
-
-bool Value::isInt() const
-{
- return impl->isInt();
-}
-
-int32_t Value::asInt() const
-{
- return impl->asInt();
-}
-
-void Value::setInt(int32_t val)
-{
- impl->setInt(val);
-}
-
-bool Value::isUint64() const
-{
- return impl->isUint64();
-}
-
-uint64_t Value::asUint64() const
-{
- return impl->asUint64();
-}
-
-void Value::setUint64(uint64_t val)
-{
- impl->setUint64(val);
-}
-
-bool Value::isInt64() const
-{
- return impl->isInt64();
-}
-
-int64_t Value::asInt64() const
-{
- return impl->asInt64();
-}
-
-void Value::setInt64(int64_t val)
-{
- impl->setInt64(val);
-}
-
-bool Value::isString() const
-{
- return impl->isString();
-}
-
-const char* Value::asString() const
-{
- return impl->asString();
-}
-
-void Value::setString(const char* val)
-{
- impl->setString(val);
-}
-
-bool Value::isBool() const
-{
- return impl->isBool();
-}
-
-bool Value::asBool() const
-{
- return impl->asBool();
-}
-
-void Value::setBool(bool val)
-{
- impl->setBool(val);
-}
-
-bool Value::isFloat() const
-{
- return impl->isFloat();
-}
-
-float Value::asFloat() const
-{
- return impl->asFloat();
-}
-
-void Value::setFloat(float val)
-{
- impl->setFloat(val);
-}
-
-bool Value::isDouble() const
-{
- return impl->isDouble();
-}
-
-double Value::asDouble() const
-{
- return impl->asDouble();
-}
-
-void Value::setDouble(double val)
-{
- impl->setDouble(val);
-}
-
-bool Value::isUuid() const
-{
- return impl->isUuid();
-}
-
-const uint8_t* Value::asUuid() const
-{
- return impl->asUuid();
-}
-
-void Value::setUuid(const uint8_t* val)
-{
- impl->setUuid(val);
-}
-
-bool Value::isObject() const
-{
- return impl->isObject();
-}
-
-Object* Value::asObject() const
-{
- return impl->asObject();
-}
-
-void Value::setObject(Object* val)
-{
- impl->setObject(val);
-}
-
-bool Value::isMap() const
-{
- return impl->isMap();
-}
-
-bool Value::keyInMap(const char* key) const
-{
- return impl->keyInMap(key);
-}
-
-Value* Value::byKey(const char* key)
-{
- return impl->byKey(key);
-}
-
-const Value* Value::byKey(const char* key) const
-{
- return impl->byKey(key);
-}
-
-void Value::deleteKey(const char* key)
-{
- impl->deleteKey(key);
-}
-
-void Value::insert(const char* key, Value* val)
-{
- impl->insert(key, val);
-}
-
-uint32_t Value::keyCount() const
-{
- return impl->keyCount();
-}
-
-const char* Value::key(uint32_t idx) const
-{
- return impl->key(idx);
-}
-
-bool Value::isList() const
-{
- return impl->isList();
-}
-
-uint32_t Value::listItemCount() const
-{
- return impl->listItemCount();
-}
-
-Value* Value::listItem(uint32_t idx)
-{
- return impl->listItem(idx);
-}
-
-void Value::appendToList(Value* val)
-{
- impl->appendToList(val);
-}
-
-void Value::deleteListItem(uint32_t idx)
-{
- impl->deleteListItem(idx);
-}
-
-bool Value::isArray() const
-{
- return impl->isArray();
-}
-
-Typecode Value::arrayType() const
-{
- return impl->arrayType();
-}
-
-uint32_t Value::arrayItemCount() const
-{
- return impl->arrayItemCount();
-}
-
-Value* Value::arrayItem(uint32_t idx)
-{
- return impl->arrayItem(idx);
-}
-
-void Value::appendToArray(Value* val)
-{
- impl->appendToArray(val);
-}
-
-void Value::deleteArrayItem(uint32_t idx)
-{
- impl->deleteArrayItem(idx);
-}
+Value::Value(const Value& from) : impl(new ValueImpl(*(from.impl))) {}
+Value::Value(Typecode t, Typecode at) : impl(new ValueImpl(t, at)) {}
+Value::Value(ValueImpl* i) : impl(i) {}
+Value::~Value() { delete impl;}
+
+Typecode Value::getType() const { return impl->getType(); }
+bool Value::isNull() const { return impl->isNull(); }
+void Value::setNull() { impl->setNull(); }
+bool Value::isObjectId() const { return impl->isObjectId(); }
+const ObjectId& Value::asObjectId() const { return impl->asObjectId(); }
+void Value::setObjectId(const ObjectId& oid) { impl->setObjectId(oid); }
+bool Value::isUint() const { return impl->isUint(); }
+uint32_t Value::asUint() const { return impl->asUint(); }
+void Value::setUint(uint32_t val) { impl->setUint(val); }
+bool Value::isInt() const { return impl->isInt(); }
+int32_t Value::asInt() const { return impl->asInt(); }
+void Value::setInt(int32_t val) { impl->setInt(val); }
+bool Value::isUint64() const { return impl->isUint64(); }
+uint64_t Value::asUint64() const { return impl->asUint64(); }
+void Value::setUint64(uint64_t val) { impl->setUint64(val); }
+bool Value::isInt64() const { return impl->isInt64(); }
+int64_t Value::asInt64() const { return impl->asInt64(); }
+void Value::setInt64(int64_t val) { impl->setInt64(val); }
+bool Value::isString() const { return impl->isString(); }
+const char* Value::asString() const { return impl->asString(); }
+void Value::setString(const char* val) { impl->setString(val); }
+bool Value::isBool() const { return impl->isBool(); }
+bool Value::asBool() const { return impl->asBool(); }
+void Value::setBool(bool val) { impl->setBool(val); }
+bool Value::isFloat() const { return impl->isFloat(); }
+float Value::asFloat() const { return impl->asFloat(); }
+void Value::setFloat(float val) { impl->setFloat(val); }
+bool Value::isDouble() const { return impl->isDouble(); }
+double Value::asDouble() const { return impl->asDouble(); }
+void Value::setDouble(double val) { impl->setDouble(val); }
+bool Value::isUuid() const { return impl->isUuid(); }
+const uint8_t* Value::asUuid() const { return impl->asUuid(); }
+void Value::setUuid(const uint8_t* val) { impl->setUuid(val); }
+bool Value::isObject() const { return impl->isObject(); }
+const Object* Value::asObject() const { return impl->asObject(); }
+void Value::setObject(Object* val) { impl->setObject(val); }
+bool Value::isMap() const { return impl->isMap(); }
+bool Value::keyInMap(const char* key) const { return impl->keyInMap(key); }
+Value* Value::byKey(const char* key) { return impl->byKey(key); }
+const Value* Value::byKey(const char* key) const { return impl->byKey(key); }
+void Value::deleteKey(const char* key) { impl->deleteKey(key); }
+void Value::insert(const char* key, Value* val) { impl->insert(key, val); }
+uint32_t Value::keyCount() const { return impl->keyCount(); }
+const char* Value::key(uint32_t idx) const { return impl->key(idx); }
+bool Value::isList() const { return impl->isList(); }
+uint32_t Value::listItemCount() const { return impl->listItemCount(); }
+Value* Value::listItem(uint32_t idx) { return impl->listItem(idx); }
+void Value::appendToList(Value* val) { impl->appendToList(val); }
+void Value::deleteListItem(uint32_t idx) { impl->deleteListItem(idx); }
+bool Value::isArray() const { return impl->isArray(); }
+Typecode Value::arrayType() const { return impl->arrayType(); }
+uint32_t Value::arrayItemCount() const { return impl->arrayItemCount(); }
+Value* Value::arrayItem(uint32_t idx) { return impl->arrayItem(idx); }
+void Value::appendToArray(Value* val) { impl->appendToArray(val); }
+void Value::deleteArrayItem(uint32_t idx) { impl->deleteArrayItem(idx); }
diff --git a/qpid/cpp/src/qmf/ValueImpl.h b/qpid/cpp/src/qmf/engine/ValueImpl.h
index cf33035bf7..b6adae5d93 100644
--- a/qpid/cpp/src/qmf/ValueImpl.h
+++ b/qpid/cpp/src/qmf/engine/ValueImpl.h
@@ -1,5 +1,5 @@
-#ifndef _QmfValueImpl_
-#define _QmfValueImpl_
+#ifndef _QmfEngineValueImpl_
+#define _QmfEngineValueImpl_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,9 +20,9 @@
* under the License.
*/
-#include <qmf/Value.h>
-#include <qmf/ObjectIdImpl.h>
-#include <qmf/Object.h>
+#include <qmf/engine/Value.h>
+#include <qmf/engine/ObjectIdImpl.h>
+#include <qmf/engine/Object.h>
#include <qpid/framing/Buffer.h>
#include <string>
#include <string.h>
@@ -31,22 +31,20 @@
#include <boost/shared_ptr.hpp>
namespace qmf {
+namespace engine {
// TODO: set valid flag on all value settors
// TODO: add a modified flag and accessors
struct ValueImpl {
- typedef boost::shared_ptr<Value> VPtr;
- typedef boost::shared_ptr<Object> OPtr;
- Value* envelope;
const Typecode typecode;
bool valid;
ObjectId refVal;
std::string stringVal;
- OPtr objectVal;
- std::map<std::string, VPtr> mapVal;
- std::vector<VPtr> vectorVal;
+ std::auto_ptr<Object> objectVal;
+ std::map<std::string, Value> mapVal;
+ std::vector<Value> vectorVal;
Typecode arrayTypecode;
union {
@@ -60,10 +58,17 @@ namespace qmf {
uint8_t uuidVal[16];
} value;
- ValueImpl(Value* e, Typecode t, Typecode at) :
- envelope(e), typecode(t), valid(false), arrayTypecode(at) {}
+ ValueImpl(const ValueImpl& from) :
+ typecode(from.typecode), valid(from.valid), refVal(from.refVal), stringVal(from.stringVal),
+ objectVal(from.objectVal.get() ? new Object(*(from.objectVal)) : 0),
+ mapVal(from.mapVal), vectorVal(from.vectorVal), arrayTypecode(from.arrayTypecode),
+ value(from.value) {}
+
+ ValueImpl(Typecode t, Typecode at);
ValueImpl(Typecode t, qpid::framing::Buffer& b);
ValueImpl(Typecode t);
+ static Value* factory(Typecode t, qpid::framing::Buffer& b);
+ static Value* factory(Typecode t);
~ValueImpl();
void encode(qpid::framing::Buffer& b) const;
@@ -139,6 +144,7 @@ namespace qmf {
void deleteArrayItem(uint32_t idx);
};
}
+}
#endif
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index 81519c3311..5d7a028736 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -18,7 +18,8 @@
#include "qpid/acl/AclData.h"
#include "qpid/log/Statement.h"
-
+#include "qpid/sys/IntegerTypes.h"
+#include <boost/lexical_cast.hpp>
namespace qpid {
namespace acl {
@@ -57,14 +58,15 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj
const std::string& name, std::map<Property, std::string>* params) {
QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
- << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name
- << " with params " << AclHelper::propertyMapToString(params));
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name
+ << " with params " << AclHelper::propertyMapToString(params));
AclResult aclresult = decisionMode;
if (actionList[action] && actionList[action][objType]) {
AclData::actObjItr itrRule = actionList[action][objType]->find(id);
if (itrRule == actionList[action][objType]->end())
itrRule = actionList[action][objType]->find("*");
+
if (itrRule != actionList[action][objType]->end()) {
QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
@@ -79,25 +81,48 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj
if (pMItr->first == acl::PROP_NAME) {
if (matchProp(pMItr->second, name)){
QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
- << pMItr->second << "' given in the rule");
- }else{
+ << pMItr->second << "' given in the rule");
+ }else{
match = false;
QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
- << pMItr->second << "' given in the rule");
+ << pMItr->second << "' given in the rule");
}
} else if (params) { //match pMItr against params
propertyMapItr paramItr = params->find(pMItr->first);
if (paramItr == params->end()) {
match = false;
QPID_LOG(debug, "ACL: the given parameter map in lookup doesn't contain the property '"
- << AclHelper::getPropertyStr(pMItr->first) << "'");
- } else if (!matchProp(pMItr->second, paramItr->second)) {
+ << AclHelper::getPropertyStr(pMItr->first) << "'");
+ }else if ( pMItr->first == acl::PROP_MAXQUEUECOUNT || pMItr->first == acl::PROP_MAXQUEUESIZE ) {
+ if ( pMItr->first == paramItr->first ) {
+ uint64_t aclMax = boost::lexical_cast<uint64_t>(pMItr->second);
+ uint64_t paramMax = boost::lexical_cast<uint64_t>(paramItr->second);
+ QPID_LOG(debug, "ACL: Numeric comparison for property " <<
+ AclHelper::getPropertyStr(paramItr->first) <<
+ " (value given in lookup = " <<
+ boost::lexical_cast<std::string>(paramItr->second) <<
+ ", value give in rule = " <<
+ boost::lexical_cast<std::string>(pMItr->second) << " )");
+ if (( aclMax ) && ( paramMax == 0 || paramMax > aclMax)){
+ match = decisionMode == qpid::acl::ALLOW ;
+ QPID_LOG(debug, "ACL: Limit exceeded and match=" <<
+ (match ? "true": "false") <<
+ " as decision mode is " << AclHelper::getAclResultStr(decisionMode));
+ }
+ }
+ }else if (matchProp(pMItr->second, paramItr->second)) {
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
+ << ") given in lookup matched the pair("
+ << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
+ } else {
QPID_LOG(debug, "ACL: the pair("
- << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
- << ") given in lookup doesn't match the pair("
- << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
+ << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
+ << ") given in lookup doesn't match the pair("
+ << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
match = false;
- }
+
+ }
}
}
if (match)
@@ -116,37 +141,63 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj
AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey)
{
- AclResult aclresult = decisionMode;
+
+ QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " exchange name:" << name
+ << " with routing key " << RoutingKey);
+
+ AclResult aclresult = decisionMode;
- if (actionList[action] && actionList[action][objType]){
- AclData::actObjItr itrRule = actionList[action][objType]->find(id);
- if (itrRule == actionList[action][objType]->end())
+ if (actionList[action] && actionList[action][objType]){
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+
+ if (itrRule == actionList[action][objType]->end())
itrRule = actionList[action][objType]->find("*");
+
if (itrRule != actionList[action][objType]->end() ) {
+ QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
+
//loop the vector
- for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
-
+ for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
+ QPID_LOG(debug, "ACL: checking rule " << i->toString());
+
// loop the names looking for match
bool match =true;
for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
{
- //match name is exists first
+ //match name is exists first
if (pMItr->first == acl::PROP_NAME){
- if (!matchProp(pMItr->second, name)){
- match= false;
- }
+ if (matchProp(pMItr->second, name)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
+ << pMItr->second << "' given in the rule");
+
+ }else{
+ match= false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
+ << pMItr->second << "' given in the rule");
+ }
}else if (pMItr->first == acl::PROP_ROUTINGKEY){
- if (!matchProp(pMItr->second, RoutingKey)){
- match= false;
- }
+ if (matchProp(pMItr->second, RoutingKey)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with routing_key '"
+ << pMItr->second << "' given in the rule");
+ }else{
+ match= false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with routing_key '"
+ << pMItr->second << "' given in the rule");
+ }
}
}
- if (match) return getACLResult(i->logOnly, i->log);
- }
+ if (match){
+ aclresult = getACLResult(i->logOnly, i->log);
+ QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+ }
+ }
}
- }
- return aclresult;
+ }
+ QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
}
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index 093e9cea32..f9f39316e2 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -78,7 +78,7 @@ ManagementAgent* ManagementAgent::Singleton::getInstance()
const string ManagementAgentImpl::storeMagicNumber("MA02");
ManagementAgentImpl::ManagementAgentImpl() :
- interval(10), extThread(false),
+ interval(10), extThread(false), pipeHandle(0),
initialized(false), connected(false), lastFailure("never connected"),
clientWasAdded(true), requestedBrokerBank(0), requestedAgentBank(0),
assignedBrokerBank(0), assignedAgentBank(0), bootSequence(0),
@@ -89,13 +89,12 @@ ManagementAgentImpl::ManagementAgentImpl() :
ManagementAgentImpl::~ManagementAgentImpl()
{
+ // shutdown & cleanup all threads
connThreadBody.close();
+ pubThreadBody.close();
- // If the thread is doing work on the connection, we must wait for it to
- // complete before shutting down.
- if (!connThreadBody.isSleeping()) {
- connThread.join();
- }
+ connThread.join();
+ pubThread.join();
// Release the memory associated with stored management objects.
{
@@ -777,6 +776,7 @@ void ManagementAgentImpl::ConnectionThread::run()
static const int delayFactor(2);
int delay(delayMin);
string dest("qmfagent");
+ ConnectionThread::shared_ptr tmp;
sessionId.generate();
queueName << "qmfagent-" << sessionId;
@@ -787,7 +787,7 @@ void ManagementAgentImpl::ConnectionThread::run()
QPID_LOG(debug, "QMF Agent attempting to connect to the broker...");
connection.open(agent.connectionSettings);
session = connection.newSession(queueName.str());
- subscriptions = new client::SubscriptionManager(session);
+ subscriptions.reset(new client::SubscriptionManager(session));
session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true,
arg::exclusive=true);
@@ -811,11 +811,12 @@ void ManagementAgentImpl::ConnectionThread::run()
operational = false;
agent.connected = false;
+ tmp = subscriptions;
+ subscriptions.reset();
}
+ tmp.reset(); // frees the subscription outside the lock
delay = delayMin;
connection.close();
- delete subscriptions;
- subscriptions = 0;
}
} catch (exception &e) {
if (delay < delayMax)
@@ -824,14 +825,19 @@ void ManagementAgentImpl::ConnectionThread::run()
}
{
+ // sleep for "delay" seconds, but peridically check if the
+ // agent is shutting down so we don't hang for up to delayMax
+ // seconds during agent shutdown
Mutex::ScopedLock _lock(connLock);
if (shutdown)
return;
sleeping = true;
- {
- Mutex::ScopedUnlock _unlock(connLock);
- ::sleep(delay);
- }
+ int totalSleep = 0;
+ do {
+ Mutex::ScopedUnlock _unlock(connLock);
+ ::sleep(delayMin);
+ totalSleep += delayMin;
+ } while (totalSleep < delay && !shutdown);
sleeping = false;
if (shutdown)
return;
@@ -848,10 +854,12 @@ void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf,
const string& exchange,
const string& routingKey)
{
+ ConnectionThread::shared_ptr s;
{
Mutex::ScopedLock _lock(connLock);
if (!operational)
return;
+ s = subscriptions;
}
Message msg;
@@ -866,8 +874,8 @@ void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf,
} catch(exception& e) {
QPID_LOG(error, "Exception caught in sendBuffer: " << e.what());
// Bounce the connection
- if (subscriptions)
- subscriptions->stop();
+ if (s)
+ s->stop();
}
}
@@ -881,12 +889,14 @@ void ManagementAgentImpl::ConnectionThread::bindToBank(uint32_t brokerBank, uint
void ManagementAgentImpl::ConnectionThread::close()
{
+ ConnectionThread::shared_ptr s;
{
Mutex::ScopedLock _lock(connLock);
shutdown = true;
+ s = subscriptions;
}
- if (subscriptions)
- subscriptions->stop();
+ if (s)
+ s->stop();
}
bool ManagementAgentImpl::ConnectionThread::isSleeping() const
@@ -898,8 +908,13 @@ bool ManagementAgentImpl::ConnectionThread::isSleeping() const
void ManagementAgentImpl::PublishThread::run()
{
- while (true) {
+ uint16_t totalSleep;
+
+ while (!shutdown) {
agent.periodicProcessing();
- ::sleep(agent.getInterval());
+ totalSleep = 0;
+ while (totalSleep++ < agent.getInterval() && !shutdown) {
+ ::sleep(1);
+ }
}
}
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
index f9cad9ebf5..a876496e98 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
@@ -163,12 +163,14 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
friend class ConnectionThread;
class ConnectionThread : public sys::Runnable
{
+ typedef boost::shared_ptr<client::SubscriptionManager> shared_ptr;
+
bool operational;
ManagementAgentImpl& agent;
framing::Uuid sessionId;
client::Connection connection;
client::Session session;
- client::SubscriptionManager* subscriptions;
+ ConnectionThread::shared_ptr subscriptions;
std::stringstream queueName;
mutable sys::Mutex connLock;
bool shutdown;
@@ -176,7 +178,7 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
void run();
public:
ConnectionThread(ManagementAgentImpl& _agent) :
- operational(false), agent(_agent), subscriptions(0),
+ operational(false), agent(_agent),
shutdown(false), sleeping(false) {}
~ConnectionThread();
void sendBuffer(qpid::framing::Buffer& buf,
@@ -192,8 +194,11 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
{
ManagementAgentImpl& agent;
void run();
+ bool shutdown;
public:
- PublishThread(ManagementAgentImpl& _agent) : agent(_agent) {}
+ PublishThread(ManagementAgentImpl& _agent) :
+ agent(_agent), shutdown(false) {}
+ void close() { shutdown = true; }
};
ConnectionThread connThreadBody;
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp b/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
index 96d5146c30..bf2e7d5713 100644
--- a/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
+++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp
@@ -31,7 +31,7 @@ namespace amqp_0_10 {
using sys::Mutex;
Connection::Connection(sys::OutputControl& o, const std::string& id, bool _isClient)
- : frameQueueClosed(false), output(o), identifier(id), initialized(false),
+ : pushClosed(false), popClosed(false), output(o), identifier(id), initialized(false),
isClient(_isClient), buffered(0), version(0,10)
{}
@@ -61,19 +61,23 @@ size_t Connection::decode(const char* buffer, size_t size) {
}
bool Connection::canEncode() {
- if (!frameQueueClosed) connection->doOutput();
Mutex::ScopedLock l(frameQueueLock);
- return (!isClient && !initialized) || !frameQueue.empty();
+ if (!popClosed) {
+ Mutex::ScopedUnlock u(frameQueueLock);
+ connection->doOutput();
+ }
+ return !popClosed && ((!isClient && !initialized) || !frameQueue.empty());
}
bool Connection::isClosed() const {
Mutex::ScopedLock l(frameQueueLock);
- return frameQueueClosed;
+ return pushClosed && popClosed;
}
size_t Connection::encode(const char* buffer, size_t size) {
{ // Swap frameQueue data into workQueue to avoid holding lock while we encode.
Mutex::ScopedLock l(frameQueueLock);
+ if (popClosed) return 0; // Can't pop any more frames.
assert(workQueue.empty());
workQueue.swap(frameQueue);
}
@@ -102,6 +106,8 @@ size_t Connection::encode(const char* buffer, size_t size) {
// Put back any frames we did not encode.
frameQueue.insert(frameQueue.begin(), workQueue.begin(), workQueue.end());
workQueue.clear();
+ if (frameQueue.empty() && pushClosed)
+ popClosed = true;
}
return out.getPosition();
}
@@ -111,9 +117,10 @@ void Connection::activateOutput() { output.activateOutput(); }
void Connection::giveReadCredit(int32_t credit) { output.giveReadCredit(credit); }
void Connection::close() {
- // Close the output queue.
+ // No more frames can be pushed onto the queue.
+ // Frames aleady on the queue can be popped.
Mutex::ScopedLock l(frameQueueLock);
- frameQueueClosed = true;
+ pushClosed = true;
}
void Connection::closed() {
@@ -123,7 +130,7 @@ void Connection::closed() {
void Connection::send(framing::AMQFrame& f) {
{
Mutex::ScopedLock l(frameQueueLock);
- if (!frameQueueClosed)
+ if (!pushClosed)
frameQueue.push_back(f);
buffered += f.encodedSize();
}
diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.h b/qpid/cpp/src/qpid/amqp_0_10/Connection.h
index 6fd51381fc..995d824796 100644
--- a/qpid/cpp/src/qpid/amqp_0_10/Connection.h
+++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.h
@@ -47,7 +47,7 @@ class Connection : public sys::ConnectionCodec,
FrameQueue frameQueue;
FrameQueue workQueue;
- bool frameQueueClosed;
+ bool pushClosed, popClosed;
mutable sys::Mutex frameQueueLock;
sys::OutputControl& output;
std::auto_ptr<sys::ConnectionInputHandler> connection;
diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h
index 536fa21b2b..2f4f7eaacc 100644
--- a/qpid/cpp/src/qpid/broker/AclModule.h
+++ b/qpid/cpp/src/qpid/broker/AclModule.h
@@ -40,7 +40,8 @@ enum Action {ACT_CONSUME, ACT_PUBLISH, ACT_CREATE, ACT_ACCESS, ACT_BIND,
enum Property {PROP_NAME, PROP_DURABLE, PROP_OWNER, PROP_ROUTINGKEY,
PROP_PASSIVE, PROP_AUTODELETE, PROP_EXCLUSIVE, PROP_TYPE,
PROP_ALTERNATE, PROP_QUEUENAME, PROP_SCHEMAPACKAGE,
- PROP_SCHEMACLASS};
+ PROP_SCHEMACLASS, PROP_POLICYTYPE, PROP_MAXQUEUESIZE,
+ PROP_MAXQUEUECOUNT};
enum AclResult {ALLOW, ALLOWLOG, DENY, DENYLOG};
} // namespace acl
@@ -132,6 +133,9 @@ class AclHelper {
if (str.compare("queuename") == 0) return PROP_QUEUENAME;
if (str.compare("schemapackage") == 0) return PROP_SCHEMAPACKAGE;
if (str.compare("schemaclass") == 0) return PROP_SCHEMACLASS;
+ if (str.compare("policytype") == 0) return PROP_POLICYTYPE;
+ if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE;
+ if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT;
throw str;
}
static inline std::string getPropertyStr(const Property p) {
@@ -148,6 +152,9 @@ class AclHelper {
case PROP_QUEUENAME: return "queuename";
case PROP_SCHEMAPACKAGE: return "schemapackage";
case PROP_SCHEMACLASS: return "schemaclass";
+ case PROP_POLICYTYPE: return "policytype";
+ case PROP_MAXQUEUESIZE: return "maxqueuesize";
+ case PROP_MAXQUEUECOUNT: return "maxqueuecount";
default: assert(false); // should never get here
}
return "";
@@ -217,11 +224,14 @@ class AclHelper {
// == Queues ==
propSetPtr p4(new propSet);
- p3->insert(PROP_ALTERNATE);
- p3->insert(PROP_PASSIVE);
- p3->insert(PROP_DURABLE);
- p3->insert(PROP_EXCLUSIVE);
- p3->insert(PROP_AUTODELETE);
+ p4->insert(PROP_ALTERNATE);
+ p4->insert(PROP_PASSIVE);
+ p4->insert(PROP_DURABLE);
+ p4->insert(PROP_EXCLUSIVE);
+ p4->insert(PROP_AUTODELETE);
+ p4->insert(PROP_POLICYTYPE);
+ p4->insert(PROP_MAXQUEUESIZE);
+ p4->insert(PROP_MAXQUEUECOUNT);
actionMapPtr a1(new actionMap);
a1->insert(actionPair(ACT_ACCESS, p0));
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index 13cf88fb11..4259bb2f31 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -91,7 +91,8 @@ Broker::Options::Options(const std::string& name) :
queueLimit(100*1048576/*100M default limit*/),
tcpNoDelay(false),
requireEncrypted(false),
- maxSessionRate(0)
+ maxSessionRate(0),
+ asyncQueueEvents(true)
{
int c = sys::SystemInfo::concurrency();
workerThreads=c+1;
@@ -121,7 +122,8 @@ Broker::Options::Options(const std::string& name) :
("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections")
("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted")
("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)")
- ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)");
+ ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)")
+ ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication");
}
const std::string empty;
@@ -150,7 +152,7 @@ Broker::Broker(const Broker::Options& conf) :
*this),
managementAgent(conf.enableMgmt ? new ManagementAgent() : 0),
queueCleaner(queues, timer),
- queueEvents(poller),
+ queueEvents(poller,!conf.asyncQueueEvents),
recovery(true),
expiryPolicy(new ExpiryPolicy),
getKnownBrokers(boost::bind(&Broker::getKnownBrokersImpl, this))
@@ -208,8 +210,10 @@ Broker::Broker(const Broker::Options& conf) :
(*i)->earlyInitialize(*this);
// If no plugin store module registered itself, set up the null store.
- if (store.get() == 0)
- setStore (new NullMessageStore());
+ if (store.get() == 0) {
+ boost::shared_ptr<MessageStore> p(new NullMessageStore());
+ setStore (p);
+ }
exchanges.declare(empty, DirectExchange::typeName); // Default exchange.
@@ -296,7 +300,7 @@ boost::intrusive_ptr<Broker> Broker::create(const Options& opts)
return boost::intrusive_ptr<Broker>(new Broker(opts));
}
-void Broker::setStore (MessageStore* _store)
+void Broker::setStore (boost::shared_ptr<MessageStore>& _store)
{
store.reset(new MessageStoreModule (_store));
queues.setStore (store.get());
diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h
index 0517ceca95..5ca01e0867 100644
--- a/qpid/cpp/src/qpid/broker/Broker.h
+++ b/qpid/cpp/src/qpid/broker/Broker.h
@@ -111,6 +111,7 @@ public:
bool requireEncrypted;
std::string knownHosts;
uint32_t maxSessionRate;
+ bool asyncQueueEvents;
private:
std::string getHome();
@@ -171,7 +172,7 @@ public:
/** Shut down the broker */
virtual void shutdown();
- QPID_BROKER_EXTERN void setStore (MessageStore*);
+ QPID_BROKER_EXTERN void setStore (boost::shared_ptr<MessageStore>& store);
MessageStore& getStore() { return *store; }
void setAcl (AclModule* _acl) {acl = _acl;}
AclModule* getAcl() { return acl; }
diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.cpp b/qpid/cpp/src/qpid/broker/DirectExchange.cpp
index b9f24dee5f..29fe47beac 100644
--- a/qpid/cpp/src/qpid/broker/DirectExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/DirectExchange.cpp
@@ -145,39 +145,12 @@ bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, c
void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
{
PreRoute pr(msg, this);
- Queues::ConstPtr p;
+ ConstBindingList b;
{
Mutex::ScopedLock l(lock);
- p = bindings[routingKey].queues.snapshot();
- }
- int count(0);
-
- if (p) {
- for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++, count++) {
- msg.deliverTo((*i)->queue);
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched();
- }
- }
-
- if(!count){
- QPID_LOG(info, "DirectExchange " << getName() << " could not route message with key " << routingKey
- << "; no matching binding found");
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- } else {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes(count);
- mgmtExchange->inc_byteRoutes(count * msg.contentSize());
- }
- }
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives();
- mgmtExchange->inc_byteReceives(msg.contentSize());
+ b = bindings[routingKey].queues.snapshot();
}
+ doRoute(msg, b);
}
diff --git a/qpid/cpp/src/qpid/broker/DtxAck.cpp b/qpid/cpp/src/qpid/broker/DtxAck.cpp
index b189ef4cdb..bca3f90bbe 100644
--- a/qpid/cpp/src/qpid/broker/DtxAck.cpp
+++ b/qpid/cpp/src/qpid/broker/DtxAck.cpp
@@ -48,12 +48,26 @@ bool DtxAck::prepare(TransactionContext* ctxt) throw()
void DtxAck::commit() throw()
{
- for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed));
- pending.clear();
+ try {
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed));
+ pending.clear();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
+ }
+
}
void DtxAck::rollback() throw()
{
- for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
- pending.clear();
+ try {
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
+ pending.clear();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to complete rollback: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to complete rollback (unknown error)");
+ }
+
}
diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp
index 90d81b81c6..757127eef2 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.cpp
+++ b/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -76,6 +76,40 @@ Exchange::PreRoute::~PreRoute(){
}
}
+void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
+{
+ int count = 0;
+
+ if (b.get()) {
+ // Block the content release if the message is transient AND there is more than one binding
+ if (!msg.getMessage().isPersistent() && b->size() > 1)
+ msg.getMessage().blockContentRelease();
+
+ for(std::vector<Binding::shared_ptr>::const_iterator i = b->begin(); i != b->end(); i++, count++) {
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched();
+ }
+ }
+
+ if (mgmtExchange != 0)
+ {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (count == 0)
+ {
+ //QPID_LOG(warning, "Exchange " << getName() << " could not route message; no matching binding found");
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ else
+ {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+}
+
void Exchange::routeIVE(){
if (ive && lastMsg.get()){
DeliverableMessage dmsg(lastMsg);
diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h
index c1e878200f..9bea376c28 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.h
+++ b/qpid/cpp/src/qpid/broker/Exchange.h
@@ -79,6 +79,9 @@ protected:
Exchange* parent;
};
+ typedef boost::shared_ptr<const std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > ConstBindingList;
+ typedef boost::shared_ptr< std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > BindingList;
+ void doRoute(Deliverable& msg, ConstBindingList b);
void routeIVE();
diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
index e9007ba682..b7d46a33fe 100644
--- a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp
@@ -106,36 +106,12 @@ bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, cons
return true;
}
-void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){
+void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/)
+{
PreRoute pr(msg, this);
- uint32_t count(0);
-
- BindingsArray::ConstPtr p = bindings.snapshot();
- if (p.get()){
- for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i, count++){
- msg.deliverTo((*i)->queue);
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched ();
- }
- }
-
- if (mgmtExchange != 0)
- {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- if (count == 0)
- {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- else
- {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
+ doRoute(msg, bindings.snapshot());
}
-
+
bool FanOutExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const)
{
BindingsArray::ConstPtr ptr = bindings.snapshot();
diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
index c628c44909..a7c90156e1 100644
--- a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -104,7 +104,8 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey,
}
-void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){
+void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args)
+{
if (!args) {
//can't match if there were no headers passed in
if (mgmtExchange != 0) {
@@ -118,31 +119,17 @@ void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, cons
PreRoute pr(msg, this);
- uint32_t count(0);
-
- Bindings::ConstPtr p = bindings.snapshot();
- if (p.get()){
+ ConstBindingList p = bindings.snapshot();
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ if (p.get())
+ {
for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) {
if (match((*i)->args, *args)) {
- msg.deliverTo((*i)->queue);
- count++;
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched();
+ b->push_back(*i);
}
}
}
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives();
- mgmtExchange->inc_byteReceives(msg.contentSize());
- if (count == 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- } else {
- mgmtExchange->inc_msgRoutes(count);
- mgmtExchange->inc_byteRoutes(count * msg.contentSize());
- }
- }
+ doRoute(msg, b);
}
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index 7360010192..e2799b0bff 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -49,7 +49,7 @@ TransferAdapter Message::TRANSFER;
Message::Message(const framing::SequenceNumber& id) :
frames(id), persistenceId(0), redelivered(false), loaded(false),
staged(false), forcePersistentPolicy(false), publisher(0), adapter(0),
- expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0) {}
+ expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0), requiredCredit(0) {}
Message::~Message()
{
@@ -98,7 +98,7 @@ const FieldTable* Message::getApplicationHeaders() const
return getAdapter().getApplicationHeaders(frames);
}
-bool Message::isPersistent()
+bool Message::isPersistent() const
{
return (getAdapter().isPersistent(frames) || forcePersistentPolicy);
}
@@ -108,12 +108,16 @@ bool Message::requiresAccept()
return getAdapter().requiresAccept(frames);
}
-uint32_t Message::getRequiredCredit() const
+uint32_t Message::getRequiredCredit()
{
- //add up payload for all header and content frames in the frameset
- SumBodySize sum;
- frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
- return sum.getSize();
+ sys::Mutex::ScopedLock l(lock);
+ if (!requiredCredit) {
+ //add up payload for all header and content frames in the frameset
+ SumBodySize sum;
+ frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
+ requiredCredit = sum.getSize();
+ }
+ return requiredCredit;
}
void Message::encode(framing::Buffer& buffer) const
@@ -181,17 +185,31 @@ void Message::decodeContent(framing::Buffer& buffer)
loaded = true;
}
-void Message::releaseContent(MessageStore* _store)
+void Message::tryReleaseContent()
{
- if (!store) {
- store = _store;
+ if (checkContentReleasable()) {
+ releaseContent();
}
+}
+
+void Message::releaseContent(MessageStore* s)
+{
+ //deprecated, use setStore(store); releaseContent(); instead
+ if (!store) setStore(s);
+ releaseContent();
+}
+
+void Message::releaseContent()
+{
+ sys::Mutex::ScopedLock l(lock);
if (store) {
if (!getPersistenceId()) {
intrusive_ptr<PersistableMessage> pmsg(this);
store->stage(pmsg);
staged = true;
}
+ //ensure required credit is cached before content frames are released
+ getRequiredCredit();
//remove any content frames from the frameset
frames.remove(TypeFilter<CONTENT_BODY>());
setContentReleased();
@@ -211,31 +229,29 @@ void Message::destroy()
bool Message::getContentFrame(const Queue& queue, AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const
{
- if (isContentReleased()) {
- intrusive_ptr<const PersistableMessage> pmsg(this);
-
- bool done = false;
- string& data = frame.castBody<AMQContentBody>()->getData();
- store->loadContent(queue, pmsg, data, offset, maxContentSize);
- done = data.size() < maxContentSize;
- frame.setBof(false);
- frame.setEof(true);
- QPID_LOG(debug, "loaded frame" << frame);
- if (offset > 0) {
- frame.setBos(false);
- }
- if (!done) {
- frame.setEos(false);
- } else return false;
- return true;
+ intrusive_ptr<const PersistableMessage> pmsg(this);
+
+ bool done = false;
+ string& data = frame.castBody<AMQContentBody>()->getData();
+ store->loadContent(queue, pmsg, data, offset, maxContentSize);
+ done = data.size() < maxContentSize;
+ frame.setBof(false);
+ frame.setEof(true);
+ QPID_LOG(debug, "loaded frame" << frame);
+ if (offset > 0) {
+ frame.setBos(false);
}
- else return false;
+ if (!done) {
+ frame.setEos(false);
+ } else return false;
+ return true;
}
void Message::sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const
{
+ sys::Mutex::ScopedLock l(lock);
if (isContentReleased() && !frames.isComplete()) {
-
+ sys::Mutex::ScopedUnlock u(lock);
uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
bool morecontent = true;
for (uint64_t offset = 0; morecontent; offset += maxContentSize)
@@ -373,28 +389,36 @@ void Message::setReplacementMessage(boost::intrusive_ptr<Message> msg, const Que
}
void Message::allEnqueuesComplete() {
- MessageCallback* cb = 0;
- {
- sys::Mutex::ScopedLock l(lock);
- std::swap(cb, enqueueCallback);
- }
+ sys::Mutex::ScopedLock l(callbackLock);
+ MessageCallback* cb = enqueueCallback;
if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
}
void Message::allDequeuesComplete() {
- MessageCallback* cb = 0;
- {
- sys::Mutex::ScopedLock l(lock);
- std::swap(cb, dequeueCallback);
- }
+ sys::Mutex::ScopedLock l(callbackLock);
+ MessageCallback* cb = dequeueCallback;
if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
}
-void Message::setEnqueueCompleteCallback(MessageCallback& cb) { enqueueCallback = &cb; }
-void Message::resetEnqueueCompleteCallback() { enqueueCallback = 0; }
+void Message::setEnqueueCompleteCallback(MessageCallback& cb) {
+ sys::Mutex::ScopedLock l(callbackLock);
+ enqueueCallback = &cb;
+}
+
+void Message::resetEnqueueCompleteCallback() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ enqueueCallback = 0;
+}
-void Message::setDequeueCompleteCallback(MessageCallback& cb) { dequeueCallback = &cb; }
-void Message::resetDequeueCompleteCallback() { dequeueCallback = 0; }
+void Message::setDequeueCompleteCallback(MessageCallback& cb) {
+ sys::Mutex::ScopedLock l(callbackLock);
+ dequeueCallback = &cb;
+}
+
+void Message::resetDequeueCompleteCallback() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ dequeueCallback = 0;
+}
framing::FieldTable& Message::getOrInsertHeaders()
{
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index e4d09b1042..3894960c95 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -74,7 +74,7 @@ public:
bool isImmediate() const;
QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const;
framing::FieldTable& getOrInsertHeaders();
- QPID_BROKER_EXTERN bool isPersistent();
+ QPID_BROKER_EXTERN bool isPersistent() const;
bool requiresAccept();
QPID_BROKER_EXTERN void setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e);
@@ -108,7 +108,7 @@ public:
return frames.isA<T>();
}
- uint32_t getRequiredCredit() const;
+ uint32_t getRequiredCredit();
void encode(framing::Buffer& buffer) const;
void encodeContent(framing::Buffer& buffer) const;
@@ -129,12 +129,9 @@ public:
QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer);
QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer);
- /**
- * Releases the in-memory content data held by this
- * message. Must pass in a store from which the data can
- * be reloaded.
- */
- void releaseContent(MessageStore* store);
+ void QPID_BROKER_EXTERN tryReleaseContent();
+ void releaseContent();
+ void releaseContent(MessageStore* s);//deprecated, use 'setStore(store); releaseContent();' instead
void destroy();
bool getContentFrame(const Queue& queue, framing::AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const;
@@ -187,8 +184,12 @@ public:
mutable Replacement replacement;
mutable boost::intrusive_ptr<Message> empty;
+
+ sys::Mutex callbackLock;
MessageCallback* enqueueCallback;
MessageCallback* dequeueCallback;
+
+ uint32_t requiredCredit;
static std::string updateDestination;
};
diff --git a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
index 14b233fd6c..b1a2b77b05 100644
--- a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
+++ b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -80,7 +80,7 @@ void MessageBuilder::handle(AMQFrame& frame)
&& !NullMessageStore::isNullStore(store)
&& message->getExchangeName() != QPID_MANAGEMENT /* don't stage mgnt messages */)
{
- message->releaseContent(store);
+ message->releaseContent();
staging = true;
}
}
@@ -96,6 +96,7 @@ void MessageBuilder::end()
void MessageBuilder::start(const SequenceNumber& id)
{
message = intrusive_ptr<Message>(new Message(id));
+ message->setStore(store);
state = METHOD;
staging = false;
}
diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
index 0b8a5db1c7..5f7cceebd3 100644
--- a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
+++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp
@@ -32,11 +32,11 @@ using qpid::framing::FieldTable;
namespace qpid {
namespace broker {
-MessageStoreModule::MessageStoreModule(MessageStore* _store) : store(_store) {}
+MessageStoreModule::MessageStoreModule(boost::shared_ptr<MessageStore>& _store)
+ : store(_store) {}
MessageStoreModule::~MessageStoreModule()
{
- delete store;
}
bool MessageStoreModule::init(const Options*) { return true; }
@@ -173,7 +173,7 @@ void MessageStoreModule::collectPreparedXids(std::set<std::string>& xids)
bool MessageStoreModule::isNull() const
{
- return NullMessageStore::isNullStore(store);
+ return NullMessageStore::isNullStore(store.get());
}
}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.h b/qpid/cpp/src/qpid/broker/MessageStoreModule.h
index 02cbd13cf1..56b5a3c1ae 100644
--- a/qpid/cpp/src/qpid/broker/MessageStoreModule.h
+++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.h
@@ -26,6 +26,7 @@
#include "qpid/broker/RecoveryManager.h"
#include <boost/intrusive_ptr.hpp>
+#include <boost/shared_ptr.hpp>
namespace qpid {
namespace broker {
@@ -35,9 +36,9 @@ namespace broker {
*/
class MessageStoreModule : public MessageStore
{
- MessageStore* store;
+ boost::shared_ptr<MessageStore> store;
public:
- MessageStoreModule(MessageStore* store);
+ MessageStoreModule(boost::shared_ptr<MessageStore>& store);
bool init(const Options* options);
void truncateInit(const bool pushDownStoreFiles = false);
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
index 2ef223aa81..303a0501f4 100644
--- a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
@@ -36,7 +36,6 @@ PersistableMessage::~PersistableMessage() {}
PersistableMessage::PersistableMessage() :
asyncEnqueueCounter(0),
asyncDequeueCounter(0),
- contentReleased(false),
store(0)
{}
@@ -59,9 +58,15 @@ void PersistableMessage::flush()
}
}
-void PersistableMessage::setContentReleased() {contentReleased = true; }
+void PersistableMessage::setContentReleased()
+{
+ contentReleaseState.released = true;
+}
-bool PersistableMessage::isContentReleased()const { return contentReleased; }
+bool PersistableMessage::isContentReleased() const
+{
+ return contentReleaseState.released;
+}
bool PersistableMessage::isEnqueueComplete() {
sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
@@ -153,6 +158,26 @@ void PersistableMessage::dequeueAsync() {
asyncDequeueCounter++;
}
+PersistableMessage::ContentReleaseState::ContentReleaseState() : blocked(false), requested(false), released(false) {}
+
+void PersistableMessage::setStore(MessageStore* s)
+{
+ store = s;
+}
+
+void PersistableMessage::requestContentRelease()
+{
+ contentReleaseState.requested = true;
+}
+void PersistableMessage::blockContentRelease()
+{
+ contentReleaseState.blocked = true;
+}
+bool PersistableMessage::checkContentReleasable()
+{
+ return contentReleaseState.requested && !contentReleaseState.blocked;
+}
+
}}
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h
index 0274b41375..2576e266d2 100644
--- a/qpid/cpp/src/qpid/broker/PersistableMessage.h
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h
@@ -68,8 +68,16 @@ class PersistableMessage : public Persistable
void enqueueAsync();
void dequeueAsync();
- bool contentReleased;
syncList synclist;
+ struct ContentReleaseState
+ {
+ bool blocked;
+ bool requested;
+ bool released;
+
+ ContentReleaseState();
+ };
+ ContentReleaseState contentReleaseState;
protected:
/** Called when all enqueues are complete for this message. */
@@ -96,8 +104,15 @@ class PersistableMessage : public Persistable
void flush();
- bool isContentReleased() const;
-
+ bool QPID_BROKER_EXTERN isContentReleased() const;
+
+ void QPID_BROKER_EXTERN setStore(MessageStore*);
+ void requestContentRelease();
+ void blockContentRelease();
+ bool checkContentReleasable();
+
+ virtual QPID_BROKER_EXTERN bool isPersistent() const = 0;
+
QPID_BROKER_EXTERN bool isEnqueueComplete();
QPID_BROKER_EXTERN void enqueueComplete();
diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp
index b2a8e223c5..86de96468d 100644
--- a/qpid/cpp/src/qpid/broker/Queue.cpp
+++ b/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -181,6 +181,8 @@ void Queue::deliver(boost::intrusive_ptr<Message>& msg){
void Queue::recover(boost::intrusive_ptr<Message>& msg){
+ if (policy.get()) policy->recoverEnqueued(msg);
+
push(msg, true);
if (store){
// setup synclist for recovered messages, so they don't get re-stored on lastNodeFailure
@@ -206,11 +208,10 @@ void Queue::process(boost::intrusive_ptr<Message>& msg){
}
void Queue::requeue(const QueuedMessage& msg){
- if (!isEnqueued(msg)) return;
-
QueueListeners::NotificationSet copy;
{
Mutex::ScopedLock locker(messageLock);
+ if (!isEnqueued(msg)) return;
msg.payload->enqueueComplete(); // mark the message as enqueued
messages.push_front(msg);
listeners.populate(copy);
@@ -563,16 +564,10 @@ void Queue::popMsg(QueuedMessage& qmsg)
}
void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
- Messages dequeues;
QueueListeners::NotificationSet copy;
{
Mutex::ScopedLock locker(messageLock);
QueuedMessage qm(this, msg, ++sequence);
- if (policy.get()) {
- policy->tryEnqueue(qm);
- //depending on policy, may have some dequeues
- if (!isRecovery) pendingDequeues.swap(dequeues);
- }
if (insertSeqNo) msg->getOrInsertHeaders().setInt64(seqNoKey, sequence);
LVQ::iterator i;
@@ -606,12 +601,11 @@ void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
if (eventMgr) eventMgr->enqueued(qm);
else QPID_LOG(warning, "Enqueue manager not set, events not generated for " << getName());
}
+ if (policy.get()) {
+ policy->enqueued(qm);
+ }
}
copy.notify();
- if (!dequeues.empty()) {
- //depending on policy, may have some dequeues
- for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
- }
}
QueuedMessage Queue::getFront()
@@ -697,8 +691,19 @@ void Queue::setLastNodeFailure()
}
// return true if store exists,
-bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck)
{
+ if (policy.get() && !suppressPolicyCheck) {
+ Messages dequeues;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ policy->tryEnqueue(msg);
+ policy->getPendingDequeues(dequeues);
+ }
+ //depending on policy, may have some dequeues that need to performed without holding the lock
+ for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
+ }
+
if (inLastNodeFailure && persistLastNode){
msg->forcePersistent();
}
@@ -707,15 +712,27 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
msg->addTraceId(traceId);
}
- if (msg->isPersistent() && store) {
+ if ((msg->isPersistent() || msg->checkContentReleasable()) && store) {
msg->enqueueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg);
store->enqueue(ctxt, pmsg, *this);
return true;
}
+ if (!store) {
+ //Messages enqueued on a transient queue should be prevented
+ //from having their content released as it may not be
+ //recoverable by these queue for delivery
+ msg->blockContentRelease();
+ }
return false;
}
+void Queue::enqueueAborted(boost::intrusive_ptr<Message> msg)
+{
+ Mutex::ScopedLock locker(messageLock);
+ if (policy.get()) policy->enqueueAborted(msg);
+}
+
// return true if store exists,
bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
{
@@ -726,7 +743,7 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
dequeued(msg);
}
}
- if (msg.payload->isPersistent() && store) {
+ if ((msg.payload->isPersistent() || msg.payload->checkContentReleasable()) && store) {
msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload);
store->dequeue(ctxt, pmsg, *this);
@@ -781,22 +798,37 @@ void Queue::create(const FieldTable& _settings)
void Queue::configure(const FieldTable& _settings, bool recovering)
{
- setPolicy(QueuePolicy::createQueuePolicy(_settings));
+
+ eventMode = _settings.getAsInt(qpidQueueEventGeneration);
+
+ if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK &&
+ (!store || NullMessageStore::isNullStore(store) || (eventMode && eventMgr && !eventMgr->isSync()) )) {
+ if ( NullMessageStore::isNullStore(store)) {
+ QPID_LOG(warning, "Flow to disk not valid for non-persisted queue:" << getName());
+ } else if (eventMgr && !eventMgr->isSync() ) {
+ QPID_LOG(warning, "Flow to disk not valid with async Queue Events:" << getName());
+ }
+ FieldTable copy(_settings);
+ copy.erase(QueuePolicy::typeKey);
+ setPolicy(QueuePolicy::createQueuePolicy(getName(), copy));
+ } else {
+ setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings));
+ }
//set this regardless of owner to allow use of no-local with exclusive consumers also
noLocal = _settings.get(qpidNoLocal);
- QPID_LOG(debug, "Configured queue with no-local=" << noLocal);
+ QPID_LOG(debug, "Configured queue " << getName() << " with no-local=" << noLocal);
lastValueQueue= _settings.get(qpidLastValueQueue);
- if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue");
+ if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue for: " << getName());
lastValueQueueNoBrowse = _settings.get(qpidLastValueQueueNoBrowse);
if (lastValueQueueNoBrowse){
- QPID_LOG(debug, "Configured queue as Last Value Queue No Browse");
+ QPID_LOG(debug, "Configured queue as Last Value Queue No Browse for: " << getName());
lastValueQueue = lastValueQueueNoBrowse;
}
persistLastNode= _settings.get(qpidPersistLastNode);
- if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node");
+ if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node for: " << getName());
traceId = _settings.getAsString(qpidTraceIdentity);
std::string excludeList = _settings.getAsString(qpidTraceExclude);
@@ -806,8 +838,6 @@ void Queue::configure(const FieldTable& _settings, bool recovering)
QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId
<< "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements");
- eventMode = _settings.getAsInt(qpidQueueEventGeneration);
-
FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers);
if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>());
@@ -975,19 +1005,6 @@ void Queue::setExternalQueueStore(ExternalQueueStore* inst) {
}
}
-bool Queue::releaseMessageContent(const QueuedMessage& m)
-{
- if (store && !NullMessageStore::isNullStore(store)) {
- QPID_LOG(debug, "Message " << m.position << " on " << name << " released from memory");
- m.payload->releaseContent(store);
- return true;
- } else {
- QPID_LOG(warning, "Message " << m.position << " on " << name
- << " cannot be released from memory as the queue is not durable");
- return false;
- }
-}
-
ManagementObject* Queue::GetManagementObject (void) const
{
return (ManagementObject*) mgmtObject;
@@ -1044,11 +1061,12 @@ void Queue::insertSequenceNumbers(const std::string& key)
void Queue::enqueued(const QueuedMessage& m)
{
if (m.payload) {
- if (policy.get()) policy->tryEnqueue(m);
- mgntEnqStats(m.payload);
- if (m.payload->isPersistent()) {
- enqueue ( 0, m.payload );
+ if (policy.get()) {
+ policy->recoverEnqueued(m.payload);
+ policy->enqueued(m);
}
+ mgntEnqStats(m.payload);
+ enqueue ( 0, m.payload, true );
} else {
QPID_LOG(warning, "Queue informed of enqueued message that has no payload");
}
@@ -1059,10 +1077,4 @@ bool Queue::isEnqueued(const QueuedMessage& msg)
return !policy.get() || policy->isEnqueued(msg);
}
-void Queue::addPendingDequeue(const QueuedMessage& msg)
-{
- //assumes lock is held - true at present but rather nasty as this is a public method
- pendingDequeues.push_back(msg);
-}
-
QueueListeners& Queue::getListeners() { return listeners; }
diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h
index 77799fd967..661e46f619 100644
--- a/qpid/cpp/src/qpid/broker/Queue.h
+++ b/qpid/cpp/src/qpid/broker/Queue.h
@@ -239,7 +239,8 @@ namespace qpid {
QPID_BROKER_EXTERN void setLastNodeFailure();
QPID_BROKER_EXTERN void clearLastNodeFailure();
- bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck = false);
+ void enqueueAborted(boost::intrusive_ptr<Message> msg);
/**
* dequeue from store (only done once messages is acknowledged)
*/
@@ -315,8 +316,6 @@ namespace qpid {
bindings.eachBinding(f);
}
- bool releaseMessageContent(const QueuedMessage&);
-
void popMsg(QueuedMessage& qmsg);
/** Set the position sequence number for the next message on the queue.
@@ -335,18 +334,6 @@ namespace qpid {
*/
void recoveryComplete();
- /**
- * This is a hack to avoid deadlocks in durable ring
- * queues. It is used for dequeueing messages in response
- * to an enqueue while avoid holding lock over call to
- * store.
- *
- * Assumes messageLock is held - true for curent use case
- * (QueuePolicy::tryEnqueue()) but rather nasty as this is a public
- * method
- **/
- void addPendingDequeue(const QueuedMessage &msg);
-
// For cluster update
QueueListeners& getListeners();
};
diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.cpp b/qpid/cpp/src/qpid/broker/QueueEvents.cpp
index 6df869673d..bba054b0b8 100644
--- a/qpid/cpp/src/qpid/broker/QueueEvents.cpp
+++ b/qpid/cpp/src/qpid/broker/QueueEvents.cpp
@@ -25,25 +25,41 @@
namespace qpid {
namespace broker {
-QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller) :
- eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true)
+QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync) :
+ eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true), sync(isSync)
{
- eventQueue.start();
+ if (!sync) eventQueue.start();
}
QueueEvents::~QueueEvents()
{
- eventQueue.stop();
+ if (!sync) eventQueue.stop();
}
void QueueEvents::enqueued(const QueuedMessage& m)
{
- if (enabled) eventQueue.push(Event(ENQUEUE, m));
+ if (enabled) {
+ Event enq(ENQUEUE, m);
+ if (sync) {
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
+ j->second(enq);
+ } else {
+ eventQueue.push(enq);
+ }
+ }
}
void QueueEvents::dequeued(const QueuedMessage& m)
{
- if (enabled) eventQueue.push(Event(DEQUEUE, m));
+ if (enabled) {
+ Event deq(DEQUEUE, m);
+ if (sync) {
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
+ j->second(deq);
+ } else {
+ eventQueue.push(Event(DEQUEUE, m));
+ }
+ }
}
void QueueEvents::registerListener(const std::string& id, const EventListener& listener)
@@ -70,15 +86,16 @@ QueueEvents::EventQueue::Batch::const_iterator
QueueEvents::handle(const EventQueue::Batch& events) {
qpid::sys::Mutex::ScopedLock l(lock);
for (EventQueue::Batch::const_iterator i = events.begin(); i != events.end(); ++i) {
- for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
- j->second(*i);
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) {
+ j->second(*i);
+ }
}
return events.end();
}
void QueueEvents::shutdown()
{
- if (!eventQueue.empty() && !listeners.empty()) eventQueue.shutdown();
+ if (!sync && !eventQueue.empty() && !listeners.empty()) eventQueue.shutdown();
}
void QueueEvents::enable()
@@ -93,6 +110,12 @@ void QueueEvents::disable()
QPID_LOG(debug, "Queue events disabled");
}
+bool QueueEvents::isSync()
+{
+ return sync;
+}
+
+
QueueEvents::Event::Event(EventType t, const QueuedMessage& m) : type(t), msg(m) {}
diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.h b/qpid/cpp/src/qpid/broker/QueueEvents.h
index 6826c6e79a..c42752133e 100644
--- a/qpid/cpp/src/qpid/broker/QueueEvents.h
+++ b/qpid/cpp/src/qpid/broker/QueueEvents.h
@@ -54,7 +54,7 @@ class QueueEvents
typedef boost::function<void (Event)> EventListener;
- QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller);
+ QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync = false);
QPID_BROKER_EXTERN ~QueueEvents();
QPID_BROKER_EXTERN void enqueued(const QueuedMessage&);
QPID_BROKER_EXTERN void dequeued(const QueuedMessage&);
@@ -65,6 +65,7 @@ class QueueEvents
void disable();
//process all outstanding events
QPID_BROKER_EXTERN void shutdown();
+ QPID_BROKER_EXTERN bool isSync();
private:
typedef qpid::sys::PollableQueue<Event> EventQueue;
typedef std::map<std::string, EventListener> Listeners;
@@ -73,6 +74,7 @@ class QueueEvents
Listeners listeners;
volatile bool enabled;
qpid::sys::Mutex lock;//protect listeners from concurrent access
+ bool sync;
EventQueue::Batch::const_iterator handle(const EventQueue::Batch& e);
diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
index 39afe90134..a8aa674c53 100644
--- a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
+++ b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
@@ -28,8 +28,8 @@
using namespace qpid::broker;
using namespace qpid::framing;
-QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
- maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false) {}
+QueuePolicy::QueuePolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false), name(_name) {}
void QueuePolicy::enqueued(uint64_t _size)
{
@@ -39,18 +39,15 @@ void QueuePolicy::enqueued(uint64_t _size)
void QueuePolicy::dequeued(uint64_t _size)
{
- //Note: underflow detection is not reliable in the face of
- //concurrent updates (at present locking in Queue.cpp prevents
- //these anyway); updates are atomic and are safe regardless.
if (maxCount) {
- if (count.get() > 0) {
+ if (count > 0) {
--count;
} else {
throw Exception(QPID_MSG("Attempted count underflow on dequeue(" << _size << "): " << *this));
}
}
if (maxSize) {
- if (_size > size.get()) {
+ if (_size > size) {
throw Exception(QPID_MSG("Attempted size underflow on dequeue(" << _size << "): " << *this));
} else {
size -= _size;
@@ -58,47 +55,47 @@ void QueuePolicy::dequeued(uint64_t _size)
}
}
-bool QueuePolicy::checkLimit(const QueuedMessage& m)
+bool QueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
{
- bool sizeExceeded = maxSize && (size.get() + m.payload->contentSize()) > maxSize;
- bool countExceeded = maxCount && (count.get() + 1) > maxCount;
+ bool sizeExceeded = maxSize && (size + m->contentSize()) > maxSize;
+ bool countExceeded = maxCount && (count + 1) > maxCount;
bool exceeded = sizeExceeded || countExceeded;
if (exceeded) {
if (!policyExceeded) {
- policyExceeded = true;
- if (m.queue) {
- if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << m.queue->getName());
- if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << m.queue->getName());
- }
+ policyExceeded = true;
+ if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << name);
+ if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << name);
}
} else {
if (policyExceeded) {
policyExceeded = false;
- if (m.queue) {
- QPID_LOG(info, "Queue cumulative message size and message count within policy for " << m.queue->getName());
- }
+ QPID_LOG(info, "Queue cumulative message size and message count within policy for " << name);
}
}
return !exceeded;
}
-void QueuePolicy::tryEnqueue(const QueuedMessage& m)
+void QueuePolicy::tryEnqueue(boost::intrusive_ptr<Message> m)
{
if (checkLimit(m)) {
- enqueued(m);
+ enqueued(m->contentSize());
} else {
- std::string queue = m.queue ? m.queue->getName() : std::string("unknown queue");
- throw ResourceLimitExceededException(
- QPID_MSG("Policy exceeded on " << queue << " by message " << m.position
- << " of size " << m.payload->contentSize() << " , policy: " << *this));
+ throw ResourceLimitExceededException(QPID_MSG("Policy exceeded on " << name << ", policy: " << *this));
}
}
-void QueuePolicy::enqueued(const QueuedMessage& m)
+void QueuePolicy::recoverEnqueued(boost::intrusive_ptr<Message> m)
{
- enqueued(m.payload->contentSize());
+ enqueued(m->contentSize());
}
+void QueuePolicy::enqueueAborted(boost::intrusive_ptr<Message> m)
+{
+ dequeued(m->contentSize());
+}
+
+void QueuePolicy::enqueued(const QueuedMessage&) {}
+
void QueuePolicy::dequeued(const QueuedMessage& m)
{
dequeued(m.payload->contentSize());
@@ -132,7 +129,7 @@ std::string QueuePolicy::getType(const FieldTable& settings)
std::transform(t.begin(), t.end(), t.begin(), tolower);
if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t;
}
- return FLOW_TO_DISK;
+ return REJECT;
}
void QueuePolicy::setDefaultMaxSize(uint64_t s)
@@ -140,6 +137,7 @@ void QueuePolicy::setDefaultMaxSize(uint64_t s)
defaultMaxSize = s;
}
+void QueuePolicy::getPendingDequeues(Messages&) {}
@@ -148,8 +146,8 @@ void QueuePolicy::encode(Buffer& buffer) const
{
buffer.putLong(maxCount);
buffer.putLongLong(maxSize);
- buffer.putLong(count.get());
- buffer.putLongLong(size.get());
+ buffer.putLong(count);
+ buffer.putLongLong(size);
}
void QueuePolicy::decode ( Buffer& buffer )
@@ -179,16 +177,18 @@ const std::string QueuePolicy::RING("ring");
const std::string QueuePolicy::RING_STRICT("ring_strict");
uint64_t QueuePolicy::defaultMaxSize(0);
-FlowToDiskPolicy::FlowToDiskPolicy(uint32_t _maxCount, uint64_t _maxSize) :
- QueuePolicy(_maxCount, _maxSize, FLOW_TO_DISK) {}
+FlowToDiskPolicy::FlowToDiskPolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize) :
+ QueuePolicy(_name, _maxCount, _maxSize, FLOW_TO_DISK) {}
-bool FlowToDiskPolicy::checkLimit(const QueuedMessage& m)
+bool FlowToDiskPolicy::checkLimit(boost::intrusive_ptr<Message> m)
{
- return QueuePolicy::checkLimit(m) || m.queue->releaseMessageContent(m);
+ if (!QueuePolicy::checkLimit(m)) m->requestContentRelease();
+ return true;
}
-RingQueuePolicy::RingQueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
- QueuePolicy(_maxCount, _maxSize, _type), strict(_type == RING_STRICT) {}
+RingQueuePolicy::RingQueuePolicy(const std::string& _name,
+ uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ QueuePolicy(_name, _maxCount, _maxSize, _type), strict(_type == RING_STRICT) {}
bool before(const QueuedMessage& a, const QueuedMessage& b)
{
@@ -197,15 +197,12 @@ bool before(const QueuedMessage& a, const QueuedMessage& b)
void RingQueuePolicy::enqueued(const QueuedMessage& m)
{
- QueuePolicy::enqueued(m);
- qpid::sys::Mutex::ScopedLock l(lock);
//need to insert in correct location based on position
queue.insert(lower_bound(queue.begin(), queue.end(), m, before), m);
}
void RingQueuePolicy::dequeued(const QueuedMessage& m)
{
- qpid::sys::Mutex::ScopedLock l(lock);
//find and remove m from queue
if (find(m, pendingDequeues, true) || find(m, queue, true)) {
//now update count and size
@@ -215,49 +212,32 @@ void RingQueuePolicy::dequeued(const QueuedMessage& m)
bool RingQueuePolicy::isEnqueued(const QueuedMessage& m)
{
- qpid::sys::Mutex::ScopedLock l(lock);
//for non-strict ring policy, a message can be replaced (and
//therefore dequeued) before it is accepted or released by
//subscriber; need to detect this
return find(m, pendingDequeues, false) || find(m, queue, false);
}
-bool RingQueuePolicy::checkLimit(const QueuedMessage& m)
+bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
{
if (QueuePolicy::checkLimit(m)) return true;//if haven't hit limit, ok to accept
QueuedMessage oldest;
- {
- qpid::sys::Mutex::ScopedLock l(lock);
- if (queue.empty()) {
- QPID_LOG(debug, "Message too large for ring queue "
- << (m.queue ? m.queue->getName() : std::string("unknown queue"))
- << " [" << *this << "] "
- << ": message size = " << m.payload->contentSize() << " bytes");
- return false;
- }
- oldest = queue.front();
+ if (queue.empty()) {
+ QPID_LOG(debug, "Message too large for ring queue " << name
+ << " [" << *this << "] "
+ << ": message size = " << m->contentSize() << " bytes");
+ return false;
}
+ oldest = queue.front();
if (oldest.queue->acquire(oldest) || !strict) {
- {
- //TODO: fix this! In the current code, this method is
- //only ever called with the Queue lock already taken. This
- //should not be relied upon going forward however and
- //clearly the locking in this class is insufficient as
- //there is no guarantee that the message previously atthe
- //front is still there.
- qpid::sys::Mutex::ScopedLock l(lock);
- queue.pop_front();
- pendingDequeues.push_back(oldest);
- }
- oldest.queue->addPendingDequeue(oldest);
- QPID_LOG(debug, "Ring policy triggered in queue "
- << (m.queue ? m.queue->getName() : std::string("unknown queue"))
- << ": removed message " << oldest.position << " to make way for " << m.position);
+ queue.pop_front();
+ pendingDequeues.push_back(oldest);
+ QPID_LOG(debug, "Ring policy triggered in " << name
+ << ": removed message " << oldest.position << " to make way for new message");
return true;
} else {
- QPID_LOG(debug, "Ring policy could not be triggered in queue "
- << (m.queue ? m.queue->getName() : std::string("unknown queue"))
+ QPID_LOG(debug, "Ring policy could not be triggered in " << name
<< ": oldest message (seq-no=" << oldest.position << ") has been delivered but not yet acknowledged or requeued");
//in strict mode, if oldest message has been delivered (hence
//cannot be acquired) but not yet acked, it should not be
@@ -266,6 +246,11 @@ bool RingQueuePolicy::checkLimit(const QueuedMessage& m)
}
}
+void RingQueuePolicy::getPendingDequeues(Messages& result)
+{
+ result = pendingDequeues;
+}
+
bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove)
{
for (Messages::iterator i = q.begin(); i != q.end(); i++) {
@@ -277,25 +262,36 @@ bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove)
return false;
}
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type)
+{
+ return createQueuePolicy("<unspecified>", maxCount, maxSize, type);
+}
+
std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::FieldTable& settings)
{
+ return createQueuePolicy("<unspecified>", settings);
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings)
+{
uint32_t maxCount = getInt(settings, maxCountKey, 0);
uint32_t maxSize = getInt(settings, maxSizeKey, defaultMaxSize);
if (maxCount || maxSize) {
- return createQueuePolicy(maxCount, maxSize, getType(settings));
+ return createQueuePolicy(name, maxCount, maxSize, getType(settings));
} else {
return std::auto_ptr<QueuePolicy>();
}
}
-std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type)
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name,
+ uint32_t maxCount, uint64_t maxSize, const std::string& type)
{
if (type == RING || type == RING_STRICT) {
- return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(maxCount, maxSize, type));
+ return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(name, maxCount, maxSize, type));
} else if (type == FLOW_TO_DISK) {
- return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(maxCount, maxSize));
+ return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(name, maxCount, maxSize));
} else {
- return std::auto_ptr<QueuePolicy>(new QueuePolicy(maxCount, maxSize, type));
+ return std::auto_ptr<QueuePolicy>(new QueuePolicy(name, maxCount, maxSize, type));
}
}
@@ -305,10 +301,10 @@ namespace qpid {
std::ostream& operator<<(std::ostream& out, const QueuePolicy& p)
{
- if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size.get();
+ if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size;
else out << "size: unlimited";
out << "; ";
- if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count.get();
+ if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count;
else out << "count: unlimited";
out << "; type=" << p.type;
return out;
diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.h b/qpid/cpp/src/qpid/broker/QueuePolicy.h
index 54745876d5..b2937e94c7 100644
--- a/qpid/cpp/src/qpid/broker/QueuePolicy.h
+++ b/qpid/cpp/src/qpid/broker/QueuePolicy.h
@@ -40,14 +40,14 @@ class QueuePolicy
uint32_t maxCount;
uint64_t maxSize;
const std::string type;
- qpid::sys::AtomicValue<uint32_t> count;
- qpid::sys::AtomicValue<uint64_t> size;
+ uint32_t count;
+ uint64_t size;
bool policyExceeded;
static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
- static std::string getType(const qpid::framing::FieldTable& settings);
public:
+ typedef std::deque<QueuedMessage> Messages;
static QPID_BROKER_EXTERN const std::string maxCountKey;
static QPID_BROKER_EXTERN const std::string maxSizeKey;
static QPID_BROKER_EXTERN const std::string typeKey;
@@ -57,27 +57,34 @@ class QueuePolicy
static QPID_BROKER_EXTERN const std::string RING_STRICT;
virtual ~QueuePolicy() {}
- QPID_BROKER_EXTERN void tryEnqueue(const QueuedMessage&);
+ QPID_BROKER_EXTERN void tryEnqueue(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN void recoverEnqueued(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN void enqueueAborted(boost::intrusive_ptr<Message> msg);
+ virtual void enqueued(const QueuedMessage&);
virtual void dequeued(const QueuedMessage&);
virtual bool isEnqueued(const QueuedMessage&);
- virtual bool checkLimit(const QueuedMessage&);
QPID_BROKER_EXTERN void update(qpid::framing::FieldTable& settings);
uint32_t getMaxCount() const { return maxCount; }
uint64_t getMaxSize() const { return maxSize; }
void encode(framing::Buffer& buffer) const;
void decode ( framing::Buffer& buffer );
uint32_t encodedSize() const;
+ virtual void getPendingDequeues(Messages& result);
-
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings);
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings);
static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+ static std::string getType(const qpid::framing::FieldTable& settings);
static void setDefaultMaxSize(uint64_t);
friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&,
const QueuePolicy&);
protected:
- QueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+ const std::string name;
- virtual void enqueued(const QueuedMessage&);
+ QueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+
+ virtual bool checkLimit(boost::intrusive_ptr<Message> msg);
void enqueued(uint64_t size);
void dequeued(uint64_t size);
};
@@ -86,21 +93,20 @@ class QueuePolicy
class FlowToDiskPolicy : public QueuePolicy
{
public:
- FlowToDiskPolicy(uint32_t maxCount, uint64_t maxSize);
- bool checkLimit(const QueuedMessage&);
+ FlowToDiskPolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize);
+ bool checkLimit(boost::intrusive_ptr<Message> msg);
};
class RingQueuePolicy : public QueuePolicy
{
public:
- RingQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = RING);
+ RingQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = RING);
void enqueued(const QueuedMessage&);
void dequeued(const QueuedMessage&);
bool isEnqueued(const QueuedMessage&);
- bool checkLimit(const QueuedMessage&);
+ bool checkLimit(boost::intrusive_ptr<Message> msg);
+ void getPendingDequeues(Messages& result);
private:
- typedef std::deque<QueuedMessage> Messages;
- qpid::sys::Mutex lock;
Messages pendingDequeues;
Messages queue;
const bool strict;
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp
index bdd5f33601..7e3090bf17 100644
--- a/qpid/cpp/src/qpid/broker/SemanticState.cpp
+++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp
@@ -65,7 +65,7 @@ SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss)
tagGenerator("sgen"),
dtxSelected(false),
authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isFederationLink()),
- userID(getSession().getConnection().getUserId().substr(0,getSession().getConnection().getUserId().find('@')))
+ userID(getSession().getConnection().getUserId())
{
acl = getSession().getBroker().getAcl();
}
@@ -302,6 +302,18 @@ bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
return !blocked;
}
+namespace {
+struct ConsumerName {
+ const SemanticState::ConsumerImpl& consumer;
+ ConsumerName(const SemanticState::ConsumerImpl& ci) : consumer(ci) {}
+};
+
+ostream& operator<<(ostream& o, const ConsumerName& pc) {
+ return o << pc.consumer.getName() << " on "
+ << pc.consumer.getParent().getSession().getSessionId();
+}
+}
+
void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
{
uint32_t originalMsgCredit = msgCredit;
@@ -312,7 +324,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
if (byteCredit != 0xFFFFFFFF) {
byteCredit -= msg->getRequiredCredit();
}
- QPID_LOG(debug, "Credit allocated for '" << name << "' on " << parent
+ QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this)
<< ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit
<< " now bytes: " << byteCredit << " msgs: " << msgCredit);
@@ -320,15 +332,13 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
{
- if (msgCredit == 0 || (byteCredit != 0xFFFFFFFF && byteCredit < msg->getRequiredCredit())) {
- QPID_LOG(debug, "Not enough credit for '" << name << "' on " << parent
- << ", bytes: " << byteCredit << " msgs: " << msgCredit);
- return false;
- } else {
- QPID_LOG(debug, "Credit available for '" << name << "' on " << parent
- << " bytes: " << byteCredit << " msgs: " << msgCredit);
- return true;
- }
+ bool enoughCredit = msgCredit > 0 &&
+ (byteCredit == 0xFFFFFFFF || byteCredit >= msg->getRequiredCredit());
+ QPID_LOG(debug, (enoughCredit ? "Sufficient credit for " : "Insufficient credit for ")
+ << ConsumerName(*this)
+ << ", have bytes: " << byteCredit << " msgs: " << msgCredit
+ << ", need " << msg->getRequiredCredit() << " bytes");
+ return enoughCredit;
}
SemanticState::ConsumerImpl::~ConsumerImpl() {}
@@ -356,6 +366,9 @@ void SemanticState::handle(intrusive_ptr<Message> msg) {
} else {
DeliverableMessage deliverable(msg);
route(msg, deliverable);
+ if (msg->checkContentReleasable()) {
+ msg->releaseContent();
+ }
}
}
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.h b/qpid/cpp/src/qpid/broker/SemanticState.h
index da8383fc12..89fe7b83dd 100644
--- a/qpid/cpp/src/qpid/broker/SemanticState.h
+++ b/qpid/cpp/src/qpid/broker/SemanticState.h
@@ -129,6 +129,7 @@ class SemanticState : private boost::noncopyable {
const framing::FieldTable& getArguments() const { return arguments; }
SemanticState& getParent() { return *parent; }
+ const SemanticState& getParent() const { return *parent; }
};
private:
@@ -163,6 +164,7 @@ class SemanticState : private boost::noncopyable {
~SemanticState();
SessionContext& getSession() { return session; }
+ const SessionContext& getSession() const { return session; }
ConsumerImpl& find(const std::string& destination);
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
index a1ad5a0a30..2ac6d66e62 100644
--- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -337,6 +337,10 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE)));
params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE)));
params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? _TRUE : _FALSE)));
+ params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type")));
+ params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count"))));
+ params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size"))));
+
if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
throw NotAllowedException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId()));
}
@@ -472,8 +476,7 @@ SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName,
AclModule* acl = getBroker().getAcl();
if (acl)
- {
- // add flags as needed
+ {
if (!acl->authorise(getConnection().getUserId(),acl::ACT_CONSUME,acl::OBJ_QUEUE,queueName,NULL) )
throw NotAllowedException(QPID_MSG("ACL denied Queue subscribe request from " << getConnection().getUserId()));
}
diff --git a/qpid/cpp/src/qpid/broker/SessionContext.h b/qpid/cpp/src/qpid/broker/SessionContext.h
index cfdbd100c3..afbbb2cc22 100644
--- a/qpid/cpp/src/qpid/broker/SessionContext.h
+++ b/qpid/cpp/src/qpid/broker/SessionContext.h
@@ -28,7 +28,7 @@
#include "qpid/sys/OutputControl.h"
#include "qpid/broker/ConnectionState.h"
#include "qpid/broker/OwnershipToken.h"
-
+#include "qpid/SessionId.h"
#include <boost/noncopyable.hpp>
@@ -45,6 +45,7 @@ class SessionContext : public OwnershipToken, public sys::OutputControl
virtual framing::AMQP_ClientProxy& getProxy() = 0;
virtual Broker& getBroker() = 0;
virtual uint16_t getChannel() const = 0;
+ virtual const SessionId& getSessionId() const = 0;
};
}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h
index 67fd4f4f38..eade93ddaa 100644
--- a/qpid/cpp/src/qpid/broker/SessionState.h
+++ b/qpid/cpp/src/qpid/broker/SessionState.h
@@ -118,6 +118,8 @@ class SessionState : public qpid::SessionState,
bool processSendCredit(uint32_t msgs);
+ const SessionId& getSessionId() const { return getId(); }
+
private:
void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id);
diff --git a/qpid/cpp/src/qpid/broker/SignalHandler.cpp b/qpid/cpp/src/qpid/broker/SignalHandler.cpp
index f4a3822554..b565cfd419 100644
--- a/qpid/cpp/src/qpid/broker/SignalHandler.cpp
+++ b/qpid/cpp/src/qpid/broker/SignalHandler.cpp
@@ -38,6 +38,8 @@ void SignalHandler::setBroker(const boost::intrusive_ptr<Broker>& b) {
signal(SIGCHLD,SIG_IGN);
}
+void SignalHandler::shutdown() { shutdownHandler(0); }
+
void SignalHandler::shutdownHandler(int) {
if (broker.get()) {
broker->shutdown();
diff --git a/qpid/cpp/src/qpid/broker/SignalHandler.h b/qpid/cpp/src/qpid/broker/SignalHandler.h
index d2cdfae07c..bbe831b61d 100644
--- a/qpid/cpp/src/qpid/broker/SignalHandler.h
+++ b/qpid/cpp/src/qpid/broker/SignalHandler.h
@@ -38,6 +38,9 @@ class SignalHandler
/** Set the broker to be shutdown on signals */
static void setBroker(const boost::intrusive_ptr<Broker>& broker);
+ /** Initiate shut-down of broker */
+ static void shutdown();
+
private:
static void shutdownHandler(int);
static boost::intrusive_ptr<Broker> broker;
diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
index 6bf0b104ea..cb04742677 100644
--- a/qpid/cpp/src/qpid/broker/TopicExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
@@ -293,44 +293,23 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string& pattern)
return q != qv.end();
}
-void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
+void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+{
Binding::vector mb;
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
PreRoute pr(msg, this);
- uint32_t count(0);
-
{
- RWlock::ScopedRlock l(lock);
- for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
- if (match(i->first, routingKey)) {
- Binding::vector& qv(i->second.bindingVector);
- for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++, count++){
- mb.push_back(*j);
+ RWlock::ScopedRlock l(lock);
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (match(i->first, routingKey)) {
+ Binding::vector& qv(i->second.bindingVector);
+ for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++){
+ b->push_back(*j);
+ }
}
}
}
- }
-
- for (Binding::vector::iterator j = mb.begin(); j != mb.end(); ++j) {
- msg.deliverTo((*j)->queue);
- if ((*j)->mgmtBinding != 0)
- (*j)->mgmtBinding->inc_msgMatched ();
- }
-
- if (mgmtExchange != 0)
- {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- if (count == 0)
- {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- else
- {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
+ doRoute(msg, b);
}
bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
diff --git a/qpid/cpp/src/qpid/broker/TxAccept.cpp b/qpid/cpp/src/qpid/broker/TxAccept.cpp
index e47ac84990..928ac12c10 100644
--- a/qpid/cpp/src/qpid/broker/TxAccept.cpp
+++ b/qpid/cpp/src/qpid/broker/TxAccept.cpp
@@ -88,7 +88,13 @@ bool TxAccept::prepare(TransactionContext* ctxt) throw()
void TxAccept::commit() throw()
{
- ops.commit();
+ try {
+ ops.commit();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
+ }
}
void TxAccept::rollback() throw() {}
diff --git a/qpid/cpp/src/qpid/broker/TxPublish.cpp b/qpid/cpp/src/qpid/broker/TxPublish.cpp
index 17b99fd883..4b083033ea 100644
--- a/qpid/cpp/src/qpid/broker/TxPublish.cpp
+++ b/qpid/cpp/src/qpid/broker/TxPublish.cpp
@@ -26,9 +26,14 @@ using namespace qpid::broker;
TxPublish::TxPublish(intrusive_ptr<Message> _msg) : msg(_msg) {}
-bool TxPublish::prepare(TransactionContext* ctxt) throw(){
+bool TxPublish::prepare(TransactionContext* ctxt) throw()
+{
try{
- for_each(queues.begin(), queues.end(), Prepare(ctxt, msg));
+ while (!queues.empty()) {
+ prepare(ctxt, queues.front());
+ prepared.push_back(queues.front());
+ queues.pop_front();
+ }
return true;
}catch(const std::exception& e){
QPID_LOG(error, "Failed to prepare: " << e.what());
@@ -38,11 +43,30 @@ bool TxPublish::prepare(TransactionContext* ctxt) throw(){
return false;
}
-void TxPublish::commit() throw(){
- for_each(queues.begin(), queues.end(), Commit(msg));
+void TxPublish::commit() throw()
+{
+ try {
+ for_each(prepared.begin(), prepared.end(), Commit(msg));
+ if (msg->checkContentReleasable()) {
+ msg->releaseContent();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
+ }
}
-void TxPublish::rollback() throw(){
+void TxPublish::rollback() throw()
+{
+ try {
+ for_each(prepared.begin(), prepared.end(), Rollback(msg));
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to complete rollback: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to complete rollback (unknown error)");
+ }
+
}
void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){
@@ -54,16 +78,14 @@ void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){
}
}
-TxPublish::Prepare::Prepare(TransactionContext* _ctxt, intrusive_ptr<Message>& _msg)
- : ctxt(_ctxt), msg(_msg){}
-
-void TxPublish::Prepare::operator()(const boost::shared_ptr<Queue>& queue){
+void TxPublish::prepare(TransactionContext* ctxt, const boost::shared_ptr<Queue> queue)
+{
if (!queue->enqueue(ctxt, msg)){
/**
- * if not store then mark message for ack and deleivery once
- * commit happens, as async IO will never set it when no store
- * exists
- */
+ * if not store then mark message for ack and deleivery once
+ * commit happens, as async IO will never set it when no store
+ * exists
+ */
msg->enqueueComplete();
}
}
@@ -74,6 +96,12 @@ void TxPublish::Commit::operator()(const boost::shared_ptr<Queue>& queue){
queue->process(msg);
}
+TxPublish::Rollback::Rollback(intrusive_ptr<Message>& _msg) : msg(_msg){}
+
+void TxPublish::Rollback::operator()(const boost::shared_ptr<Queue>& queue){
+ queue->enqueueAborted(msg);
+}
+
uint64_t TxPublish::contentSize ()
{
return msg->contentSize ();
diff --git a/qpid/cpp/src/qpid/broker/TxPublish.h b/qpid/cpp/src/qpid/broker/TxPublish.h
index d5cf5639c4..b6ab9767ab 100644
--- a/qpid/cpp/src/qpid/broker/TxPublish.h
+++ b/qpid/cpp/src/qpid/broker/TxPublish.h
@@ -47,23 +47,25 @@ namespace qpid {
* dispatch or to be added to the in-memory queue.
*/
class TxPublish : public TxOp, public Deliverable{
- class Prepare{
- TransactionContext* ctxt;
+
+ class Commit{
boost::intrusive_ptr<Message>& msg;
public:
- Prepare(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg);
+ Commit(boost::intrusive_ptr<Message>& msg);
void operator()(const boost::shared_ptr<Queue>& queue);
};
-
- class Commit{
+ class Rollback{
boost::intrusive_ptr<Message>& msg;
public:
- Commit(boost::intrusive_ptr<Message>& msg);
+ Rollback(boost::intrusive_ptr<Message>& msg);
void operator()(const boost::shared_ptr<Queue>& queue);
};
boost::intrusive_ptr<Message> msg;
std::list<Queue::shared_ptr> queues;
+ std::list<Queue::shared_ptr> prepared;
+
+ void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>);
public:
QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg);
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
index 9b2f662c8e..bb348675c6 100644
--- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -257,6 +257,7 @@ void ConnectionHandler::openOk ( const Array& knownBrokers )
knownBrokersUrls.push_back(Url((*i)->get<std::string>()));
if (sasl.get()) {
securityLayer = sasl->getSecurityLayer(maxFrameSize);
+ operUserId = sasl->getUserId();
}
setState(OPEN);
QPID_LOG(debug, "Known-brokers for connection: " << log::formatList(knownBrokersUrls));
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.h b/qpid/cpp/src/qpid/client/ConnectionHandler.h
index b1fd5be7c3..e9cc5194ae 100644
--- a/qpid/cpp/src/qpid/client/ConnectionHandler.h
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.h
@@ -71,6 +71,7 @@ class ConnectionHandler : private StateManager,
std::auto_ptr<Sasl> sasl;
std::auto_ptr<qpid::sys::SecurityLayer> securityLayer;
boost::intrusive_ptr<qpid::sys::TimerTask> rcvTimeoutTask;
+ std::string operUserId;
void checkState(STATES s, const std::string& msg);
@@ -120,6 +121,7 @@ public:
std::vector<Url> knownBrokersUrls;
static framing::connection::CloseCode convert(uint16_t replyCode);
+ const std::string& getUserId() const { return operUserId; }
};
}}
diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
index 45ad819ebd..c56d6a6807 100644
--- a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -151,6 +151,12 @@ void ConnectionImpl::open()
handler.waitForOpen();
+ // If the SASL layer has provided an "operational" userId for the connection,
+ // put it in the negotiated settings.
+ const std::string& userId(handler.getUserId());
+ if (!userId.empty())
+ handler.username = userId;
+
//enable security layer if one has been negotiated:
std::auto_ptr<SecurityLayer> securityLayer = handler.getSecurityLayer();
if (securityLayer.get()) {
diff --git a/qpid/cpp/src/qpid/client/Connector.cpp b/qpid/cpp/src/qpid/client/Connector.cpp
index f69032b26d..fbb571d40a 100644
--- a/qpid/cpp/src/qpid/client/Connector.cpp
+++ b/qpid/cpp/src/qpid/client/Connector.cpp
@@ -51,10 +51,10 @@ using boost::str;
// Stuff for the registry of protocol connectors (maybe should be moved to its own file)
namespace {
typedef std::map<std::string, Connector::Factory*> ProtocolRegistry;
-
+
ProtocolRegistry& theProtocolRegistry() {
static ProtocolRegistry protocolRegistry;
-
+
return protocolRegistry;
}
}
@@ -93,7 +93,7 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable
size_t lastEof; // Position after last EOF in frames
uint64_t currentSize;
Bounds* bounds;
-
+
framing::ProtocolVersion version;
bool initiated;
bool closed;
@@ -118,16 +118,17 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable
void run();
void handleClosed();
bool closeInternal();
-
+
+ void connected(const Socket&);
+ void connectFailed(const std::string& msg);
bool readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*);
void writebuff(qpid::sys::AsynchIO&);
void writeDataBlock(const framing::AMQDataBlock& data);
void eof(qpid::sys::AsynchIO&);
boost::weak_ptr<ConnectionImpl> impl;
-
+
void connect(const std::string& host, int port);
- void init();
void close();
void send(framing::AMQFrame& frame);
void abort();
@@ -142,7 +143,6 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable
size_t decode(const char* buffer, size_t size);
size_t encode(const char* buffer, size_t size);
bool canEncode();
-
public:
TCPConnector(framing::ProtocolVersion pVersion,
@@ -163,6 +163,11 @@ namespace {
} init;
}
+struct TCPConnector::Buff : public AsynchIO::BufferBase {
+ Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
+ ~Buff() { delete [] bytes;}
+};
+
TCPConnector::TCPConnector(ProtocolVersion ver,
const ConnectionSettings& settings,
ConnectionImpl* cimpl)
@@ -189,15 +194,19 @@ TCPConnector::~TCPConnector() {
void TCPConnector::connect(const std::string& host, int port){
Mutex::ScopedLock l(lock);
assert(closed);
- try {
- socket.connect(host, port);
- } catch (const std::exception& /*e*/) {
- socket.close();
- throw;
- }
-
- identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ assert(joined);
poller = Poller::shared_ptr(new Poller);
+ AsynchConnector::create(socket,
+ poller,
+ host, port,
+ boost::bind(&TCPConnector::connected, this, _1),
+ boost::bind(&TCPConnector::connectFailed, this, _3));
+ closed = false;
+ joined = false;
+ receiver = Thread(this);
+}
+
+void TCPConnector::connected(const Socket&) {
aio = AsynchIO::create(socket,
boost::bind(&TCPConnector::readbuff, this, _1, _2),
boost::bind(&TCPConnector::eof, this, _1),
@@ -205,16 +214,23 @@ void TCPConnector::connect(const std::string& host, int port){
0, // closed
0, // nobuffs
boost::bind(&TCPConnector::writebuff, this, _1));
- closed = false;
-}
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff(maxFrameSize));
+ }
+ aio->start(poller);
-void TCPConnector::init(){
- Mutex::ScopedLock l(lock);
- assert(joined);
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
ProtocolInitiation init(version);
writeDataBlock(init);
- joined = false;
- receiver = Thread(this);
+}
+
+void TCPConnector::connectFailed(const std::string& msg) {
+ QPID_LOG(warning, "Connecting failed: " << msg);
+ closed = true;
+ poller->shutdown();
+ closeInternal();
+ if (shutdownHandler)
+ shutdownHandler->shutdown();
}
bool TCPConnector::closeInternal() {
@@ -235,7 +251,7 @@ bool TCPConnector::closeInternal() {
receiver.join();
return ret;
}
-
+
void TCPConnector::close() {
closeInternal();
}
@@ -243,7 +259,13 @@ void TCPConnector::close() {
void TCPConnector::abort() {
// Can't abort a closed connection
if (!closed) {
- aio->requestCallback(boost::bind(&TCPConnector::eof, this, _1));
+ if (aio) {
+ // Established connection
+ aio->requestCallback(boost::bind(&TCPConnector::eof, this, _1));
+ } else {
+ // We're still connecting
+ connectFailed("Connection timedout");
+ }
}
}
@@ -288,18 +310,13 @@ void TCPConnector::handleClosed() {
shutdownHandler->shutdown();
}
-struct TCPConnector::Buff : public AsynchIO::BufferBase {
- Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
- ~Buff() { delete [] bytes;}
-};
-
void TCPConnector::writebuff(AsynchIO& /*aio*/)
{
Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
if (codec->canEncode()) {
std::auto_ptr<AsynchIO::BufferBase> buffer = std::auto_ptr<AsynchIO::BufferBase>(aio->getQueuedBuffer());
if (!buffer.get()) buffer = std::auto_ptr<AsynchIO::BufferBase>(new Buff(maxFrameSize));
-
+
size_t encoded = codec->encode(buffer->bytes, buffer->byteCount);
buffer->dataStart = 0;
@@ -395,11 +412,6 @@ void TCPConnector::run() {
try {
Dispatcher d(poller);
- for (int i = 0; i < 32; i++) {
- aio->queueReadBuffer(new Buff(maxFrameSize));
- }
-
- aio->start(poller);
d.run();
} catch (const std::exception& e) {
QPID_LOG(error, QPID_MSG("FAIL " << identifier << ": " << e.what()));
diff --git a/qpid/cpp/src/qpid/client/RdmaConnector.cpp b/qpid/cpp/src/qpid/client/RdmaConnector.cpp
index 0aefcc04cf..0692c3d85c 100644
--- a/qpid/cpp/src/qpid/client/RdmaConnector.cpp
+++ b/qpid/cpp/src/qpid/client/RdmaConnector.cpp
@@ -167,20 +167,9 @@ void RdmaConnector::connect(const std::string& host, int port){
assert(joined);
poller = Poller::shared_ptr(new Poller);
- // This stuff needs to abstracted out of here to a platform specific file
- ::addrinfo *res;
- ::addrinfo hints;
- hints.ai_flags = 0;
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = 0;
- int n = ::getaddrinfo(host.c_str(), boost::lexical_cast<std::string>(port).c_str(), &hints, &res);
- if (n<0) {
- throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n)));
- }
-
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
Rdma::Connector* c = new Rdma::Connector(
- *res->ai_addr,
+ sa,
Rdma::ConnectionParams(maxFrameSize, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(&RdmaConnector::connected, this, poller, _1, _2),
boost::bind(&RdmaConnector::connectionError, this, poller, _1, _2),
diff --git a/qpid/cpp/src/qpid/client/Sasl.h b/qpid/cpp/src/qpid/client/Sasl.h
index 9dc5817f3d..d773609655 100644
--- a/qpid/cpp/src/qpid/client/Sasl.h
+++ b/qpid/cpp/src/qpid/client/Sasl.h
@@ -45,6 +45,7 @@ class Sasl
virtual std::string start(const std::string& mechanisms) = 0;
virtual std::string step(const std::string& challenge) = 0;
virtual std::string getMechanism() = 0;
+ virtual std::string getUserId() = 0;
virtual std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize) = 0;
virtual ~Sasl() {}
};
diff --git a/qpid/cpp/src/qpid/client/SaslFactory.cpp b/qpid/cpp/src/qpid/client/SaslFactory.cpp
index 884f527f01..2258163ec8 100644
--- a/qpid/cpp/src/qpid/client/SaslFactory.cpp
+++ b/qpid/cpp/src/qpid/client/SaslFactory.cpp
@@ -82,6 +82,7 @@ class CyrusSasl : public Sasl
std::string start(const std::string& mechanisms);
std::string step(const std::string& challenge);
std::string getMechanism();
+ std::string getUserId();
std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
private:
sasl_conn_t* conn;
@@ -266,6 +267,18 @@ std::string CyrusSasl::getMechanism()
return mechanism;
}
+std::string CyrusSasl::getUserId()
+{
+ int propResult;
+ const void* operName;
+
+ propResult = sasl_getprop(conn, SASL_USERNAME, &operName);
+ if (propResult == SASL_OK)
+ return std::string((const char*) operName);
+
+ return std::string();
+}
+
void CyrusSasl::interact(sasl_interact_t* client_interact)
{
diff --git a/qpid/cpp/src/qpid/client/SessionImpl.cpp b/qpid/cpp/src/qpid/client/SessionImpl.cpp
index 8ead44a172..32541dceac 100644
--- a/qpid/cpp/src/qpid/client/SessionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/SessionImpl.cpp
@@ -64,7 +64,8 @@ SessionImpl::SessionImpl(const std::string& name, boost::shared_ptr<ConnectionIm
proxy(ioHandler),
nextIn(0),
nextOut(0),
- sendMsgCredit(0)
+ sendMsgCredit(0),
+ doClearDeliveryPropertiesExchange(true)
{
channel.next = connectionShared.get();
}
@@ -396,11 +397,16 @@ void SessionImpl::sendContent(const MethodContent& content)
{
AMQFrame header(content.getHeader());
- // Client is not allowed to set the delivery-properties.exchange.
- AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody());
- if (headerp && headerp->get<DeliveryProperties>())
- headerp->get<DeliveryProperties>(true)->clearExchangeFlag();
-
+ // doClearDeliveryPropertiesExchange is set by cluster update client so
+ // it can send messages with delivery-properties.exchange set.
+ //
+ if (doClearDeliveryPropertiesExchange) {
+ // Normal client is not allowed to set the delivery-properties.exchange
+ // so clear it here.
+ AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody());
+ if (headerp && headerp->get<DeliveryProperties>())
+ headerp->get<DeliveryProperties>(true)->clearExchangeFlag();
+ }
header.setFirstSegment(false);
uint64_t data_length = content.getData().length();
if(data_length > 0){
diff --git a/qpid/cpp/src/qpid/client/SessionImpl.h b/qpid/cpp/src/qpid/client/SessionImpl.h
index 49d268c44d..0624bb8b3c 100644
--- a/qpid/cpp/src/qpid/client/SessionImpl.h
+++ b/qpid/cpp/src/qpid/client/SessionImpl.h
@@ -130,6 +130,8 @@ public:
*/
boost::shared_ptr<ConnectionImpl> getConnection();
+ void setDoClearDeliveryPropertiesExchange(bool b=true) { doClearDeliveryPropertiesExchange = b; }
+
private:
enum State {
INACTIVE,
@@ -243,6 +245,8 @@ private:
// Only keep track of message credit
sys::Semaphore* sendMsgCredit;
+ bool doClearDeliveryPropertiesExchange;
+
friend class client::SessionHandler;
};
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
index 9b9f06ec57..f51a96efd9 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -362,21 +362,12 @@ void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, Ou
void QueueSink::cancel(qpid::client::AsyncSession&, const std::string&) {}
-template <class T> void encode(qpid::messaging::Message& from)
-{
- T codec;
- from.encode(codec);
- from.setContentType(T::contentType);
-}
-
void translate(const Variant::Map& from, FieldTable& to);//implementation in Codecs.cpp
void convert(qpid::messaging::Message& from, qpid::client::Message& to)
{
//TODO: need to avoid copying as much as possible
- if (from.getContent().isList()) encode<ListCodec>(from);
- if (from.getContent().isMap()) encode<MapCodec>(from);
- to.setData(from.getBytes());
+ to.setData(from.getContent());
to.getDeliveryProperties().setRoutingKey(from.getSubject());
//TODO: set other delivery properties
to.getMessageProperties().setContentType(from.getContentType());
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
index d22208368b..8e060c62d7 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
@@ -269,18 +269,9 @@ void populate(qpid::messaging::Message& message, FrameSet& command)
//e.g. for rejecting.
MessageImplAccess::get(message).setInternalId(command.getId());
- command.getContent(message.getBytes());
+ command.getContent(message.getContent());
populateHeaders(message, command.getHeaders());
-
- //decode content if necessary
- if (message.getContentType() == ListCodec::contentType) {
- ListCodec codec;
- message.decode(codec);
- } else if (message.getContentType() == MapCodec::contentType) {
- MapCodec codec;
- message.decode(codec);
- }
}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
index 716f955f98..cbc95b44fb 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
@@ -33,24 +33,11 @@ namespace amqp0_10 {
using qpid::messaging::Address;
using qpid::messaging::MessageImplAccess;
-template <class T> void encode(const qpid::messaging::Message& from, qpid::client::Message& to)
-{
- T codec;
- MessageImplAccess::get(from).getEncodedContent(codec, to.getData());
- to.getMessageProperties().setContentType(T::contentType);
-}
-
void OutgoingMessage::convert(const qpid::messaging::Message& from)
{
//TODO: need to avoid copying as much as possible
- if (from.getContent().isList()) {
- encode<ListCodec>(from, message);
- } else if (from.getContent().isMap()) {
- encode<MapCodec>(from, message);
- } else {
- message.setData(from.getBytes());
- message.getMessageProperties().setContentType(from.getContentType());
- }
+ message.setData(from.getContent());
+ message.getMessageProperties().setContentType(from.getContentType());
const Address& address = from.getReplyTo();
if (!address.value.empty()) {
message.getMessageProperties().setReplyTo(AddressResolution::convert(address));
diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
index 58956609a4..3a662463c1 100644
--- a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
+++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
@@ -43,6 +43,7 @@ class WindowsSasl : public Sasl
std::string start(const std::string& mechanisms);
std::string step(const std::string& challenge);
std::string getMechanism();
+ std::string getUserId();
std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
private:
ConnectionSettings settings;
@@ -131,6 +132,11 @@ std::string WindowsSasl::getMechanism()
return mechanism;
}
+std::string WindowsSasl::getUserId()
+{
+ return std::string(); // TODO - when GSSAPI is supported, return userId for connection.
+}
+
std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t maxFrameSize)
{
return std::auto_ptr<SecurityLayer>(0);
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp
index e35d3e4175..0706fc72e8 100644
--- a/qpid/cpp/src/qpid/cluster/Cluster.cpp
+++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp
@@ -99,6 +99,7 @@
#include "qpid/broker/Connection.h"
#include "qpid/broker/QueueRegistry.h"
#include "qpid/broker/SessionState.h"
+#include "qpid/broker/SignalHandler.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/AMQP_AllOperations.h"
#include "qpid/framing/AllInvoker.h"
@@ -120,7 +121,6 @@
#include "qpid/management/ManagementAgent.h"
#include "qpid/memory.h"
#include "qpid/sys/Thread.h"
-#include "qpid/sys/LatencyTracker.h"
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
@@ -144,12 +144,16 @@ using qpid::management::Manageable;
using qpid::management::Args;
namespace _qmf = ::qmf::org::apache::qpid::cluster;
-/** NOTE: increment this number whenever any incompatible changes in
+/**
+ * NOTE: must increment this number whenever any incompatible changes in
* cluster protocol/behavior are made. It allows early detection and
* sensible reporting of an attempt to mix different versions in a
* cluster.
+ *
+ * Currently use SVN revision to avoid clashes with versions from
+ * different branches.
*/
-const uint32_t Cluster::CLUSTER_VERSION = 2;
+const uint32_t Cluster::CLUSTER_VERSION = 820783;
struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
qpid::cluster::Cluster& cluster;
@@ -308,7 +312,7 @@ void Cluster::leave(Lock&) {
// Finalize connections now now to avoid problems later in destructor.
LEAVE_TRY(localConnections.clear());
LEAVE_TRY(connections.clear());
- LEAVE_TRY(broker.shutdown());
+ LEAVE_TRY(broker::SignalHandler::shutdown());
}
}
@@ -324,20 +328,14 @@ void Cluster::deliver(
MemberId from(nodeid, pid);
framing::Buffer buf(static_cast<char*>(msg), msg_len);
Event e(Event::decodeCopy(from, buf));
- LATENCY_TRACK(if (e.getConnectionId().getMember() == self) mcast.cpgLatency.finish());
deliverEvent(e);
}
-LATENCY_TRACK(sys::LatencyTracker<const char*> eventQueueLatencyTracker("EventQueue");)
- LATENCY_TRACK(sys::LatencyTracker<const AMQBody*> frameQueueLatencyTracker("FrameQueue");)
-
- void Cluster::deliverEvent(const Event& e) {
- LATENCY_TRACK(eventQueueLatencyTracker.start(e.getData());)
- deliverEventQueue.push(e);
+void Cluster::deliverEvent(const Event& e) {
+ deliverEventQueue.push(e);
}
void Cluster::deliverFrame(const EventFrame& e) {
- LATENCY_TRACK(frameQueueLatencyTracker.start(e.frame.getBody()));
deliverFrameQueue.push(e);
}
@@ -350,7 +348,6 @@ const ClusterUpdateOfferBody* castUpdateOffer(const framing::AMQBody* body) {
// Handler for deliverEventQueue.
// This thread decodes frames from events.
void Cluster::deliveredEvent(const Event& e) {
- LATENCY_TRACK(eventQueueLatencyTracker.finish(e.getData()));
if (e.isCluster()) {
QPID_LOG(trace, *this << " DLVR: " << e);
EventFrame ef(e, e.getFrame());
@@ -396,13 +393,9 @@ void Cluster::flagError(
error.error(connection, type, map.getFrameSeq(), map.getMembers(), msg);
}
-LATENCY_TRACK(sys::LatencyTracker<const AMQBody*> doOutputTracker("DoOutput");)
-
// Handler for deliverFrameQueue.
// This thread executes the main logic.
- void Cluster::deliveredFrame(const EventFrame& efConst) {
- LATENCY_TRACK(frameQueueLatencyTracker.finish(e.frame.getBody()));
- LATENCY_TRACK(if (e.frame.getBody()->type() == CONTENT_BODY) doOutputTracker.start(e.frame.getBody()));
+void Cluster::deliveredFrame(const EventFrame& efConst) {
Mutex::ScopedLock l(lock);
if (state == LEFT) return;
EventFrame e(efConst);
@@ -434,7 +427,6 @@ void Cluster::processFrame(const EventFrame& e, Lock& l) {
throw Exception(QPID_MSG("Invalid cluster control"));
}
else if (state >= CATCHUP) {
- LATENCY_TRACK(LatencyScope ls(processLatency));
map.incrementFrameSeq();
ConnectionPtr connection = getConnection(e, l);
if (connection) {
diff --git a/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp b/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp
index 35be055d06..5b7011047b 100644
--- a/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp
+++ b/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp
@@ -45,7 +45,8 @@ ostream& operator<<(ostream& o, const ErrorCheck::MemberSet& ms) {
}
void ErrorCheck::error(
- Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms, const std::string& msg)
+ Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms,
+ const std::string& msg)
{
// Detected a local error, inform cluster and set error state.
assert(t != ERROR_TYPE_NONE); // Must be an error.
@@ -54,10 +55,11 @@ void ErrorCheck::error(
unresolved = ms;
frameSeq = seq;
connection = &c;
- QPID_LOG(error, cluster
- << (type == ERROR_TYPE_SESSION ? " channel" : " connection")
- << " error " << frameSeq << " on " << c << ": " << msg
- << " must be resolved with: " << unresolved);
+ message = msg;
+ QPID_LOG(debug, cluster<< (type == ERROR_TYPE_SESSION ? " channel" : " connection")
+ << " error " << frameSeq << " on " << c
+ << " must be resolved with: " << unresolved
+ << ": " << message);
mcast.mcastControl(
ClusterErrorCheckBody(ProtocolVersion(), type, frameSeq), cluster.getId());
// If there are already frames queued up by a previous error, review
@@ -84,13 +86,15 @@ ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator&
if (errorCheck->getFrameSeq() == frameSeq) { // Addresses current error
next = frames.erase(i); // Drop matching error check controls
if (errorCheck->getType() < type) { // my error is worse than his
- QPID_LOG(critical, cluster << " error " << frameSeq
- << " did not occur on " << i->getMemberId());
- throw Exception(QPID_MSG("Error " << frameSeq
- << " did not occur on all members"));
+ QPID_LOG(critical, cluster
+ << " local error " << frameSeq << " did not occur on member "
+ << i->getMemberId()
+ << ": " << message);
+ throw Exception(
+ QPID_MSG("local error did not occur on all cluster members " << ": " << message));
}
else { // his error is worse/same as mine.
- QPID_LOG(info, cluster << " error " << frameSeq
+ QPID_LOG(debug, cluster << " error " << frameSeq
<< " resolved with " << i->getMemberId());
unresolved.erase(i->getMemberId());
checkResolved();
@@ -128,10 +132,10 @@ ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator&
void ErrorCheck::checkResolved() {
if (unresolved.empty()) { // No more potentially conflicted members, we're clear.
type = ERROR_TYPE_NONE;
- QPID_LOG(info, cluster << " error " << frameSeq << " resolved.");
+ QPID_LOG(debug, cluster << " error " << frameSeq << " resolved.");
}
else
- QPID_LOG(info, cluster << " error " << frameSeq
+ QPID_LOG(debug, cluster << " error " << frameSeq
<< " must be resolved with " << unresolved);
}
@@ -146,7 +150,7 @@ void ErrorCheck::respondNone(const MemberId& from, uint8_t type, framing::Sequen
// Don't respond to non-errors or to my own errors.
if (type == ERROR_TYPE_NONE || from == cluster.getId())
return;
- QPID_LOG(info, cluster << " error " << frameSeq << " did not occur locally.");
+ QPID_LOG(debug, cluster << " error " << frameSeq << " did not occur locally.");
mcast.mcastControl(
ClusterErrorCheckBody(ProtocolVersion(), ERROR_TYPE_NONE, frameSeq),
cluster.getId()
diff --git a/qpid/cpp/src/qpid/cluster/ErrorCheck.h b/qpid/cpp/src/qpid/cluster/ErrorCheck.h
index 09028391ac..c975b9af64 100644
--- a/qpid/cpp/src/qpid/cluster/ErrorCheck.h
+++ b/qpid/cpp/src/qpid/cluster/ErrorCheck.h
@@ -84,6 +84,7 @@ class ErrorCheck
SequenceNumber frameSeq;
ErrorType type;
Connection* connection;
+ std::string message;
};
}} // namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/cluster/Event.cpp b/qpid/cpp/src/qpid/cluster/Event.cpp
index 30866d3154..4831e7eabe 100644
--- a/qpid/cpp/src/qpid/cluster/Event.cpp
+++ b/qpid/cpp/src/qpid/cluster/Event.cpp
@@ -38,9 +38,6 @@ const size_t EventHeader::HEADER_SIZE =
sizeof(uint8_t) + // type
sizeof(uint64_t) + // connection pointer only, CPG provides member ID.
sizeof(uint32_t) // payload size
-#ifdef QPID_LATENCY_METRIC
- + sizeof(int64_t) // timestamp
-#endif
;
EventHeader::EventHeader(EventType t, const ConnectionId& c, size_t s)
@@ -61,9 +58,6 @@ void EventHeader::decode(const MemberId& m, framing::Buffer& buf) {
throw Exception("Invalid multicast event type");
connectionId = ConnectionId(m, buf.getLongLong());
size = buf.getLong();
-#ifdef QPID_LATENCY_METRIC
- latency_metric_timestamp = buf.getLongLong();
-#endif
}
Event Event::decodeCopy(const MemberId& m, framing::Buffer& buf) {
@@ -97,9 +91,6 @@ void EventHeader::encode(Buffer& b) const {
b.putOctet(type);
b.putLongLong(connectionId.getNumber());
b.putLong(size);
-#ifdef QPID_LATENCY_METRIC
- b.putLongLong(latency_metric_timestamp);
-#endif
}
// Encode my header in my buffer.
diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.cpp b/qpid/cpp/src/qpid/cluster/Multicaster.cpp
index 7e97963318..72fc1533f8 100644
--- a/qpid/cpp/src/qpid/cluster/Multicaster.cpp
+++ b/qpid/cpp/src/qpid/cluster/Multicaster.cpp
@@ -31,9 +31,6 @@ namespace cluster {
Multicaster::Multicaster(Cpg& cpg_,
const boost::shared_ptr<sys::Poller>& poller,
boost::function<void()> onError_) :
-#if defined (QPID_LATENCY_TRACKER)
- cpgLatency("CPG"),
-#endif
onError(onError_), cpg(cpg_),
queue(boost::bind(&Multicaster::sendMcast, this, _1), poller),
holding(true)
@@ -61,7 +58,6 @@ void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId&
void Multicaster::mcast(const Event& e) {
{
sys::Mutex::ScopedLock l(lock);
- LATENCY_TRACK(cpgLatency.start());
if (e.isConnection() && holding) {
holdingQueue.push_back(e);
return;
diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.h b/qpid/cpp/src/qpid/cluster/Multicaster.h
index f2ee5099bb..c1a0ddffc6 100644
--- a/qpid/cpp/src/qpid/cluster/Multicaster.h
+++ b/qpid/cpp/src/qpid/cluster/Multicaster.h
@@ -26,7 +26,6 @@
#include "qpid/cluster/Event.h"
#include "qpid/sys/PollableQueue.h"
#include "qpid/sys/Mutex.h"
-#include "qpid/sys/LatencyTracker.h"
#include <boost/shared_ptr.hpp>
#include <deque>
@@ -58,8 +57,6 @@ class Multicaster
/** End holding mode, held events are mcast */
void release();
- LATENCY_TRACK(sys::LatencyCounter cpgLatency;)
-
private:
typedef sys::PollableQueue<Event> PollableEventQueue;
typedef std::deque<Event> PlainEventQueue;
diff --git a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
index cb8f01386c..cb75fe5561 100644
--- a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
+++ b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
@@ -24,7 +24,6 @@
#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/log/Statement.h"
-#include "qpid/sys/LatencyTracker.h"
#include <boost/current_function.hpp>
@@ -40,16 +39,9 @@ OutputInterceptor::OutputInterceptor(Connection& p, sys::ConnectionOutputHandler
: parent(p), closing(false), next(&h), sendMax(1), sent(0), sentDoOutput(false)
{}
-#if defined QPID_LATENCY_TRACKER
-extern sys::LatencyTracker<const AMQBody*> doOutputTracker;
-#endif
-
void OutputInterceptor::send(framing::AMQFrame& f) {
- LATENCY_TRACK(doOutputTracker.finish(f.getBody()));
- {
- sys::Mutex::ScopedLock l(lock);
- next->send(f);
- }
+ sys::Mutex::ScopedLock l(lock);
+ next->send(f);
}
void OutputInterceptor::activateOutput() {
diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
index 2e557f2ab6..d6df8bd5ac 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
+++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -209,9 +209,16 @@ class MessageUpdater {
ClusterConnectionProxy(session).expiryId(*expiryId);
}
+ // We can't send a broker::Message via the normal client API,
+ // and it would be expensive to copy it into a client::Message
+ // so we go a bit under the client API covers here.
+ //
SessionBase_0_10Access sb(session);
+ // Disable client code that clears the delivery-properties.exchange
+ sb.get()->setDoClearDeliveryPropertiesExchange(false);
framing::MessageTransferBody transfer(
- framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE, message::ACQUIRE_MODE_PRE_ACQUIRED);
+ framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE,
+ message::ACQUIRE_MODE_PRE_ACQUIRED);
sb.get()->send(transfer, message.payload->getFrames(), !message.payload->isContentReleased());
if (message.payload->isContentReleased()){
diff --git a/qpid/cpp/src/qpid/cluster/UpdateExchange.h b/qpid/cpp/src/qpid/cluster/UpdateExchange.h
index 194a3d386d..00a92c7f1e 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateExchange.h
+++ b/qpid/cpp/src/qpid/cluster/UpdateExchange.h
@@ -30,7 +30,7 @@ namespace qpid {
namespace cluster {
/**
- * A keyless exchange (like fanout exchange) that does not modify deliver-properties.exchange
+ * A keyless exchange (like fanout exchange) that does not modify delivery-properties.exchange
* on messages.
*/
class UpdateExchange : public broker::FanOutExchange
diff --git a/qpid/cpp/src/qpid/messaging/ListContent.cpp b/qpid/cpp/src/qpid/messaging/ListContent.cpp
new file mode 100644
index 0000000000..0c3ca5fc62
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/ListContent.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ListContent.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListContentImpl : public Variant
+{
+ Message* msg;
+ public:
+ ListContentImpl(Message& m) : Variant(Variant::List()), msg(&m)
+ {
+ if (msg->getContent().size()) {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.decode(msg->getContent(), *this);
+ }
+ }
+
+ void encode()
+ {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.encode(*this, msg->getContent());
+ }
+};
+
+ListContent::ListContent(Message& m) : impl(new ListContentImpl(m)) {}
+ListContent::~ListContent() { delete impl; }
+ListContent& ListContent::operator=(const ListContent& l) { *impl = *l.impl; return *this; }
+
+ListContent::const_iterator ListContent::begin() const { return impl->asList().begin(); }
+ListContent::const_iterator ListContent::end() const { return impl->asList().end(); }
+ListContent::const_reverse_iterator ListContent::rbegin() const { return impl->asList().rbegin(); }
+ListContent::const_reverse_iterator ListContent::rend() const { return impl->asList().rend(); }
+
+ListContent::iterator ListContent::begin() { return impl->asList().begin(); }
+ListContent::iterator ListContent::end() { return impl->asList().end(); }
+ListContent::reverse_iterator ListContent::rbegin() { return impl->asList().rbegin(); }
+ListContent::reverse_iterator ListContent::rend() { return impl->asList().rend(); }
+
+bool ListContent::empty() const { return impl->asList().empty(); }
+size_t ListContent::size() const { return impl->asList().size(); }
+
+const Variant& ListContent::front() const { return impl->asList().front(); }
+Variant& ListContent::front() { return impl->asList().front(); }
+const Variant& ListContent::back() const { return impl->asList().back(); }
+Variant& ListContent::back() { return impl->asList().back(); }
+
+void ListContent::push_front(const Variant& v) { impl->asList().push_front(v); }
+void ListContent::push_back(const Variant& v) { impl->asList().push_back(v); }
+
+void ListContent::pop_front() { impl->asList().pop_front(); }
+void ListContent::pop_back() { impl->asList().pop_back(); }
+
+ListContent::iterator ListContent::insert(iterator position, const Variant& v)
+{
+ return impl->asList().insert(position, v);
+}
+void ListContent::insert(iterator position, size_t n, const Variant& v)
+{
+ impl->asList().insert(position, n, v);
+}
+ListContent::iterator ListContent::erase(iterator position) { return impl->asList().erase(position); }
+ListContent::iterator ListContent::erase(iterator first, iterator last) { return impl->asList().erase(first, last); }
+void ListContent::clear() { impl->asList().clear(); }
+
+void ListContent::encode() { impl->encode(); }
+
+const Variant::List& ListContent::asList() const { return impl->asList(); }
+Variant::List& ListContent::asList() { return impl->asList(); }
+
+std::ostream& operator<<(std::ostream& out, const ListContent& m)
+{
+ out << m.asList();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/ListView.cpp b/qpid/cpp/src/qpid/messaging/ListView.cpp
new file mode 100644
index 0000000000..b717d157fa
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/ListView.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ListView.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListViewImpl : public Variant
+{
+ public:
+ ListViewImpl(const Message& msg) : Variant(Variant::List())
+ {
+ if (msg.getContent().size()) {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.decode(msg.getContent(), *this);
+ }
+ }
+};
+
+ListView::ListView(const Message& m) :impl(new ListViewImpl(m)) {}
+ListView::~ListView() { delete impl; }
+ListView& ListView::operator=(const ListView& l) { *impl = *l.impl; return *this; }
+
+ListView::const_iterator ListView::begin() const { return impl->asList().begin(); }
+ListView::const_iterator ListView::end() const { return impl->asList().end(); }
+ListView::const_reverse_iterator ListView::rbegin() const { return impl->asList().rbegin(); }
+ListView::const_reverse_iterator ListView::rend() const { return impl->asList().rend(); }
+
+bool ListView::empty() const { return impl->asList().empty(); }
+size_t ListView::size() const { return impl->asList().size(); }
+
+const Variant& ListView::front() const { return impl->asList().front(); }
+const Variant& ListView::back() const { return impl->asList().back(); }
+
+const Variant::List& ListView::asList() const { return impl->asList(); }
+
+std::ostream& operator<<(std::ostream& out, const ListView& m)
+{
+ out << m.asList();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MapContent.cpp b/qpid/cpp/src/qpid/messaging/MapContent.cpp
new file mode 100644
index 0000000000..c653561fc9
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MapContent.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/MapContent.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class MapContentImpl : public Variant
+{
+ Message* msg;
+ public:
+ MapContentImpl(Message& m) : Variant(Variant::Map()), msg(&m)
+ {
+ if (msg->getContent().size()) {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.decode(msg->getContent(), *this);
+ }
+ }
+
+ void encode()
+ {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.encode(*this, msg->getContent());
+ }
+};
+
+MapContent::MapContent(Message& m) : impl(new MapContentImpl(m)) {}
+MapContent::~MapContent() { delete impl; }
+MapContent& MapContent::operator=(const MapContent& m) { *impl = *m.impl; return *this; }
+
+MapContent::const_iterator MapContent::begin() const { return impl->asMap().begin(); }
+MapContent::const_iterator MapContent::end() const { return impl->asMap().end(); }
+MapContent::const_reverse_iterator MapContent::rbegin() const { return impl->asMap().rbegin(); }
+MapContent::const_reverse_iterator MapContent::rend() const { return impl->asMap().rend(); }
+MapContent::iterator MapContent::begin() { return impl->asMap().begin(); }
+MapContent::iterator MapContent::end() { return impl->asMap().end(); }
+MapContent::reverse_iterator MapContent::rbegin() { return impl->asMap().rbegin(); }
+MapContent::reverse_iterator MapContent::rend() { return impl->asMap().rend(); }
+
+bool MapContent::empty() const { return impl->asMap().empty(); }
+size_t MapContent::size() const { return impl->asMap().size(); }
+
+MapContent::const_iterator MapContent::find(const key_type& key) const { return impl->asMap().find(key); }
+MapContent::iterator MapContent::find(const key_type& key) { return impl->asMap().find(key); }
+const Variant& MapContent::operator[](const key_type& key) const { return impl->asMap()[key]; }
+Variant& MapContent::operator[](const key_type& key) { return impl->asMap()[key]; }
+
+std::pair<MapContent::iterator,bool> MapContent::insert(const value_type& item) { return impl->asMap().insert(item); }
+MapContent::iterator MapContent::insert(iterator position, const value_type& item) { return impl->asMap().insert(position, item); }
+void MapContent::erase(iterator position) { impl->asMap().erase(position); }
+void MapContent::erase(iterator first, iterator last) { impl->asMap().erase(first, last); }
+size_t MapContent::erase(const key_type& key) { return impl->asMap().erase(key); }
+void MapContent::clear() { impl->asMap().clear(); }
+
+void MapContent::encode() { impl->encode(); }
+
+const std::map<MapContent::key_type, Variant>& MapContent::asMap() const { return impl->asMap(); }
+std::map<MapContent::key_type, Variant>& MapContent::asMap() { return impl->asMap(); }
+
+
+std::ostream& operator<<(std::ostream& out, const MapContent& m)
+{
+ out << m.asMap();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MapView.cpp b/qpid/cpp/src/qpid/messaging/MapView.cpp
new file mode 100644
index 0000000000..ffa6e91a16
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MapView.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/MapView.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class MapViewImpl : public Variant
+{
+ public:
+ MapViewImpl(const Message& msg) : Variant(Variant::Map())
+ {
+ if (msg.getContent().size()) {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.decode(msg.getContent(), *this);
+ }
+ }
+};
+
+MapView::MapView(const Message& m) : impl(new MapViewImpl(m)) {}
+MapView::~MapView() { delete impl; }
+MapView& MapView::operator=(const MapView& m) { *impl = *m.impl; return *this; }
+
+MapView::const_iterator MapView::begin() const { return impl->asMap().begin(); }
+MapView::const_iterator MapView::end() const { return impl->asMap().end(); }
+MapView::const_reverse_iterator MapView::rbegin() const { return impl->asMap().rbegin(); }
+MapView::const_reverse_iterator MapView::rend() const { return impl->asMap().rend(); }
+
+bool MapView::empty() const { return impl->asMap().empty(); }
+size_t MapView::size() const { return impl->asMap().size(); }
+
+MapView::const_iterator MapView::find(const key_type& key) const { return impl->asMap().find(key); }
+const Variant& MapView::operator[](const key_type& key) const { return impl->asMap()[key]; }
+
+const std::map<MapView::key_type, Variant>& MapView::asMap() const { return impl->asMap(); }
+
+std::ostream& operator<<(std::ostream& out, const MapView& m)
+{
+ out << m.asMap();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Message.cpp b/qpid/cpp/src/qpid/messaging/Message.cpp
index 1d844b3027..fb4e800eaa 100644
--- a/qpid/cpp/src/qpid/messaging/Message.cpp
+++ b/qpid/cpp/src/qpid/messaging/Message.cpp
@@ -27,7 +27,7 @@ namespace messaging {
Message::Message(const std::string& bytes) : impl(new MessageImpl(bytes)) {}
Message::Message(const char* bytes, size_t count) : impl(new MessageImpl(bytes, count)) {}
-Message::Message(const Message& m) : impl(new MessageImpl(m.getBytes())) {}
+Message::Message(const Message& m) : impl(new MessageImpl(m.getContent())) {}
Message::~Message() { delete impl; }
Message& Message::operator=(const Message& m) { *impl = *m.impl; return *this; }
@@ -44,27 +44,15 @@ const std::string& Message::getContentType() const { return impl->getContentType
const VariantMap& Message::getHeaders() const { return impl->getHeaders(); }
VariantMap& Message::getHeaders() { return impl->getHeaders(); }
-void Message::setBytes(const std::string& c) { impl->setBytes(c); }
-void Message::setBytes(const char* chars, size_t count) { impl->setBytes(chars, count); }
-const std::string& Message::getBytes() const { return impl->getBytes(); }
-std::string& Message::getBytes() { return impl->getBytes(); }
+void Message::setContent(const std::string& c) { impl->setBytes(c); }
+void Message::setContent(const char* chars, size_t count) { impl->setBytes(chars, count); }
+const std::string& Message::getContent() const { return impl->getBytes(); }
+std::string& Message::getContent() { return impl->getBytes(); }
-const char* Message::getRawContent() const { return impl->getBytes().data(); }
-size_t Message::getContentSize() const { return impl->getBytes().size(); }
-
-MessageContent& Message::getContent() { return *impl; }
-const MessageContent& Message::getContent() const { return *impl; }
-void Message::setContent(const std::string& s) { *impl = s; }
-void Message::setContent(const Variant::Map& m) { *impl = m; }
-void Message::setContent(const Variant::List& l) { *impl = l; }
-
-void Message::encode(Codec& codec) { impl->encode(codec); }
-
-void Message::decode(Codec& codec) { impl->decode(codec); }
-
-std::ostream& operator<<(std::ostream& out, const MessageContent& content)
+void Message::getContent(std::pair<const char*, size_t>& content) const
{
- return content.print(out);
+ content.first = impl->getBytes().data();
+ content.second = impl->getBytes().size();
}
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
index 5df9218e03..e17fccd64f 100644
--- a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
@@ -28,8 +28,8 @@ namespace {
const std::string EMPTY_STRING = "";
}
-MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VAR_VOID), internalId(0) {}
-MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VAR_VOID), internalId(0) {}
+MessageImpl::MessageImpl(const std::string& c) : bytes(c), internalId(0) {}
+MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), internalId(0) {}
void MessageImpl::setReplyTo(const Address& d) { replyTo = d; }
const Address& MessageImpl::getReplyTo() const { return replyTo; }
@@ -44,155 +44,14 @@ const VariantMap& MessageImpl::getHeaders() const { return headers; }
VariantMap& MessageImpl::getHeaders() { return headers; }
//should these methods be on MessageContent?
-void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; }
-void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); }
+void MessageImpl::setBytes(const std::string& c) { bytes = c; }
+void MessageImpl::setBytes(const char* chars, size_t count) { bytes.assign(chars, count); }
const std::string& MessageImpl::getBytes() const { return bytes; }
std::string& MessageImpl::getBytes() { return bytes; }
-
-Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; }
-
-std::ostream& MessageImpl::print(std::ostream& out) const
-{
- if (type == VAR_MAP) {
- return out << content.asMap();
- } else if (type == VAR_LIST) {
- return out << content.asList();
- } else {
- return out << bytes;
- }
-}
-
-template <class T> MessageContent& MessageImpl::append(T& t)
-{
- if (type == VAR_VOID) {
- //TODO: this is inefficient, probably want to hold on to the stream object
- std::stringstream s;
- s << bytes;
- s << t;
- bytes = s.str();
- } else if (type == VAR_LIST) {
- content.asList().push_back(Variant(t));
- } else {
- throw InvalidConversion("<< operator only valid on strings and lists");
- }
- return *this;
-}
-
-MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); }
-MessageContent& MessageImpl::operator<<(const char* v) { return append(v); }
-MessageContent& MessageImpl::operator<<(bool v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(double v) { return append(v); }
-MessageContent& MessageImpl::operator<<(float v) { return append(v); }
-MessageContent& MessageImpl::operator=(const std::string& s)
-{
- type = VAR_VOID;
- bytes = s;
- return *this;
-}
-MessageContent& MessageImpl::operator=(const char* c)
-{
- type = VAR_VOID;
- bytes = c;
- return *this;
-}
-MessageContent& MessageImpl::operator=(const Variant::Map& m)
-{
- type = VAR_MAP;
- content = m;
- return *this;
-}
-
-MessageContent& MessageImpl::operator=(const Variant::List& l)
-{
- type = VAR_LIST;
- content = l;
- return *this;
-}
-
-void MessageImpl::encode(Codec& codec)
-{
- if (content.getType() != VAR_VOID) {
- bytes = EMPTY_STRING;
- codec.encode(content, bytes);
- }
-}
-
-void MessageImpl::getEncodedContent(Codec& codec, std::string& out) const
-{
- if (content.getType() != VAR_VOID) {
- codec.encode(content, out);
- } else {
- out = bytes;
- }
-}
-
-void MessageImpl::decode(Codec& codec)
-{
- codec.decode(bytes, content);
- if (content.getType() == VAR_MAP) type = VAR_MAP;
- else if (content.getType() == VAR_LIST) type = VAR_LIST;
- else type = VAR_VOID;//TODO: what if codec set some type other than map or list??
-}
-
void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; }
qpid::framing::SequenceNumber MessageImpl::getInternalId() { return internalId; }
-bool MessageImpl::isVoid() const { return type == VAR_VOID; }
-
-const std::string& MessageImpl::asString() const
-{
- if (isVoid()) return getBytes();
- else return content.getString();//will throw an error
-}
-std::string& MessageImpl::asString()
-{
- if (isVoid()) return getBytes();
- else return content.getString();//will throw an error
-}
-
-const char* MessageImpl::asChars() const
-{
- if (!isVoid()) throw InvalidConversion("Content is of structured type.");
- return bytes.data();
-}
-size_t MessageImpl::size() const
-{
- return bytes.size();
-}
-
-const Variant::Map& MessageImpl::asMap() const { return content.asMap(); }
-Variant::Map& MessageImpl::asMap()
-{
- if (isVoid()) {
- content = Variant::Map();
- type = VAR_MAP;
- }
- return content.asMap();
-}
-bool MessageImpl::isMap() const { return type == VAR_MAP; }
-
-const Variant::List& MessageImpl::asList() const { return content.asList(); }
-Variant::List& MessageImpl::asList()
-{
- if (isVoid()) {
- content = Variant::List();
- type = VAR_LIST;
- }
- return content.asList();
-}
-bool MessageImpl::isList() const { return type == VAR_LIST; }
-
-void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VAR_VOID; }
-
MessageImpl& MessageImplAccess::get(Message& msg)
{
return *msg.impl;
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.h b/qpid/cpp/src/qpid/messaging/MessageImpl.h
index 1173e7570a..4939cdc5cc 100644
--- a/qpid/cpp/src/qpid/messaging/MessageImpl.h
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.h
@@ -22,15 +22,13 @@
*
*/
#include "qpid/messaging/Address.h"
-#include "qpid/messaging/Codec.h"
-#include "qpid/messaging/MessageContent.h"
#include "qpid/messaging/Variant.h"
#include "qpid/framing/SequenceNumber.h"
namespace qpid {
namespace messaging {
-struct MessageImpl : MessageContent
+struct MessageImpl
{
Address replyTo;
std::string subject;
@@ -38,8 +36,6 @@ struct MessageImpl : MessageContent
Variant::Map headers;
std::string bytes;
- Variant content;//used only for LIST and MAP
- VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value
qpid::framing::SequenceNumber internalId;
@@ -66,54 +62,6 @@ struct MessageImpl : MessageContent
void setInternalId(qpid::framing::SequenceNumber id);
qpid::framing::SequenceNumber getInternalId();
- bool isVoid() const;
-
- const std::string& asString() const;
- std::string& asString();
-
- const char* asChars() const;
- size_t size() const;
-
- const Variant::Map& asMap() const;
- Variant::Map& asMap();
- bool isMap() const;
-
- const Variant::List& asList() const;
- Variant::List& asList();
- bool isList() const;
-
- void clear();
-
- void getEncodedContent(Codec& codec, std::string&) const;
- void encode(Codec& codec);
- void decode(Codec& codec);
-
- Variant& operator[](const std::string&);
-
- std::ostream& print(std::ostream& out) const;
-
- //operator<< for variety of types...
- MessageContent& operator<<(const std::string&);
- MessageContent& operator<<(const char*);
- MessageContent& operator<<(bool);
- MessageContent& operator<<(int8_t);
- MessageContent& operator<<(int16_t);
- MessageContent& operator<<(int32_t);
- MessageContent& operator<<(int64_t);
- MessageContent& operator<<(uint8_t);
- MessageContent& operator<<(uint16_t);
- MessageContent& operator<<(uint32_t);
- MessageContent& operator<<(uint64_t);
- MessageContent& operator<<(double);
- MessageContent& operator<<(float);
-
- //assignment from string, map and list
- MessageContent& operator=(const std::string&);
- MessageContent& operator=(const char*);
- MessageContent& operator=(const Variant::Map&);
- MessageContent& operator=(const Variant::List&);
-
- template <class T> MessageContent& append(T& t);
};
class Message;
diff --git a/qpid/cpp/src/qpid/sys/AsynchIO.h b/qpid/cpp/src/qpid/sys/AsynchIO.h
index fb02183359..419770568a 100644
--- a/qpid/cpp/src/qpid/sys/AsynchIO.h
+++ b/qpid/cpp/src/qpid/sys/AsynchIO.h
@@ -57,7 +57,7 @@ public:
class AsynchConnector {
public:
typedef boost::function1<void, const Socket&> ConnectedCallback;
- typedef boost::function2<void, int, std::string> FailedCallback;
+ typedef boost::function3<void, const Socket&, int, const std::string&> FailedCallback;
// Call create() to allocate a new AsynchConnector object with the
// specified poller, addressing, and callbacks.
@@ -70,7 +70,7 @@ public:
std::string hostname,
uint16_t port,
ConnectedCallback connCb,
- FailedCallback failCb = 0);
+ FailedCallback failCb);
protected:
AsynchConnector() {}
@@ -108,7 +108,7 @@ class AsynchIO {
public:
typedef AsynchIOBufferBase BufferBase;
- typedef boost::function2<bool, AsynchIO&, BufferBase*> ReadCallback;
+ typedef boost::function2<void, AsynchIO&, BufferBase*> ReadCallback;
typedef boost::function1<void, AsynchIO&> EofCallback;
typedef boost::function1<void, AsynchIO&> DisconnectCallback;
typedef boost::function2<void, AsynchIO&, const Socket&> ClosedCallback;
diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
index 8094abd43d..eb0f213547 100644
--- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
+++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
@@ -103,10 +103,31 @@ void AsynchIOHandler::giveReadCredit(int32_t credit) {
aio->startReading();
}
-bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
+void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
if (readError) {
- return false;
+ return;
+ }
+
+ // Check here for read credit
+ if (readCredit.get() != InfiniteCredit) {
+ if (readCredit.get() == 0) {
+ // FIXME aconway 2009-10-01: Workaround to avoid "false wakeups".
+ // readbuff is sometimes called with no credit.
+ // This should be fixed somewhere else to avoid such calls.
+ aio->unread(buff);
+ return;
+ }
+ // TODO In theory should be able to use an atomic operation before taking the lock
+ // but in practice there seems to be an unexplained race in that case
+ ScopedLock<Mutex> l(creditLock);
+ if (--readCredit == 0) {
+ assert(readCredit.get() >= 0);
+ if (readCredit.get() == 0) {
+ aio->stopReading();
+ }
+ }
}
+
size_t decoded = 0;
if (codec) { // Already initiated
try {
@@ -149,20 +170,6 @@ bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
// Give whole buffer back to aio subsystem
aio->queueReadBuffer(buff);
}
- // Check here for read credit
- if (readCredit.get() != InfiniteCredit) {
- // TODO In theory should be able to use an atomic operation before taking the lock
- // but in practice there seems to be an unexplained race in that case
- ScopedLock<Mutex> l(creditLock);
- if (--readCredit == 0) {
- assert(readCredit.get() >= 0);
- if (readCredit.get() == 0) {
- aio->stopReading();
- return false;
- }
- }
- }
- return true;
}
void AsynchIOHandler::eof(AsynchIO&) {
diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h
index 9785f445a4..e1885bac79 100644
--- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h
+++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h
@@ -65,7 +65,7 @@ class AsynchIOHandler : public OutputControl {
QPID_COMMON_EXTERN void giveReadCredit(int32_t credit);
// Input side
- QPID_COMMON_EXTERN bool readbuff(AsynchIO& aio, AsynchIOBufferBase* buff);
+ QPID_COMMON_EXTERN void readbuff(AsynchIO& aio, AsynchIOBufferBase* buff);
QPID_COMMON_EXTERN void eof(AsynchIO& aio);
QPID_COMMON_EXTERN void disconnect(AsynchIO& aio);
diff --git a/qpid/cpp/src/qpid/sys/LatencyTracker.h b/qpid/cpp/src/qpid/sys/LatencyTracker.h
deleted file mode 100644
index 3294528ff6..0000000000
--- a/qpid/cpp/src/qpid/sys/LatencyTracker.h
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef QPID_SYS_LATENCYTRACKER_H
-#define QPID_SYS_LATENCYTRACKER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/Time.h"
-#include <string>
-#include <limits>
-#include <map>
-
-namespace qpid {
-namespace sys {
-
-/**@file Tools for measuring latency. NOT SUITABLE FOR PROUDCTION BUILDS.
- * Uses should be compiled only if QPID_LATENCY_TRACKER is defined.
- * See the convenience macros at the end of this file.
- */
-
-/** Used by LatencyCounter and LatencyTracker below */
-class LatencyStatistic {
- public:
- LatencyStatistic(std::string name_) : name(name_), count(0), total(0), min(std::numeric_limits<int64_t>::max()), max(0) {}
- ~LatencyStatistic() { print(); }
-
- void record(Duration d) {
- total += d;
- ++count;
- if (d > max) max=d;
- if (d < min) min=d;
- }
-
- void print() {
- if (count) {
- double meanMsec = (double(total)/count)/TIME_MSEC;
- printf("\n==== Latency metric %s: samples=%lu mean=%fms (%f-%f)\n", name.c_str(), count, meanMsec, double(min)/TIME_MSEC, double(max)/TIME_MSEC);
- }
- else
- printf("\n==== Latency metric %s: no samples.\n", name.c_str());
- }
-
- private:
- std::string name;
- unsigned long count;
- int64_t total, min, max;
-};
-
-/** Measure delay between seeing the same value at start and finish. */
-template <class T> class LatencyTracker {
- public:
- LatencyTracker(std::string name) : measuring(false), stat(name) {}
-
- void start(T value) {
- sys::Mutex::ScopedLock l(lock);
- if (!measuring) {
- measureAt = value;
- measuring = true;
- startTime = AbsTime::now();
- }
- }
-
- void finish(T value) {
- sys::Mutex::ScopedLock l(lock);
- if(measuring && measureAt == value) {
- stat.record(Duration(startTime, AbsTime::now()));
- measuring = false;
- }
- }
-
- private:
- sys::Mutex lock;
- bool measuring;
- T measureAt;
- AbsTime startTime;
- LatencyStatistic stat;
-};
-
-
-/** Measures delay between the nth call to start and the nth call to finish.
- * E.g. to measure latency between sending & receiving an ordered stream of messages.
- */
-class LatencyCounter {
- public:
- LatencyCounter(std::string name) : measuring(false), startCount(0), finishCount(0), stat(name) {}
-
- void start() {
- sys::Mutex::ScopedLock l(lock);
- if (!measuring) {
- measureAt = startCount;
- measuring = true;
- startTime = AbsTime::now();
- }
- ++startCount;
- }
-
- void finish() {
- sys::Mutex::ScopedLock l(lock);
- if (measuring && measureAt == finishCount) {
- stat.record(Duration(startTime, AbsTime::now()));
- measuring = false;
- }
- ++finishCount;
- }
-
- private:
- sys::Mutex lock;
- bool measuring;
- uint64_t startCount, finishCount, measureAt;
- AbsTime startTime;
- LatencyStatistic stat;
-};
-
-/** Measures time spent in a scope. */
-class LatencyScope {
- public:
- LatencyScope(LatencyStatistic& s) : stat(s), startTime(AbsTime::now()) {}
-
- ~LatencyScope() {
- sys::Mutex::ScopedLock l(lock);
- stat.record(Duration(startTime, AbsTime::now()));
- }
-
- private:
- sys::Mutex lock;
- LatencyStatistic& stat;
- AbsTime startTime;
-};
-
-
-/** Macros to wrap latency tracking so disabled unless QPID_LATENCY_TRACKER is defined */
-
-#if defined(QPID_LATENCY_TRACKER)
-#define LATENCY_TRACK(X) X
-#else
-#define LATENCY_TRACK(X)
-#endif
-}} // namespace qpid::sys
-
-#endif /*!QPID_SYS_LATENCYTRACKER_H*/
diff --git a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
index 6eafb6cf0b..28ff140237 100644
--- a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
@@ -29,6 +29,7 @@
#include "qpid/sys/OutputControl.h"
#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
#include <memory>
#include <netdb.h>
@@ -304,8 +305,9 @@ void RdmaIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::F
sin.sin_port = htons(listeningPort);
sin.sin_addr.s_addr = INADDR_ANY;
+ SocketAddress sa("",boost::lexical_cast<std::string>(listeningPort));
listener.reset(
- new Rdma::Listener((const sockaddr&)(sin),
+ new Rdma::Listener(sa,
Rdma::ConnectionParams(65536, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(&RdmaIOProtocolFactory::established, this, poller, _1),
boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
@@ -331,24 +333,14 @@ void RdmaIOProtocolFactory::connected(Poller::shared_ptr poller, Rdma::Connectio
void RdmaIOProtocolFactory::connect(
Poller::shared_ptr poller,
- const std::string& host, int16_t p,
+ const std::string& host, int16_t port,
ConnectionCodec::Factory* f,
ConnectFailedCallback failed)
{
- ::addrinfo *res;
- ::addrinfo hints = {};
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- stringstream ss; ss << p;
- string port = ss.str();
- int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
- if (n<0) {
- throw Exception(QPID_MSG("Rdma: Cannot resolve " << host << ": " << ::gai_strerror(n)));
- }
-
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
Rdma::Connector* c =
new Rdma::Connector(
- *res->ai_addr,
+ sa,
Rdma::ConnectionParams(8000, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(&RdmaIOProtocolFactory::connected, this, poller, _1, _2, f),
boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
diff --git a/qpid/cpp/src/qpid/sys/Socket.h b/qpid/cpp/src/qpid/sys/Socket.h
index f389e99cb8..d108402682 100644
--- a/qpid/cpp/src/qpid/sys/Socket.h
+++ b/qpid/cpp/src/qpid/sys/Socket.h
@@ -31,6 +31,7 @@ namespace qpid {
namespace sys {
class Duration;
+class SocketAddress;
class Socket : public IOHandle
{
@@ -48,6 +49,7 @@ public:
void setNonblocking() const;
QPID_COMMON_EXTERN void connect(const std::string& host, uint16_t port) const;
+ QPID_COMMON_EXTERN void connect(const SocketAddress&) const;
QPID_COMMON_EXTERN void close() const;
diff --git a/qpid/cpp/src/qpid/sys/SocketAddress.h b/qpid/cpp/src/qpid/sys/SocketAddress.h
new file mode 100644
index 0000000000..fcb9c81d43
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/SocketAddress.h
@@ -0,0 +1,51 @@
+#ifndef _sys_SocketAddress_h
+#define _sys_SocketAddress_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
+#include <string>
+
+struct addrinfo;
+
+namespace qpid {
+namespace sys {
+
+class SocketAddress {
+ friend const ::addrinfo& getAddrInfo(const SocketAddress&);
+
+public:
+ /** Create a SocketAddress from hostname and port*/
+ QPID_COMMON_EXTERN SocketAddress(const std::string& host, const std::string& port);
+ QPID_COMMON_EXTERN ~SocketAddress();
+
+ std::string asString() const;
+
+private:
+ std::string host;
+ std::string port;
+ ::addrinfo* addrInfo;
+};
+
+}}
+#endif /*!_sys_SocketAddress_h*/
diff --git a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
index b456beb098..3377be98f1 100644
--- a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
@@ -46,7 +46,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory {
void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
void connect(Poller::shared_ptr, const std::string& host, int16_t port,
ConnectionCodec::Factory*,
- boost::function2<void, int, std::string> failed);
+ ConnectFailedCallback);
uint16_t getPort() const;
std::string getHost() const;
@@ -54,6 +54,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory {
private:
void established(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*,
bool isClient);
+ void connectFailed(const Socket&, int, const std::string&, ConnectFailedCallback);
};
// Static instance to initialise plugin
@@ -118,6 +119,15 @@ void AsynchIOProtocolFactory::accept(Poller::shared_ptr poller,
acceptor->start(poller);
}
+void AsynchIOProtocolFactory::connectFailed(
+ const Socket& s, int ec, const std::string& emsg,
+ ConnectFailedCallback failedCb)
+{
+ failedCb(ec, emsg);
+ s.close();
+ delete &s;
+}
+
void AsynchIOProtocolFactory::connect(
Poller::shared_ptr poller,
const std::string& host, int16_t port,
@@ -131,13 +141,14 @@ void AsynchIOProtocolFactory::connect(
// is no longer needed.
Socket* socket = new Socket();
- AsynchConnector::create (*socket,
- poller,
- host,
- port,
- boost::bind(&AsynchIOProtocolFactory::established,
- this, poller, _1, fact, true),
- failed);
+ AsynchConnector::create(*socket,
+ poller,
+ host,
+ port,
+ boost::bind(&AsynchIOProtocolFactory::established,
+ this, poller, _1, fact, true),
+ boost::bind(&AsynchIOProtocolFactory::connectFailed,
+ this, _1, _2, _3, failed));
}
}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 8545ebd9cb..c042dcef01 100644
--- a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -21,6 +21,7 @@
#include "qpid/sys/AsynchIO.h"
#include "qpid/sys/Socket.h"
+#include "qpid/sys/SocketAddress.h"
#include "qpid/sys/Poller.h"
#include "qpid/sys/DispatchHandle.h"
#include "qpid/sys/Time.h"
@@ -37,6 +38,7 @@
#include <string.h>
#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
using namespace qpid::sys;
@@ -161,11 +163,12 @@ class AsynchConnector : public qpid::sys::AsynchConnector,
private:
void connComplete(DispatchHandle& handle);
- void failure(int, std::string);
+ void failure(int, const std::string&);
private:
ConnectedCallback connCallback;
FailedCallback failCallback;
+ std::string errMsg;
const Socket& socket;
public:
@@ -174,7 +177,7 @@ public:
std::string hostname,
uint16_t port,
ConnectedCallback connCb,
- FailedCallback failCb = 0);
+ FailedCallback failCb);
};
AsynchConnector::AsynchConnector(const Socket& s,
@@ -192,12 +195,17 @@ AsynchConnector::AsynchConnector(const Socket& s,
socket(s)
{
socket.setNonblocking();
+ SocketAddress sa(hostname, boost::lexical_cast<std::string>(port));
try {
- socket.connect(hostname, port);
- startWatch(poller);
+ socket.connect(sa);
} catch(std::exception& e) {
- failure(-1, std::string(e.what()));
+ // Defer reporting failure
+ startWatch(poller);
+ errMsg = e.what();
+ DispatchHandle::call(boost::bind(&AsynchConnector::failure, this, -1, errMsg));
+ return;
}
+ startWatch(poller);
}
void AsynchConnector::connComplete(DispatchHandle& h)
@@ -209,17 +217,13 @@ void AsynchConnector::connComplete(DispatchHandle& h)
connCallback(socket);
DispatchHandle::doDelete();
} else {
- failure(errCode, std::string(strError(errCode)));
+ failure(errCode, strError(errCode));
}
}
-void AsynchConnector::failure(int errCode, std::string message)
+void AsynchConnector::failure(int errCode, const std::string& message)
{
- if (failCallback)
- failCallback(errCode, message);
-
- socket.close();
- delete &socket;
+ failCallback(socket, errCode, message);
DispatchHandle::doDelete();
}
@@ -467,7 +471,8 @@ void AsynchIO::readable(DispatchHandle& h) {
threadReadTotal += rc;
readTotal += rc;
- if (!readCallback(*this, buff)) {
+ readCallback(*this, buff);
+ if (readingStopped) {
// We have been flow controlled.
break;
}
diff --git a/qpid/cpp/src/qpid/sys/posix/Socket.cpp b/qpid/cpp/src/qpid/sys/posix/Socket.cpp
index 31044be9ca..02004b1999 100644
--- a/qpid/cpp/src/qpid/sys/posix/Socket.cpp
+++ b/qpid/cpp/src/qpid/sys/posix/Socket.cpp
@@ -21,6 +21,7 @@
#include "qpid/sys/Socket.h"
+#include "qpid/sys/SocketAddress.h"
#include "qpid/sys/posix/check.h"
#include "qpid/sys/posix/PrivatePosix.h"
@@ -36,6 +37,7 @@
#include <iostream>
#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
namespace qpid {
namespace sys {
@@ -126,42 +128,23 @@ void Socket::setNonblocking() const {
QPID_POSIX_CHECK(::fcntl(impl->fd, F_SETFL, O_NONBLOCK));
}
-namespace {
-const char* h_errstr(int e) {
- switch (e) {
- case HOST_NOT_FOUND: return "Host not found";
- case NO_ADDRESS: return "Name does not have an IP address";
- case TRY_AGAIN: return "A temporary error occurred on an authoritative name server.";
- case NO_RECOVERY: return "Non-recoverable name server error";
- default: return "Unknown error";
- }
-}
+void Socket::connect(const std::string& host, uint16_t port) const
+{
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
+ connect(sa);
}
-void Socket::connect(const std::string& host, uint16_t p) const
+void Socket::connect(const SocketAddress& addr) const
{
- std::stringstream portstream;
- portstream << p;
- std::string port = portstream.str();
- connectname = host + ":" + port;
+ connectname = addr.asString();
const int& socket = impl->fd;
- ::addrinfo *res;
- ::addrinfo hints;
- ::memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well
- hints.ai_socktype = SOCK_STREAM;
- int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
- if (n != 0)
- throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n)));
// TODO the correct thing to do here is loop on failure until you've used all the returned addresses
- if ((::connect(socket, res->ai_addr, res->ai_addrlen) < 0) &&
+ if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) < 0) &&
(errno != EINPROGRESS)) {
- ::freeaddrinfo(res);
- throw qpid::Exception(QPID_MSG(strError(errno) << ": " << host << ":" << port));
+ throw Exception(QPID_MSG(strError(errno) << ": " << connectname));
}
- ::freeaddrinfo(res);
}
void
@@ -178,15 +161,14 @@ int Socket::listen(uint16_t port, int backlog) const
const int& socket = impl->fd;
int yes=1;
QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
- struct sockaddr_in name;
- name.sin_family = AF_INET;
- name.sin_port = htons(port);
- name.sin_addr.s_addr = 0;
- if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
+
+ SocketAddress sa("", boost::lexical_cast<std::string>(port));
+ if (::bind(socket, getAddrInfo(sa).ai_addr, getAddrInfo(sa).ai_addrlen) < 0)
throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
if (::listen(socket, backlog) < 0)
throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
-
+
+ struct sockaddr_in name;
socklen_t namelen = sizeof(name);
if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
throw QPID_POSIX_ERROR(errno);
@@ -226,9 +208,10 @@ std::string Socket::getPeername() const
std::string Socket::getPeerAddress() const
{
- if (!connectname.empty())
- return std::string (connectname);
- return getName(impl->fd, false, true);
+ if (connectname.empty()) {
+ connectname = getName(impl->fd, false, true);
+ }
+ return connectname;
}
std::string Socket::getLocalAddress() const
diff --git a/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp b/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp
new file mode 100644
index 0000000000..fe8812299c
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/SocketAddress.h"
+
+#include "qpid/sys/posix/check.h"
+
+#include <sys/socket.h>
+#include <string.h>
+#include <netdb.h>
+
+namespace qpid {
+namespace sys {
+
+SocketAddress::SocketAddress(const std::string& host0, const std::string& port0) :
+ host(host0),
+ port(port0),
+ addrInfo(0)
+{
+ ::addrinfo hints;
+ ::memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well
+ hints.ai_socktype = SOCK_STREAM;
+
+ const char* node = 0;
+ if (host.empty()) {
+ hints.ai_flags |= AI_PASSIVE;
+ } else {
+ node = host.c_str();
+ }
+ const char* service = port.empty() ? "0" : port.c_str();
+
+ int n = ::getaddrinfo(node, service, &hints, &addrInfo);
+ if (n != 0)
+ throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n)));
+}
+
+SocketAddress::~SocketAddress()
+{
+ ::freeaddrinfo(addrInfo);
+}
+
+std::string SocketAddress::asString() const
+{
+ return host + ":" + port;
+}
+
+const ::addrinfo& getAddrInfo(const SocketAddress& sa)
+{
+ return *sa.addrInfo;
+}
+
+}}
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
index 9da6c835ce..d39f7885a5 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
@@ -40,6 +40,7 @@ using std::rand;
using qpid::sys::Poller;
using qpid::sys::Dispatcher;
+using qpid::sys::SocketAddress;
using qpid::sys::AbsTime;
using qpid::sys::Duration;
using qpid::sys::TIME_SEC;
@@ -154,18 +155,8 @@ using namespace qpid::tests;
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
- ::addrinfo *res;
- ::addrinfo hints = {};
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
+ string host = args[1];
string port = (args.size() < 3) ? "20079" : args[2];
- int n = ::getaddrinfo(args[1].c_str(), port.c_str(), &hints, &res);
- if (n<0) {
- cerr << "Can't find information for: " << args[1] << "\n";
- return 1;
- } else {
- cout << "Connecting to: " << args[1] << ":" << port <<"\n";
- }
if (args.size() > 3)
msgsize = atoi(args[3].c_str());
@@ -181,8 +172,10 @@ int main(int argc, char* argv[]) {
boost::shared_ptr<Poller> p(new Poller());
Dispatcher d(p);
+ SocketAddress sa(host, port);
+ cout << "Connecting to: " << sa.asString() <<"\n";
Rdma::Connector c(
- *res->ai_addr,
+ sa,
Rdma::ConnectionParams(msgsize, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(&connected, p, _1, _2),
boost::bind(&connectionError, p, _1, _2),
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp
index 491c1612fd..8d06fccba1 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp
@@ -26,6 +26,7 @@
#include <iostream>
#include <boost/bind.hpp>
+using qpid::sys::SocketAddress;
using qpid::sys::DispatchHandle;
using qpid::sys::Poller;
@@ -461,7 +462,7 @@ namespace Rdma {
}
Listener::Listener(
- const sockaddr& src,
+ const SocketAddress& src,
const ConnectionParams& cp,
EstablishedCallback ec,
ErrorCallback errc,
@@ -541,7 +542,7 @@ namespace Rdma {
}
Connector::Connector(
- const sockaddr& dst,
+ const SocketAddress& dst,
const ConnectionParams& cp,
ConnectedCallback cc,
ErrorCallback errc,
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h
index 697d9387ce..12a1b98d24 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h
@@ -27,6 +27,7 @@
#include "qpid/sys/Dispatcher.h"
#include "qpid/sys/DispatchHandle.h"
#include "qpid/sys/Mutex.h"
+#include "qpid/sys/SocketAddress.h"
#include <netinet/in.h>
@@ -173,14 +174,14 @@ namespace Rdma {
class Listener : public ConnectionManager
{
- sockaddr src_addr;
+ qpid::sys::SocketAddress src_addr;
ConnectionParams checkConnectionParams;
ConnectionRequestCallback connectionRequestCallback;
EstablishedCallback establishedCallback;
public:
Listener(
- const sockaddr& src,
+ const qpid::sys::SocketAddress& src,
const ConnectionParams& cp,
EstablishedCallback ec,
ErrorCallback errc,
@@ -198,14 +199,14 @@ namespace Rdma {
class Connector : public ConnectionManager
{
- sockaddr dst_addr;
+ qpid::sys::SocketAddress dst_addr;
ConnectionParams connectionParams;
RejectedCallback rejectedCallback;
ConnectedCallback connectedCallback;
public:
Connector(
- const sockaddr& dst,
+ const qpid::sys::SocketAddress& dst,
const ConnectionParams& cp,
ConnectedCallback cc,
ErrorCallback errc,
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
index 07d6379362..4c11ba23eb 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
@@ -35,6 +35,7 @@ using std::string;
using std::cout;
using std::cerr;
+using qpid::sys::SocketAddress;
using qpid::sys::Poller;
using qpid::sys::Dispatcher;
@@ -144,20 +145,15 @@ using namespace qpid::tests;
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
- ::sockaddr_in sin;
-
- int port = (args.size() < 2) ? 20079 : atoi(args[1].c_str());
+ std::string port = (args.size() < 2) ? "20079" : args[1];
cout << "Listening on port: " << port << "\n";
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- sin.sin_addr.s_addr = INADDR_ANY;
-
try {
boost::shared_ptr<Poller> p(new Poller());
Dispatcher d(p);
- Rdma::Listener a((const sockaddr&)(sin),
+ SocketAddress sa("", port);
+ Rdma::Listener a(sa,
Rdma::ConnectionParams(16384, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(connected, p, _1),
connectionError,
diff --git a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
index aa2e516e6b..e11497dc02 100644
--- a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
+++ b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
@@ -350,9 +350,9 @@ namespace Rdma {
return ConnectionEvent(e);
}
- void bind(sockaddr& src_addr) const {
+ void bind(qpid::sys::SocketAddress& src_addr) const {
assert(id.get());
- CHECK(::rdma_bind_addr(id.get(), &src_addr));
+ CHECK(::rdma_bind_addr(id.get(), getAddrInfo(src_addr).ai_addr));
}
void listen(int backlog = DEFAULT_BACKLOG) const {
@@ -361,12 +361,11 @@ namespace Rdma {
}
void resolve_addr(
- sockaddr& dst_addr,
- sockaddr* src_addr = 0,
+ qpid::sys::SocketAddress& dst_addr,
int timeout_ms = DEFAULT_TIMEOUT) const
{
assert(id.get());
- CHECK(::rdma_resolve_addr(id.get(), src_addr, &dst_addr, timeout_ms));
+ CHECK(::rdma_resolve_addr(id.get(), 0, getAddrInfo(dst_addr).ai_addr, timeout_ms));
}
void resolve_route(int timeout_ms = DEFAULT_TIMEOUT) const {
diff --git a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp
index 8905b87838..475b18600d 100644
--- a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp
+++ b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp
@@ -634,7 +634,7 @@ void AsynchIO::readComplete(AsynchReadResult *result) {
if (status == 0 && bytes > 0) {
bool restartRead = true; // May not if receiver doesn't want more
if (readCallback)
- restartRead = readCallback(*this, result->getBuff());
+ readCallback(*this, result->getBuff());
if (restartRead)
startReading();
}
diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
index 8a1ef6149e..472ca28954 100644
--- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
@@ -206,45 +206,22 @@ void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldT
PreRoute pr(msg, this);
try {
XmlBinding::vector::ConstPtr p;
- {
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ {
RWlock::ScopedRlock l(lock);
- p = bindingsMap[routingKey].snapshot();
- if (!p) return;
- }
- int count(0);
+ p = bindingsMap[routingKey].snapshot();
+ if (!p.get()) return;
+ }
for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) {
if (matches((*i)->xquery, msg, args, (*i)->parse_message_content)) {
- msg.deliverTo((*i)->queue);
- count++;
- QPID_LOG(trace, "Delivered to queue" );
-
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched ();
+ b->push_back(*i);
}
- }
- if (!count) {
- QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- } else {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- }
+ }
+ doRoute(msg, b);
} catch (...) {
QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey);
}
-
-
}
diff --git a/qpid/cpp/src/qpidd.cpp b/qpid/cpp/src/qpidd.cpp
index 1839a62205..f2b46942fb 100644
--- a/qpid/cpp/src/qpidd.cpp
+++ b/qpid/cpp/src/qpidd.cpp
@@ -36,25 +36,29 @@ int main(int argc, char* argv[])
{
try
{
- {
- BootstrapOptions bootOptions(argv[0]);
- string defaultPath (bootOptions.module.loadDir);
- // Parse only the common, load, and log options to see which
- // modules need to be loaded. Once the modules are loaded,
- // the command line will be re-parsed with all of the
- // module-supplied options.
+ BootstrapOptions bootOptions(argv[0]);
+ string defaultPath (bootOptions.module.loadDir);
+ // Parse only the common, load, and log options to see which
+ // modules need to be loaded. Once the modules are loaded,
+ // the command line will be re-parsed with all of the
+ // module-supplied options.
+ try {
bootOptions.parse (argc, argv, bootOptions.common.config, true);
qpid::log::Logger::instance().configure(bootOptions.log);
+ } catch (const std::exception& e) {
+ // Couldn't configure logging so write the message direct to stderr.
+ cerr << "Unexpected error: " << e.what() << endl;
+ return 1;
+ }
- for (vector<string>::iterator iter = bootOptions.module.load.begin();
- iter != bootOptions.module.load.end();
- iter++)
- qpid::tryShlib (iter->data(), false);
+ for (vector<string>::iterator iter = bootOptions.module.load.begin();
+ iter != bootOptions.module.load.end();
+ iter++)
+ qpid::tryShlib (iter->data(), false);
- if (!bootOptions.module.noLoad) {
- bool isDefault = defaultPath == bootOptions.module.loadDir;
- qpid::loadModuleDir (bootOptions.module.loadDir, isDefault);
- }
+ if (!bootOptions.module.noLoad) {
+ bool isDefault = defaultPath == bootOptions.module.loadDir;
+ qpid::loadModuleDir (bootOptions.module.loadDir, isDefault);
}
// Parse options
diff --git a/qpid/cpp/src/tests/AsyncCompletion.cpp b/qpid/cpp/src/tests/AsyncCompletion.cpp
index 4492e6b6bc..e32097106f 100644
--- a/qpid/cpp/src/tests/AsyncCompletion.cpp
+++ b/qpid/cpp/src/tests/AsyncCompletion.cpp
@@ -70,9 +70,11 @@ class AsyncCompletionMessageStore : public NullMessageStore {
QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite)
QPID_AUTO_TEST_CASE(testWaitTillComplete) {
- AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore;
SessionFixture fix;
- fix.broker->setStore(store); // Broker will delete store.
+ AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore;
+ boost::shared_ptr<qpid::broker::MessageStore> p;
+ p.reset(store);
+ fix.broker->setStore(p);
AsyncSession s = fix.session;
static const int count = 3;
diff --git a/qpid/cpp/src/tests/ClusterFixture.h b/qpid/cpp/src/tests/ClusterFixture.h
index 5952cc1736..1eee32b9a4 100644
--- a/qpid/cpp/src/tests/ClusterFixture.h
+++ b/qpid/cpp/src/tests/ClusterFixture.h
@@ -75,10 +75,10 @@ class ClusterFixture : public vector<uint16_t> {
/** @param localIndex can be -1 meaning don't automatically start a local broker.
* A local broker can be started with addLocal().
*/
- ClusterFixture(size_t n, const Args& args, int localIndex=0);
+ ClusterFixture(size_t n, const Args& args, int localIndex=-1);
/**@param updateArgs function is passed the index of the cluster member and can update the arguments. */
- ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs, int localIndex);
+ ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs, int localIndex=-1);
void add(size_t n) { for (size_t i=0; i < n; ++i) add(); }
void add(); // Add a broker.
diff --git a/qpid/cpp/src/tests/ExchangeTest.cpp b/qpid/cpp/src/tests/ExchangeTest.cpp
index 44835c6184..88a1cd99c2 100644
--- a/qpid/cpp/src/tests/ExchangeTest.cpp
+++ b/qpid/cpp/src/tests/ExchangeTest.cpp
@@ -60,7 +60,7 @@ QPID_AUTO_TEST_CASE(testMe)
queue.reset();
queue2.reset();
- intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", "id"));
+ intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", false, "id"));
DeliverableMessage msg(msgPtr);
topic.route(msg, "abc", 0);
direct.route(msg, "abc", 0);
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index a15ba3578c..15133505a3 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -22,6 +22,7 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src
PUBLIC_INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include # Use public API only
abs_builddir=@abs_builddir@
+abs_srcdir=@abs_srcdir@
extra_libs =
lib_client = $(abs_builddir)/../libqpidclient.la
lib_common = $(abs_builddir)/../libqpidcommon.la
@@ -275,7 +276,6 @@ qpid_stream_INCLUDES=$(PUBLIC_INCLUDES)
qpid_stream_SOURCES=qpid_stream.cpp
qpid_stream_LDADD=$(lib_client)
-
TESTS_ENVIRONMENT = \
VALGRIND=$(VALGRIND) \
srcdir=$(srcdir) \
@@ -311,7 +311,7 @@ EXTRA_DIST += \
TxMocks.h \
replication_test \
run_perftest \
- ring_queue_test \
+ ring_queue_test \
run_ring_queue_test
check_LTLIBRARIES += libdlclose_noop.la
@@ -327,25 +327,47 @@ LONG_TESTS+=start_broker fanout_perftest shared_perftest multiq_perftest topic_p
run_failover_soak reliable_replication_test \
federated_cluster_test_with_node_failure
-EXTRA_DIST+=fanout_perftest shared_perftest multiq_perftest topic_perftest run_failover_soak reliable_replication_test \
- federated_cluster_test_with_node_failure \
- tests.sln \
- client_test.vcproj \
- consume.vcproj \
- echotest.vcproj \
- header_test.vcproj \
- latencytest.vcproj \
- perftest.vcproj \
- publish.vcproj \
- receiver.vcproj \
- sender.vcproj \
- shlibtest.vcproj \
- topic_listener.vcproj \
- topic_publisher.vcproj \
- txjob.vcproj \
- txshift.vcproj \
- txtest.vcproj \
- unit_test.vcproj
+EXTRA_DIST+= \
+ python_env.sh \
+ fanout_perftest \
+ shared_perftest \
+ multiq_perftest \
+ topic_perftest \
+ run_failover_soak \
+ reliable_replication_test \
+ federated_cluster_test_with_node_failure \
+ tests.sln \
+ client_test.vcproj \
+ consume.vcproj \
+ echotest.vcproj \
+ header_test.vcproj \
+ latencytest.vcproj \
+ perftest.vcproj \
+ publish.vcproj \
+ receiver.vcproj \
+ sender.vcproj \
+ shlibtest.vcproj \
+ topic_listener.vcproj \
+ topic_publisher.vcproj \
+ txjob.vcproj \
+ txshift.vcproj \
+ txtest.vcproj \
+ unit_test.vcproj
check-long:
$(MAKE) check TESTS="$(LONG_TESTS)" VALGRIND=
+
+check: python_prep
+
+PYTHON_SRC_DIR=$(abs_srcdir)/../../../python
+PYTHON_BLD_DIR=$(abs_builddir)/python
+AMQP_SPEC_DIR=$(abs_srcdir)/../../../specs
+
+# Generate python client as part of the all-am target so it gets built before tests.
+all-am: python_prep
+
+python_prep:
+ if test -d $(PYTHON_SRC_DIR) -a -d $(AMQP_SPEC_DIR); \
+ then $(MAKE) -C $(PYTHON_SRC_DIR) install PREFIX=$(PYTHON_BLD_DIR) PYTHON_LIB=$(PYTHON_BLD_DIR) EXEC_PREFIX=$(PYTHON_BLD_DIR)/commands AMQP_SPEC_DIR=$(AMQP_SPEC_DIR); \
+ else echo "WARNING: python client not built, missing one of $(PYTHON_SRC_DIR) $(AMQP_SPEC_DIR)"; fi
+
diff --git a/qpid/cpp/src/tests/MessageUtils.h b/qpid/cpp/src/tests/MessageUtils.h
index dae74cce7d..a1b140d484 100644
--- a/qpid/cpp/src/tests/MessageUtils.h
+++ b/qpid/cpp/src/tests/MessageUtils.h
@@ -34,7 +34,8 @@ namespace tests {
struct MessageUtils
{
static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
- const Uuid& messageId=Uuid(true), uint64_t contentSize = 0)
+ const bool durable = false, const Uuid& messageId=Uuid(true),
+ uint64_t contentSize = 0)
{
boost::intrusive_ptr<broker::Message> msg(new broker::Message());
@@ -47,6 +48,8 @@ struct MessageUtils
props->setContentLength(contentSize);
props->setMessageId(messageId);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ if (durable)
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(2);
return msg;
}
diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp
index f5a5420d3a..206f5ba691 100644
--- a/qpid/cpp/src/tests/MessagingSessionTests.cpp
+++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp
@@ -22,6 +22,10 @@
#include "test_tools.h"
#include "BrokerFixture.h"
#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/ListContent.h"
+#include "qpid/messaging/ListView.h"
+#include "qpid/messaging/MapContent.h"
+#include "qpid/messaging/MapView.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/MessageListener.h"
#include "qpid/messaging/Receiver.h"
@@ -160,7 +164,7 @@ struct MessageDataCollector : MessageListener
std::vector<std::string> messageData;
void received(Message& message) {
- messageData.push_back(message.getBytes());
+ messageData.push_back(message.getContent());
}
};
@@ -169,7 +173,7 @@ std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duratio
std::vector<std::string> data;
Message message;
for (int i = 0; i < count && receiver.fetch(message, timeout); i++) {
- data.push_back(message.getBytes());
+ data.push_back(message.getContent());
}
return data;
}
@@ -183,7 +187,7 @@ QPID_AUTO_TEST_CASE(testSimpleSendReceive)
Receiver receiver = fix.session.createReceiver(fix.queue);
Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
fix.session.acknowledge();
- BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+ BOOST_CHECK_EQUAL(in.getContent(), out.getContent());
}
QPID_AUTO_TEST_CASE(testSendReceiveHeaders)
@@ -199,7 +203,7 @@ QPID_AUTO_TEST_CASE(testSendReceiveHeaders)
Message in;
for (uint i = 0; i < 10; ++i) {
BOOST_CHECK(receiver.fetch(in, 5 * qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+ BOOST_CHECK_EQUAL(in.getContent(), out.getContent());
BOOST_CHECK_EQUAL(in.getHeaders()["a"].asUint32(), i);
fix.session.acknowledge();
}
@@ -229,22 +233,22 @@ QPID_AUTO_TEST_CASE(testSimpleTopic)
Receiver sub1 = fix.session.createReceiver(fix.topic);
sub1.setCapacity(10u);
sub1.start();
- msg.setBytes("two");
+ msg.setContent("two");
sender.send(msg);
Receiver sub2 = fix.session.createReceiver(fix.topic);
sub2.setCapacity(10u);
sub2.start();
- msg.setBytes("three");
+ msg.setContent("three");
sender.send(msg);
Receiver sub3 = fix.session.createReceiver(fix.topic);
sub3.setCapacity(10u);
sub3.start();
- msg.setBytes("four");
+ msg.setContent("four");
sender.send(msg);
BOOST_CHECK_EQUAL(fetch(sub2, 2), boost::assign::list_of<std::string>("three")("four"));
sub2.cancel();
- msg.setBytes("five");
+ msg.setContent("five");
sender.send(msg);
BOOST_CHECK_EQUAL(fetch(sub1, 4), boost::assign::list_of<std::string>("two")("three")("four")("five"));
BOOST_CHECK_EQUAL(fetch(sub3, 2), boost::assign::list_of<std::string>("four")("five"));
@@ -274,7 +278,7 @@ QPID_AUTO_TEST_CASE(testSessionFetch)
for (uint i = 0; i < fix.queues.size(); i++) {
Message msg;
BOOST_CHECK(fix.session.fetch(msg, qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL(msg.getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(msg.getContent(), (boost::format("Message_%1%") % (i+1)).str());
}
}
@@ -307,13 +311,16 @@ QPID_AUTO_TEST_CASE(testMapMessage)
QueueFixture fix;
Sender sender = fix.session.createSender(fix.queue);
Message out;
- out.getContent().asMap()["abc"] = "def";
- out.getContent().asMap()["pi"] = 3.14f;
+ MapContent content(out);
+ content["abc"] = "def";
+ content["pi"] = 3.14f;
+ content.encode();
sender.send(out);
Receiver receiver = fix.session.createReceiver(fix.queue);
Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- BOOST_CHECK_EQUAL(in.getContent().asMap()["abc"].asString(), "def");
- BOOST_CHECK_EQUAL(in.getContent().asMap()["pi"].asFloat(), 3.14f);
+ MapView view(in);
+ BOOST_CHECK_EQUAL(view["abc"].asString(), "def");
+ BOOST_CHECK_EQUAL(view["pi"].asFloat(), 3.14f);
fix.session.acknowledge();
}
@@ -322,23 +329,31 @@ QPID_AUTO_TEST_CASE(testListMessage)
QueueFixture fix;
Sender sender = fix.session.createSender(fix.queue);
Message out;
- out.getContent() = Variant::List();
- out.getContent() << "abc";
- out.getContent() << 1234;
- out.getContent() << "def";
- out.getContent() << 56.789;
+ ListContent content(out);
+ content.push_back(Variant("abc"));
+ content.push_back(Variant(1234));
+ content.push_back(Variant("def"));
+ content.push_back(Variant(56.789));
+ content.encode();
sender.send(out);
Receiver receiver = fix.session.createReceiver(fix.queue);
Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- Variant::List& list = in.getContent().asList();
- BOOST_CHECK_EQUAL(list.size(), out.getContent().asList().size());
- BOOST_CHECK_EQUAL(list.front().asString(), "abc");
- list.pop_front();
- BOOST_CHECK_EQUAL(list.front().asInt64(), 1234);
- list.pop_front();
- BOOST_CHECK_EQUAL(list.front().asString(), "def");
- list.pop_front();
- BOOST_CHECK_EQUAL(list.front().asDouble(), 56.789);
+ ListView view(in);
+ BOOST_CHECK_EQUAL(view.size(), content.size());
+ BOOST_CHECK_EQUAL(view.front().asString(), "abc");
+ BOOST_CHECK_EQUAL(view.back().asDouble(), 56.789);
+
+ ListView::const_iterator i = view.begin();
+ BOOST_CHECK(i != view.end());
+ BOOST_CHECK_EQUAL(i->asString(), "abc");
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asInt64(), 1234);
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asString(), "def");
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asDouble(), 56.789);
+ BOOST_CHECK(++i == view.end());
+
fix.session.acknowledge();
}
@@ -352,10 +367,10 @@ QPID_AUTO_TEST_CASE(testReject)
sender.send(m2);
Receiver receiver = fix.session.createReceiver(fix.queue);
Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- BOOST_CHECK_EQUAL(in.getBytes(), m1.getBytes());
+ BOOST_CHECK_EQUAL(in.getContent(), m1.getContent());
fix.session.reject(in);
in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- BOOST_CHECK_EQUAL(in.getBytes(), m2.getBytes());
+ BOOST_CHECK_EQUAL(in.getContent(), m2.getContent());
fix.session.acknowledge();
}
@@ -384,15 +399,15 @@ QPID_AUTO_TEST_CASE(testAvailable)
for (uint i = 0; i < 5; ++i) {
BOOST_CHECK_EQUAL(fix.session.available(), 15u - 2*i);
BOOST_CHECK_EQUAL(r1.available(), 10u - i);
- BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str());
BOOST_CHECK_EQUAL(r2.available(), 5u - i);
- BOOST_CHECK_EQUAL(r2.fetch().getBytes(), (boost::format("B_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(r2.fetch().getContent(), (boost::format("B_%1%") % (i+1)).str());
fix.session.acknowledge();
}
for (uint i = 5; i < 10; ++i) {
BOOST_CHECK_EQUAL(fix.session.available(), 10u - i);
BOOST_CHECK_EQUAL(r1.available(), 10u - i);
- BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str());
}
}
@@ -405,7 +420,7 @@ QPID_AUTO_TEST_CASE(testPendingAck)
}
Receiver receiver = fix.session.createReceiver(fix.queue);
for (uint i = 0; i < 10; ++i) {
- BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(receiver.fetch().getContent(), (boost::format("Message_%1%") % (i+1)).str());
}
BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u);
fix.session.acknowledge();
@@ -431,7 +446,7 @@ QPID_AUTO_TEST_CASE(testPendingSend)
Receiver receiver = fix.session.createReceiver(fix.queue);
for (uint i = 0; i < 10; ++i) {
- BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(receiver.fetch().getContent(), (boost::format("Message_%1%") % (i+1)).str());
}
fix.session.acknowledge();
}
diff --git a/qpid/cpp/src/tests/PartialFailure.cpp b/qpid/cpp/src/tests/PartialFailure.cpp
index 8d9970f909..5de8ecb189 100644
--- a/qpid/cpp/src/tests/PartialFailure.cpp
+++ b/qpid/cpp/src/tests/PartialFailure.cpp
@@ -105,7 +105,6 @@ QPID_AUTO_TEST_CASE(testCoincidentErrors) {
}
}
-#if 0 // FIXME aconway 2009-07-30:
// Verify normal cluster-wide errors.
QPID_AUTO_TEST_CASE(testNormalErrors) {
// FIXME aconway 2009-04-10: Would like to put a scope just around
@@ -120,7 +119,7 @@ QPID_AUTO_TEST_CASE(testNormalErrors) {
{
ScopedSuppressLogging allQuiet;
- queueAndsub(c0);
+ queueAndSub(c0);
c0.session.messageTransfer(content=Message("x", "c0"));
BOOST_CHECK_EQUAL(c0.lq.get(TIMEOUT).getData(), "x");
@@ -258,7 +257,7 @@ QPID_AUTO_TEST_CASE(testPartialFailureMemberLeaves) {
}
}
#endif
-#endif // FIXME aconway 2009-07-30:
+
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueuePolicyTest.cpp b/qpid/cpp/src/tests/QueuePolicyTest.cpp
index f40d30b588..875976db85 100644
--- a/qpid/cpp/src/tests/QueuePolicyTest.cpp
+++ b/qpid/cpp/src/tests/QueuePolicyTest.cpp
@@ -48,56 +48,56 @@ QueuedMessage createMessage(uint32_t size)
QPID_AUTO_TEST_CASE(testCount)
{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 0));
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 0));
BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize());
BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
QueuedMessage msg = createMessage(10);
for (size_t i = 0; i < 5; i++) {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
}
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on enqueuing sixth message");
} catch (const ResourceLimitExceededException&) {}
policy->dequeued(msg);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
} catch (const ResourceLimitExceededException&) {}
}
QPID_AUTO_TEST_CASE(testSize)
{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(0, 50));
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 0, 50));
QueuedMessage msg = createMessage(10);
for (size_t i = 0; i < 5; i++) {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
}
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
} catch (const ResourceLimitExceededException&) {}
policy->dequeued(msg);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
} catch (const ResourceLimitExceededException&) {}
}
QPID_AUTO_TEST_CASE(testBoth)
{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 50));
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 50));
try {
QueuedMessage msg = createMessage(51);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy);
} catch (const ResourceLimitExceededException&) {}
@@ -108,17 +108,17 @@ QPID_AUTO_TEST_CASE(testBoth)
messages.push_back(createMessage(2));
messages.push_back(createMessage(7));
for (size_t i = 0; i < messages.size(); i++) {
- policy->tryEnqueue(messages[i]);
+ policy->tryEnqueue(messages[i].payload);
}
//size = 45 at this point, count = 5
try {
QueuedMessage msg = createMessage(5);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy);
} catch (const ResourceLimitExceededException&) {}
try {
QueuedMessage msg = createMessage(10);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
} catch (const ResourceLimitExceededException&) {}
@@ -126,7 +126,7 @@ QPID_AUTO_TEST_CASE(testBoth)
policy->dequeued(messages[0]);
try {
QueuedMessage msg = createMessage(20);
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg.payload);
} catch (const ResourceLimitExceededException&) {
BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy);
}
@@ -135,10 +135,10 @@ QPID_AUTO_TEST_CASE(testBoth)
QPID_AUTO_TEST_CASE(testSettings)
{
//test reading and writing the policy from/to field table
- std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy(101, 303));
+ std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy("test", 101, 303));
FieldTable settings;
a->update(settings);
- std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy(settings));
+ std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy("test", settings));
BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount());
BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
}
@@ -146,7 +146,7 @@ QPID_AUTO_TEST_CASE(testSettings)
QPID_AUTO_TEST_CASE(testRingPolicy)
{
FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING);
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING);
policy->update(args);
ProxySessionFixture f;
@@ -175,7 +175,7 @@ QPID_AUTO_TEST_CASE(testRingPolicy)
QPID_AUTO_TEST_CASE(testStrictRingPolicy)
{
FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING_STRICT);
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING_STRICT);
policy->update(args);
ProxySessionFixture f;
@@ -201,7 +201,7 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy)
QPID_AUTO_TEST_CASE(testPolicyWithDtx)
{
FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::REJECT);
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
policy->update(args);
ProxySessionFixture f;
@@ -282,6 +282,22 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
} catch (const ResourceLimitExceededException&) {}
}
+QPID_AUTO_TEST_CASE(testPolicyFailureOnCommit)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("q");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ f.session.txSelect();
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ BOOST_CHECK_THROW(f.session.txCommit(), InternalErrorException);
+}
QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/QueueTest.cpp b/qpid/cpp/src/tests/QueueTest.cpp
index 841a19f7c1..3cfaa763ca 100644
--- a/qpid/cpp/src/tests/QueueTest.cpp
+++ b/qpid/cpp/src/tests/QueueTest.cpp
@@ -18,10 +18,13 @@
* under the License.
*
*/
+#include "MessageUtils.h"
#include "unit_test.h"
#include "test_tools.h"
#include "qpid/Exception.h"
#include "qpid/broker/Broker.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/FanOutExchange.h"
#include "qpid/broker/Queue.h"
#include "qpid/broker/Deliverable.h"
#include "qpid/broker/ExchangeRegistry.h"
@@ -30,12 +33,16 @@
#include "qpid/broker/ExpiryPolicy.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/client/QueueOptions.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/reply_exceptions.h"
#include <iostream>
#include "boost/format.hpp"
using boost::intrusive_ptr;
using namespace qpid;
using namespace qpid::broker;
+using namespace qpid::client;
using namespace qpid::framing;
using namespace qpid::sys;
@@ -61,13 +68,14 @@ public:
class FailOnDeliver : public Deliverable
{
- Message msg;
+ boost::intrusive_ptr<Message> msg;
public:
+ FailOnDeliver() : msg(MessageUtils::createMessage()) {}
void deliverTo(const boost::shared_ptr<Queue>& queue)
{
throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
}
- Message& getMessage() { return msg; }
+ Message& getMessage() { return *(msg.get()); }
};
intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) {
@@ -210,8 +218,7 @@ QPID_AUTO_TEST_CASE(testDequeue){
}
-QPID_AUTO_TEST_CASE(testBound)
-{
+QPID_AUTO_TEST_CASE(testBound){
//test the recording of bindings, and use of those to allow a queue to be unbound
string key("my-key");
FieldTable args;
@@ -245,7 +252,6 @@ QPID_AUTO_TEST_CASE(testBound)
}
QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
-
client::QueueOptions args;
args.setPersistLastNode();
@@ -273,14 +279,35 @@ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
}
-class TestMessageStoreOC : public NullMessageStore
+const std::string nullxid = "";
+
+class SimpleDummyCtxt : public TransactionContext {};
+
+class DummyCtxt : public TPCTransactionContext
+{
+ const std::string xid;
+ public:
+ DummyCtxt(const std::string& _xid) : xid(_xid) {}
+ static std::string getXid(TransactionContext& ctxt)
+ {
+ DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt));
+ return c ? c->xid : nullxid;
+ }
+};
+
+class TestMessageStoreOC : public MessageStore
{
+ std::set<std::string> prepared;
+ uint64_t nextPersistenceId;
public:
uint enqCnt;
uint deqCnt;
bool error;
+ TestMessageStoreOC() : MessageStore(),nextPersistenceId(1),enqCnt(0),deqCnt(0),error(false) {}
+ ~TestMessageStoreOC(){}
+
virtual void dequeue(TransactionContext*,
const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
const PersistableQueue& /*queue*/)
@@ -290,11 +317,12 @@ class TestMessageStoreOC : public NullMessageStore
}
virtual void enqueue(TransactionContext*,
- const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& /* queue */)
{
if (error) throw Exception("Enqueue error test");
enqCnt++;
+ msg->enqueueComplete();
}
void createError()
@@ -302,8 +330,32 @@ class TestMessageStoreOC : public NullMessageStore
error=true;
}
- TestMessageStoreOC() : NullMessageStore(),enqCnt(0),deqCnt(0),error(false) {}
- ~TestMessageStoreOC(){}
+ bool init(const Options*) { return true; }
+ void truncateInit(const bool) {}
+ void create(PersistableQueue& queue, const framing::FieldTable&) { queue.setPersistenceId(nextPersistenceId++); }
+ void destroy(PersistableQueue&) {}
+ void create(const PersistableExchange& exchange, const framing::FieldTable&) { exchange.setPersistenceId(nextPersistenceId++); }
+ void destroy(const PersistableExchange&) {}
+ void bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
+ void unbind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
+ void create(const PersistableConfig& config) { config.setPersistenceId(nextPersistenceId++); }
+ void destroy(const PersistableConfig&) {}
+ void stage(const boost::intrusive_ptr<PersistableMessage>&) {}
+ void destroy(PersistableMessage&) {}
+ void appendContent(const boost::intrusive_ptr<const PersistableMessage>&, const std::string&) {}
+ void loadContent(const qpid::broker::PersistableQueue&, const boost::intrusive_ptr<const PersistableMessage>&,
+ std::string&, uint64_t, uint32_t) { throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled"); }
+ void flush(const qpid::broker::PersistableQueue&) {}
+ uint32_t outstandingQueueAIO(const PersistableQueue&) { return 0; }
+
+ std::auto_ptr<TransactionContext> begin() { return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt()); }
+ std::auto_ptr<TPCTransactionContext> begin(const std::string& xid) { return std::auto_ptr<TPCTransactionContext>(new DummyCtxt(xid)); }
+ void prepare(TPCTransactionContext& ctxt) { prepared.insert(DummyCtxt::getXid(ctxt)); }
+ void commit(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
+ void abort(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
+ void collectPreparedXids(std::set<std::string>& out) { out.insert(prepared.begin(), prepared.end()); }
+
+ void recover(RecoveryManager&) {}
};
@@ -703,7 +755,7 @@ not requeued to the store.
QPID_AUTO_TEST_CASE(testLastNodeJournalError){
/*
-simulate store excption going into last node standing
+simulate store exception going into last node standing
*/
TestMessageStoreOC testStore;
@@ -727,16 +779,271 @@ simulate store excption going into last node standing
}
-intrusive_ptr<Message> mkMsg(std::string exchange, std::string routingKey) {
- intrusive_ptr<Message> msg(new Message());
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- msg->getFrames().append(method);
- msg->getFrames().append(header);
- msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+intrusive_ptr<Message> mkMsg(MessageStore& store, std::string content = "", bool durable = false)
+{
+ intrusive_ptr<Message> msg = MessageUtils::createMessage("", "", durable);
+ if (content.size()) MessageUtils::addContent(msg, content);
+ msg->setStore(&store);
return msg;
}
+QPID_AUTO_TEST_CASE(testFlowToDiskBlocking){
+
+ TestMessageStoreOC testStore;
+ client::QueueOptions args0; // No size policy
+ client::QueueOptions args1;
+ args1.setSizePolicy(FLOW_TO_DISK, 0, 1);
+ client::QueueOptions args2;
+ args2.setSizePolicy(FLOW_TO_DISK, 0, 2);
+
+ // --- Fanout exchange bound to single transient queue -------------------------------------------------------------
+
+ FanOutExchange sbtFanout1("sbtFanout1", false, args0); // single binding to transient queue
+ Queue::shared_ptr tq1(new Queue("tq1", true)); // transient w/ limit
+ tq1->configure(args1);
+ sbtFanout1.bind(tq1, "", 0);
+
+ intrusive_ptr<Message> msg01 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg01(msg01);
+ sbtFanout1.route(dmsg01, "", 0); // Brings queue 1 to capacity limit
+ msg01->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg01->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg02 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg02(msg02);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg02, "", 0), ResourceLimitExceededException);
+ msg02->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg02->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg03 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg03(msg03);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg03, "", 0), ResourceLimitExceededException);
+ msg03->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg03->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg04 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg04(msg04);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg04, "", 0), ResourceLimitExceededException);
+ msg04->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg04->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg05 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg05(msg05);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg05, "", 0), ResourceLimitExceededException);
+ msg05->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg05->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ // --- Fanout exchange bound to single durable queue ---------------------------------------------------------------
+
+ FanOutExchange sbdFanout2("sbdFanout2", false, args0); // single binding to durable queue
+ Queue::shared_ptr dq2(new Queue("dq2", true, &testStore)); // durable w/ limit
+ dq2->configure(args1);
+ sbdFanout2.bind(dq2, "", 0);
+
+ intrusive_ptr<Message> msg06 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg06(msg06);
+ sbdFanout2.route(dmsg06, "", 0); // Brings queue 2 to capacity limit
+ msg06->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg06->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg07 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg07(msg07);
+ sbdFanout2.route(dmsg07, "", 0);
+ msg07->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg07->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(2u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg08 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg08(msg08);
+ sbdFanout2.route(dmsg08, "", 0);
+ msg08->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg08->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(3u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg09 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg09(msg09);
+ sbdFanout2.route(dmsg09, "", 0);
+ msg09->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg09->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(4u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg10 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg10(msg10);
+ sbdFanout2.route(dmsg10, "", 0);
+ msg10->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg10->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(5u, dq2->getMessageCount());
+
+ // --- Fanout exchange bound to multiple durable queues ------------------------------------------------------------
+
+ FanOutExchange mbdFanout3("mbdFanout3", false, args0); // multiple bindings to durable queues
+ Queue::shared_ptr dq3(new Queue("dq3", true, &testStore)); // durable w/ limit 2
+ dq3->configure(args2);
+ mbdFanout3.bind(dq3, "", 0);
+ Queue::shared_ptr dq4(new Queue("dq4", true, &testStore)); // durable w/ limit 1
+ dq4->configure(args1);
+ mbdFanout3.bind(dq4, "", 0);
+ Queue::shared_ptr dq5(new Queue("dq5", true, &testStore)); // durable no limit
+ dq5->configure(args0);
+ mbdFanout3.bind(dq5, "", 0);
+
+ intrusive_ptr<Message> msg11 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg11(msg11);
+ mbdFanout3.route(dmsg11, "", 0); // Brings queues 3 and 4 to capacity limit
+ msg11->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg11->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg12 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg12(msg12);
+ mbdFanout3.route(dmsg12, "", 0);
+ msg12->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg12->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
+ BOOST_CHECK_EQUAL(2u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg13 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg13(msg13);
+ mbdFanout3.route(dmsg13, "", 0);
+ msg13->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg13->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(3u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(3u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(3u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg14 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg14(msg14);
+ mbdFanout3.route(dmsg14, "", 0);
+ msg14->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg14->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
+ BOOST_CHECK_EQUAL(4u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(4u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(4u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg15 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg15(msg15);
+ mbdFanout3.route(dmsg15, "", 0);
+ msg15->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg15->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(5u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(5u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(5u, dq5->getMessageCount());
+
+ // Bind a transient queue, this should block the release of any further messages.
+ // Note: this will result in a violation of the count policy of dq3 and dq4 - but this
+ // is expected until a better overall multi-queue design is implemented. Similarly
+ // for the other tests in this section.
+
+ Queue::shared_ptr tq6(new Queue("tq6", true)); // transient no limit
+ tq6->configure(args0);
+ mbdFanout3.bind(tq6, "", 0);
+
+ intrusive_ptr<Message> msg16 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg16(msg16);
+ mbdFanout3.route(dmsg16, "", 0);
+ msg16->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg16->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(6u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(6u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(6u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg17 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg17(msg17);
+ mbdFanout3.route(dmsg17, "", 0);
+ msg17->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg17->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(7u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(7u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(7u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg18 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg18(msg18);
+ mbdFanout3.route(dmsg18, "", 0);
+ msg18->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg18->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(8u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(8u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(8u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg19 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg19(msg19);
+ mbdFanout3.route(dmsg19, "", 0);
+ msg19->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg19->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(9u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(9u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(9u, dq5->getMessageCount());
+
+
+ // --- Fanout exchange bound to multiple durable and transient queues ----------------------------------------------
+
+ FanOutExchange mbmFanout4("mbmFanout4", false, args0); // multiple bindings to durable/transient queues
+ Queue::shared_ptr dq7(new Queue("dq7", true, &testStore)); // durable no limit
+ dq7->configure(args0);
+ mbmFanout4.bind(dq7, "", 0);
+ Queue::shared_ptr dq8(new Queue("dq8", true, &testStore)); // durable w/ limit
+ dq8->configure(args1);
+ mbmFanout4.bind(dq8, "", 0);
+ Queue::shared_ptr tq9(new Queue("tq9", true)); // transient no limit
+ tq9->configure(args0);
+ mbmFanout4.bind(tq9, "", 0);
+
+ intrusive_ptr<Message> msg20 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg20(msg20);
+ mbmFanout4.route(dmsg20, "", 0); // Brings queue 7 to capacity limit
+ msg20->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg20->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq7->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq8->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg21 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg21(msg21);
+ mbmFanout4.route(dmsg21, "", 0);
+ msg21->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg21->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(2u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(2u, dq8->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg22 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg22(msg22);
+ mbmFanout4.route(dmsg22, "", 0);
+ msg22->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg22->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(3u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(3u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(3u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg23 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg23(msg23);
+ mbmFanout4.route(dmsg23, "", 0);
+ msg23->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg23->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(4u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(4u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(4u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg24 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg24(msg24);
+ mbmFanout4.route(dmsg24, "", 0);
+ msg24->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg24->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(5u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(5u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(5u, tq9->getMessageCount());
+}
+
+
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/TxPublishTest.cpp b/qpid/cpp/src/tests/TxPublishTest.cpp
index fabb01b864..6b44d95baa 100644
--- a/qpid/cpp/src/tests/TxPublishTest.cpp
+++ b/qpid/cpp/src/tests/TxPublishTest.cpp
@@ -50,7 +50,7 @@ struct TxPublishTest
TxPublishTest() :
queue1(new Queue("queue1", false, &store, 0)),
queue2(new Queue("queue2", false, &store, 0)),
- msg(MessageUtils::createMessage("exchange", "routing_key", "id")),
+ msg(MessageUtils::createMessage("exchange", "routing_key", false, "id")),
op(msg)
{
msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index fc53d2ce8b..2d776e9941 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -220,10 +220,11 @@ class ACLTests(TestBase010):
"""
aclf = ACLFile()
aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n')
- aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true\n')
+ aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ring\n')
aclf.write('acl deny bob@QPID access queue name=q3\n')
aclf.write('acl deny bob@QPID purge queue name=q3\n')
- aclf.write('acl deny bob@QPID delete queue name=q4\n')
+ aclf.write('acl deny bob@QPID delete queue name=q4\n')
+ aclf.write('acl deny bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n')
aclf.write('acl allow all all')
aclf.close()
@@ -241,19 +242,41 @@ class ACLTests(TestBase010):
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q2", exclusive=True)
- self.fail("ACL should deny queue create request with name=q2 exclusive=true");
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2 exclusive=true qpid.policy_type=ring");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q2", durable=True)
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring_strict"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow queue create request for q2 with any parameter other than exclusive=true");
+ self.fail("ACL should allow queue create request with name=q2 exclusive=true qpid.policy_type=ring_strict");
try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", exclusive=True, arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2, qpid.max_size=500 and qpid.max_count=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 100
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q2, qpid.max_size=100 and qpid.max_count=200 ");
+ try:
session.queue_declare(queue="q3", exclusive=True)
session.queue_declare(queue="q4", durable=True)
except qpid.session.SessionException, e:
@@ -300,12 +323,13 @@ class ACLTests(TestBase010):
"""
aclf = ACLFile()
aclf.write('acl allow bob@QPID create queue name=q1 durable=true passive=true\n')
- aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true\n')
+ aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true policytype=ring\n')
aclf.write('acl allow bob@QPID access queue name=q3\n')
aclf.write('acl allow bob@QPID purge queue name=q3\n')
aclf.write('acl allow bob@QPID create queue name=q3\n')
aclf.write('acl allow bob@QPID create queue name=q4\n')
- aclf.write('acl allow bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n')
aclf.write('acl allow guest@QPID all all\n')
aclf.write('acl deny all all')
aclf.close()
@@ -337,10 +361,31 @@ class ACLTests(TestBase010):
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q2", exclusive=True)
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2 maxqueuesize=500 maxqueuecount=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 100
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", arguments=queue_options)
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow queue create request for q2 with exclusive=true");
+ self.fail("ACL should allow queue create request with name=q2 maxqueuesize=500 maxqueuecount=200");
+
+ try:
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q2 with exclusive=true policytype=ring");
try:
session.queue_declare(queue="q3")
@@ -733,7 +778,7 @@ class ACLTests(TestBase010):
# ACL publish tests
#=====================================
- def test_publish_acl(self):
+ def test_publish_acl_allow_mode(self):
"""
Test various publish acl
"""
@@ -779,4 +824,61 @@ class ACLTests(TestBase010):
session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow message transfer to exchange amq.direct");
+ self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk2");
+
+
+ def test_publish_acl_deny_mode(self):
+ """
+ Test various publish acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
+ aclf.write('acl allow bob@QPID publish exchange name=amq.topic\n')
+ aclf.write('acl allow bob@QPID publish exchange name=myEx routingkey=rk2\n')
+ aclf.write('acl allow bob@QPID create exchange\n')
+ aclf.write('acl allow guest@QPID all all \n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ props = session.delivery_properties(routing_key="rk2")
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk2");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.topic", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.topic with any routing key");
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange myEx with routing key=rk2");
+
+ props = session.delivery_properties(routing_key="rk1")
+
+ try:
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=myEx routingkey=rk1");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk1");
diff --git a/qpid/cpp/src/tests/ais_check b/qpid/cpp/src/tests/ais_check
index 79862d7439..92eaa9dd39 100755
--- a/qpid/cpp/src/tests/ais_check
+++ b/qpid/cpp/src/tests/ais_check
@@ -21,35 +21,14 @@
srcdir=`dirname $0`
# Check AIS requirements and run tests if found.
-id -nG | grep '\<ais\>' >/dev/null || \
- NOGROUP="You are not a member of the ais group."
-ps -u root | grep 'aisexec\|corosync' >/dev/null || \
- NOAISEXEC="The aisexec or corosync daemon is not running as root"
-
-if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
- cat <<EOF
-
- =========== WARNING: NOT RUNNING AIS TESTS ==============
-
- Tests that depend on the openais library (used for clustering)
- will not be run because:
- $NOGROUP
- $NOAISEXEC
-
- ==========================================================
-
-EOF
+ps -u root | grep 'aisexec\|corosync' >/dev/null || {
+ echo WARNING: Skipping cluster tests, the aisexec or corosync daemon is not running.
exit 0; # A warning, not a failure.
-fi
+}
-# Execute command with the ais group set.
+# Execute command with the ais group set if user is a member.
with_ais_group() {
- id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group."; exit 1; }
- echo $* | newgrp ais
+ if id -nG | grep '\<ais\>' >/dev/null; then sg ais -c "$*"
+ else "$@"
+ fi
}
-
-# Run the tests
-srcdir=`dirname $0`
-with_ais_group $srcdir/run_test ./cluster_test || ERROR=1
-exit $ERROR
-
diff --git a/qpid/cpp/src/tests/background.ps1 b/qpid/cpp/src/tests/background.ps1
index 934078602b..36e9e4e6e9 100644
--- a/qpid/cpp/src/tests/background.ps1
+++ b/qpid/cpp/src/tests/background.ps1
@@ -30,11 +30,26 @@ trap { break }
$encodedScript = [convert]::ToBase64String(
[Text.Encoding]::Unicode.GetBytes([string] $script))
-$p = new-object System.Diagnostics.Process
+#$p = new-object System.Diagnostics.Process
$si = new-object System.Diagnostics.ProcessStartInfo
$si.WorkingDirectory = $pwd
-$si.UseShellExecute = $true
$si.FileName = (get-command powershell.exe).Definition
$si.Arguments = "-encodedCommand $encodedScript"
-[diagnostics.process]::Start($si)
+###### debugging setup
+#$si.CreateNoWindow = $true
+# UseShellExecute false required for RedirectStandard(Error, Output)
+#$si.UseShellExecute = $false
+#$si.RedirectStandardError = $true
+#$si.RedirectStandardOutput = $true
+######
+$si.UseShellExecute = $true
+
+##### Debugging, instead of the plain Start() above.
+#$output = [io.File]::AppendText("start.out")
+#$error = [io.File]::AppendText("start.err")
+$p = [System.Diagnostics.Process]::Start($si)
+#$output.WriteLine($p.StandardOutput.ReadToEnd())
+#$error.WriteLine($p.StandardError.ReadToEnd())
+#$p.WaitForExit()
+#$output.Close()
diff --git a/qpid/cpp/src/tests/cluster.mk b/qpid/cpp/src/tests/cluster.mk
index 05e18ab9eb..bdec10ebb0 100644
--- a/qpid/cpp/src/tests/cluster.mk
+++ b/qpid/cpp/src/tests/cluster.mk
@@ -30,7 +30,8 @@ if HAVE_LIBCPG
# ais_check checks pre-requisites for cluster tests and runs them if ok.
TESTS += \
- ais_check \
+ run_cluster_test \
+ cluster_read_credit \
test_watchdog \
run_cluster_tests \
federated_cluster_test \
@@ -38,6 +39,8 @@ TESTS += \
EXTRA_DIST += \
ais_check \
+ run_cluster_test \
+ cluster_read_credit \
test_watchdog \
start_cluster \
stop_cluster \
diff --git a/qpid/cpp/src/tests/cluster_read_credit b/qpid/cpp/src/tests/cluster_read_credit
new file mode 100755
index 0000000000..370d4098c5
--- /dev/null
+++ b/qpid/cpp/src/tests/cluster_read_credit
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Regression test for http://issues.apache.org/jira/browse/QPID-2086
+
+srcdir=`dirname $0`
+. $srcdir/ais_check
+$srcdir/start_cluster 1 --cluster-read-max=2 || exit 1
+trap $srcdir/stop_cluster EXIT
+seq 1 10000 | ./sender --port `cat cluster.ports` --routing-key no-such-queue
diff --git a/qpid/cpp/src/tests/cluster_test.cpp b/qpid/cpp/src/tests/cluster_test.cpp
index 28fcdd13ad..247aef1b2a 100644
--- a/qpid/cpp/src/tests/cluster_test.cpp
+++ b/qpid/cpp/src/tests/cluster_test.cpp
@@ -85,6 +85,12 @@ void prepareArgs(ClusterFixture::Args& args, const bool durableFlag = false) {
args += "--no-data-dir";
}
+ClusterFixture::Args prepareArgs(const bool durableFlag = false) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ return args;
+}
+
// Timeout for tests that wait for messages
const sys::Duration TIMEOUT=sys::TIME_SEC/4;
@@ -596,16 +602,19 @@ QPID_AUTO_TEST_CASE(testUpdateConsumers) {
}
}
-QPID_AUTO_TEST_CASE(testCatchupSharedState) {
+// Test that message data and delivery properties are updated properly.
+QPID_AUTO_TEST_CASE(testUpdateMessages) {
ClusterFixture::Args args;
prepareArgs(args, durableFlag);
ClusterFixture cluster(1, args, -1);
Client c0(cluster[0], "c0");
- // Create some shared state.
+ // Create messages with different delivery properties
c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.exchangeBind(arg::exchange="amq.fanout", arg::queue="q");
c0.session.messageTransfer(arg::content=makeMessage("foo","q", durableFlag));
- c0.session.messageTransfer(arg::content=makeMessage("bar","q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("bar","q", durableFlag),
+ arg::destination="amq.fanout");
while (c0.session.queueQuery("q").getMessageCount() != 2)
sys::usleep(1000); // Wait for message to show up on broker 0.
@@ -628,9 +637,12 @@ QPID_AUTO_TEST_CASE(testCatchupSharedState) {
BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
BOOST_CHECK_EQUAL(m.getData(), "foo");
+ BOOST_CHECK(m.getDeliveryProperties().hasExchange());
BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), "");
BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
BOOST_CHECK_EQUAL(m.getData(), "bar");
+ BOOST_CHECK(m.getDeliveryProperties().hasExchange());
+ BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), "amq.fanout");
BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
// Add another broker, don't wait for join - should be stalled till ready.
@@ -905,6 +917,7 @@ QPID_AUTO_TEST_CASE(testExclusiveQueueUpdate) {
BOOST_CHECK(!result.getDurable());
BOOST_CHECK_EQUAL(result.getAlternateExchange(), std::string("amq.fanout"));
BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::exclusive=true, arg::passive=true), framing::ResourceLockedException);
+ c1.session.close();
c1.connection.close();
c2.session = c2.connection.newSession();
BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::passive=true), framing::NotFoundException);
@@ -1100,6 +1113,44 @@ QPID_AUTO_TEST_CASE(testRelease) {
}
}
-QPID_AUTO_TEST_SUITE_END()
+// Browse for 1 message with byte credit, return true if a message was
+// received false if not.
+bool browseByteCredit(Client& c, const string& q, int n, Message& m) {
+ SubscriptionSettings browseSettings(
+ FlowControl(1, n, false), // 1 message, n bytes credit, no window
+ ACCEPT_MODE_NONE,
+ ACQUIRE_MODE_NOT_ACQUIRED,
+ 0 // No auto-ack.
+ );
+ LocalQueue lq;
+ Subscription s = c.subs.subscribe(lq, q, browseSettings);
+ c.session.messageFlush(arg::destination=q, arg::sync=true);
+ c.session.sync();
+ c.subs.getSubscription(q).cancel();
+ return lq.get(m, 0); // No timeout, flush should push message thru.
+}
+
+// Ensure cluster update preserves exact message size, use byte credt as test.
+QPID_AUTO_TEST_CASE(testExactByteCredit) {
+ ClusterFixture cluster(1, prepareArgs(), -1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("MyMessage", "q"));
+ cluster.add();
+
+ int size=36; // Size of message on broker: headers+body
+ Client c1(cluster[1], "c1");
+ Message m;
+
+ // Ensure we get the message with exact credit.
+ BOOST_CHECK(browseByteCredit(c0, "q", size, m));
+ BOOST_CHECK(browseByteCredit(c1, "q", size, m));
+ // and not with one byte less.
+ BOOST_CHECK(!browseByteCredit(c0, "q", size-1, m));
+ BOOST_CHECK(!browseByteCredit(c1, "q", size-1, m));
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/clustered_replication_test b/qpid/cpp/src/tests/clustered_replication_test
index cc331957ad..4f13b4672c 100755
--- a/qpid/cpp/src/tests/clustered_replication_test
+++ b/qpid/cpp/src/tests/clustered_replication_test
@@ -22,8 +22,7 @@
# Test reliability of the replication feature in the face of link
# failures:
srcdir=`dirname $0`
-PYTHON_DIR=$srcdir/../../../python
-export PYTHONPATH=$PYTHON_DIR
+. $srcdir/python_env.sh
trap stop_brokers INT EXIT
@@ -31,10 +30,6 @@ fail() {
echo $1
exit 1
}
-with_ais_group() {
- id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; }
- echo $* | newgrp ais
-}
stop_brokers() {
if [[ $PRIMARY1 ]] ; then
@@ -55,26 +50,8 @@ stop_brokers() {
fi
}
-if test -d ${PYTHON_DIR}; then
- id -nG | grep '\<ais\>' >/dev/null || \
- NOGROUP="You are not a member of the ais group."
- ps -u root | grep 'aisexec\|corosync' >/dev/null || \
- NOAISEXEC="The aisexec or corosync daemon is not running as root"
-
- if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
- cat <<EOF
-
- =========== WARNING: NOT RUNNING AIS TESTS ==============
-
- Not running cluster replication test because:
- $NOGROUP
- $NOAISEXEC
-
- ==========================================================
-
-EOF
- exit 0;
- fi
+if test -d $PYTHON_DIR; then
+ . $srcdir/ais_check
#todo: these cluster names need to be unique to prevent clashes
PRIMARY_CLUSTER=PRIMARY_$(hostname)_$(pwd)
@@ -89,8 +66,8 @@ EOF
#start first node of primary cluster and set up test queue
echo Starting primary cluster
PRIMARY1=$(with_ais_group ../qpidd $GENERAL_OPTS $PRIMARY_OPTS --log-to-file repl.primary.1.tmp) || fail "Could not start node"
- $PYTHON_DIR/commands/qpid-config -a "localhost:$PRIMARY1" add queue test-queue --generate-queue-events 2
- $PYTHON_DIR/commands/qpid-config -a "localhost:$PRIMARY1" add queue control-queue --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue test-queue --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue control-queue --generate-queue-events 1
#send 10 messages, consume 5 of them
for i in `seq 1 10`; do echo Message$i; done | ./sender --port $PRIMARY1
@@ -105,10 +82,10 @@ EOF
DR1=$(with_ais_group ../qpidd $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.1.tmp)
DR2=$(with_ais_group ../qpidd $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.2.tmp)
- $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add queue test-queue
- $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add queue control-queue
- $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add exchange replication REPLICATION_EXCHANGE
- $PYTHON_DIR/commands/qpid-route queue add localhost:$DR2 localhost:$PRIMARY2 REPLICATION_EXCHANGE REPLICATION_QUEUE
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue control-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add exchange replication REPLICATION_EXCHANGE
+ $PYTHON_COMMANDS/qpid-route queue add localhost:$DR2 localhost:$PRIMARY2 REPLICATION_EXCHANGE REPLICATION_QUEUE
#send more messages to primary
for i in `seq 11 20`; do echo Message$i; done | ./sender --port $PRIMARY1 --send-eos 1
diff --git a/qpid/cpp/src/tests/federated_cluster_test b/qpid/cpp/src/tests/federated_cluster_test
index a781e269d6..8b3ce3cb95 100755
--- a/qpid/cpp/src/tests/federated_cluster_test
+++ b/qpid/cpp/src/tests/federated_cluster_test
@@ -22,7 +22,7 @@
# Test reliability of the replication feature in the face of link
# failures:
srcdir=`dirname $0`
-PYTHON_DIR=$srcdir/../../../python
+. $srcdir/python_env.sh
trap stop_brokers EXIT
@@ -61,22 +61,21 @@ start_brokers() {
}
setup() {
- export PYTHONPATH=$PYTHON_DIR
#create exchange on both cluster and single broker
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add exchange direct test-exchange
- $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" add exchange direct test-exchange
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add exchange direct test-exchange
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add exchange direct test-exchange
#create dynamic routes for test exchange
- $PYTHON_DIR/commands/qpid-route dynamic add "localhost:$NODE_2" "localhost:$BROKER_A" test-exchange
- $PYTHON_DIR/commands/qpid-route dynamic add "localhost:$BROKER_A" "localhost:$NODE_2" test-exchange
+ $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$NODE_2" "localhost:$BROKER_A" test-exchange
+ $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$BROKER_A" "localhost:$NODE_2" test-exchange
#create test queue on cluster and bind it to the test exchange
- $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" add queue test-queue
- $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" bind test-exchange test-queue to-cluster
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" bind test-exchange test-queue to-cluster
#create test queue on single broker and bind it to the test exchange
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue test-queue
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" bind test-exchange test-queue from-cluster
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" bind test-exchange test-queue from-cluster
}
run_test_pull_to_cluster_two_consumers() {
@@ -127,25 +126,7 @@ run_test_pull_from_cluster() {
if test -d ${PYTHON_DIR}; then
- id -nG | grep '\<ais\>' >/dev/null || \
- NOGROUP="You are not a member of the ais group."
- ps -u root | grep 'aisexec\|corosync' >/dev/null || \
- NOAISEXEC="The aisexec or corosync daemon is not running as root"
-
- if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
- cat <<EOF
-
- =========== WARNING: NOT RUNNING AIS TESTS ==============
-
- Not running federation to cluster test because:
- $NOGROUP
- $NOAISEXEC
-
- ==========================================================
-
-EOF
- exit 0;
- fi
+ . $srcdir/ais_check
rm -f fed*.tmp #cleanup any files left from previous run
start_brokers
diff --git a/qpid/cpp/src/tests/federated_topic_test b/qpid/cpp/src/tests/federated_topic_test
index 21d8411eaf..dbe9a85e95 100755
--- a/qpid/cpp/src/tests/federated_topic_test
+++ b/qpid/cpp/src/tests/federated_topic_test
@@ -43,7 +43,7 @@ while getopts "s:m:b:" opt ; do
done
MY_DIR=$(dirname $(which $0))
-PYTHON_DIR=${MY_DIR}/../../../python
+. $MY_DIR/python_env.sh
trap stop_brokers EXIT
@@ -87,29 +87,28 @@ setup_routes() {
BROKER_A="localhost:$PORT_A"
BROKER_B="localhost:$PORT_B"
BROKER_C="localhost:$PORT_C"
- export PYTHONPATH=$PYTHON_DIR
if (($VERBOSE)); then
echo "Establishing routes for topic..."
fi
- $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B
- $PYTHON_DIR/commands/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C
if (($VERBOSE)); then
echo "linked A->B->C"
fi
- $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B
- $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A
if (($VERBOSE)); then
echo "linked C->B->A"
echo "Establishing routes for response queue..."
fi
- $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B
- $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A
if (($VERBOSE)); then
echo "linked C->B->A"
for b in $BROKER_A $BROKER_B $BROKER_C; do
echo "Routes for $b"
- $PYTHON_DIR/commands/qpid-route route list $b
+ $PYTHON_COMMANDS/qpid-route route list $b
done
fi
}
diff --git a/qpid/cpp/src/tests/python_env.sh b/qpid/cpp/src/tests/python_env.sh
new file mode 100644
index 0000000000..f5dca97a56
--- /dev/null
+++ b/qpid/cpp/src/tests/python_env.sh
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Environment for python tests
+test -d python || { echo "WARNING: skipping `basename $0`, no python directory."; exit 0; }
+PYTHON_DIR=$PWD/python
+PYTHON_COMMANDS=$PYTHON_DIR/commands
+PYTHONPATH=$PYTHON_DIR
+export PYTHONPATH PYTHON_DIR
+
diff --git a/qpid/cpp/src/tests/python_tests b/qpid/cpp/src/tests/python_tests
index e3906c1685..e2077ef7dc 100755
--- a/qpid/cpp/src/tests/python_tests
+++ b/qpid/cpp/src/tests/python_tests
@@ -20,14 +20,10 @@
#
# Run the python tests.
+. `dirname $0`/python_env.sh
QPID_PORT=${QPID_PORT:-5672}
PYTHON_TESTS=${PYTHON_TESTS:-$*}
-QPID_PYTHON_DIR=${QPID_PYTHON_DIR:-`dirname $0`/../../../python}
FAILING=${FAILING:-/dev/null}
-if test -d $QPID_PYTHON_DIR; then
- cd $QPID_PYTHON_DIR
- ./qpid-python-test -b localhost:$QPID_PORT -I $FAILING $PYTHON_TESTS || { echo "FAIL python tests"; exit 1; }
-else
- echo "WARNING: No python tests. $QPID_PYTHON_DIR not found."
-fi
+cd $PYTHON_DIR
+python commands/qpid-python-test -b localhost:$QPID_PORT -I $FAILING $PYTHON_TESTS || exit 1
diff --git a/qpid/cpp/src/tests/python_tests.ps1 b/qpid/cpp/src/tests/python_tests.ps1
new file mode 100644
index 0000000000..a7f6920783
--- /dev/null
+++ b/qpid/cpp/src/tests/python_tests.ps1
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the python tests; intended to be run by run_test.ps1 which sets up
+# QPID_PORT
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping header test as python libs not found"
+ exit 1
+}
+
+if (Test-Path env:FAILING) {
+ $fails = "-I $env:FAILING"
+}
+if (Test-Path env:PYTHON_TESTS) {
+ $tests = "$env:PYTHON_TESTS"
+}
+else {
+ $tests = "*"
+}
+
+#cd $PYTHON_DIR
+$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH"
+python $PYTHON_DIR/qpid-python-test -b localhost:$env:QPID_PORT $fails $tests
+exit $LASTEXITCODE
diff --git a/qpid/cpp/src/tests/qpid_stream.cpp b/qpid/cpp/src/tests/qpid_stream.cpp
index 8e02baa8a0..8195bf390e 100644
--- a/qpid/cpp/src/tests/qpid_stream.cpp
+++ b/qpid/cpp/src/tests/qpid_stream.cpp
@@ -34,6 +34,9 @@
using namespace qpid::messaging;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
struct Args : public qpid::Options
{
std::string url;
@@ -139,10 +142,14 @@ struct Consume : Client
<< ", min=" << minLatency
<< ", max=" << maxLatency << std::endl;
}
- }
+ }
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
diff --git a/qpid/cpp/src/tests/quick_topictest.ps1 b/qpid/cpp/src/tests/quick_topictest.ps1
index 2b857edfff..b1e0ed1f7d 100644
--- a/qpid/cpp/src/tests/quick_topictest.ps1
+++ b/qpid/cpp/src/tests/quick_topictest.ps1
@@ -18,12 +18,13 @@
#
# Quick and quiet topic test for make check.
-$srcdir = Split-Path $myInvocation.ScriptName
-$PsHome\powershell $srcdir\topictest.ps1 -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1
-if ($LastExitCode != 0) {
- echo $0 FAILED:
+[string]$me = $myInvocation.InvocationName
+$srcdir = Split-Path $me
+powershell "$srcdir\topictest.ps1" -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1
+if (!$?) {
+ "$me FAILED:"
cat topictest.log
exit $LastExitCode
}
-rm topictest.log
+Remove-Item topictest.log
exit 0
diff --git a/qpid/cpp/src/tests/reliable_replication_test b/qpid/cpp/src/tests/reliable_replication_test
index a788d5a76b..db06259f0c 100755
--- a/qpid/cpp/src/tests/reliable_replication_test
+++ b/qpid/cpp/src/tests/reliable_replication_test
@@ -22,7 +22,7 @@
# Test reliability of the replication feature in the face of link
# failures:
MY_DIR=`dirname \`which $0\``
-PYTHON_DIR=${MY_DIR}/../../../python
+. ${MY_DIR}/python_env.sh
trap stop_brokers EXIT
@@ -53,12 +53,12 @@ setup() {
echo "Testing replication from port $BROKER_A to port $BROKER_B"
export PYTHONPATH=$PYTHON_DIR
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
- $PYTHON_DIR/commands/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
#create test queue (only replicate enqueues for this test):
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 1
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-a
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a
}
send() {
@@ -72,10 +72,10 @@ receive() {
bounce_link() {
echo "Destroying link..."
- $PYTHON_DIR/commands/qpid-route link del "localhost:$BROKER_B" "localhost:$BROKER_A"
+ $PYTHON_COMMANDS/qpid-route link del "localhost:$BROKER_B" "localhost:$BROKER_A"
echo "Link destroyed; recreating route..."
sleep 2
- $PYTHON_DIR/commands/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
echo "Route re-established"
}
diff --git a/qpid/cpp/src/tests/replication_test b/qpid/cpp/src/tests/replication_test
index 8b3022b260..000b4591da 100755
--- a/qpid/cpp/src/tests/replication_test
+++ b/qpid/cpp/src/tests/replication_test
@@ -21,7 +21,8 @@
# Run a test of the replication feature
MY_DIR=`dirname \`which $0\``
-PYTHON_DIR=${MY_DIR}/../../../python
+. `dirname $0`/python_env.sh
+
trap stop_brokers INT TERM QUIT
stop_brokers() {
@@ -47,21 +48,21 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f
export PYTHONPATH
echo "Running replication test between localhost:$BROKER_A and localhost:$BROKER_B"
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
- $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
#create test queues
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 2
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-b --generate-queue-events 2
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-c --generate-queue-events 1
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 2
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-b --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-c --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 1
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-a
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-b
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-c
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-b
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-c
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
#queue-d deliberately not declared on DR; this error case should be handled
#publish and consume from test queues on broker A:
@@ -125,13 +126,13 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f
../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module ../.libs/replication_exchange.so --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port
BROKER_B=`cat qpidd.port`
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
- $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 2
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 1
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-d
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-d
i=1
while [ $i -le 10 ]; do
@@ -153,9 +154,9 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f
../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module ../.libs/replication_exchange.so --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port
BROKER_B=`cat qpidd.port`
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e
- $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
- $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
# now send another 15
i=11
while [ $i -le 15 ]; do
diff --git a/qpid/cpp/src/tests/ring_queue_test b/qpid/cpp/src/tests/ring_queue_test
index 5805989d7e..553746eb49 100755
--- a/qpid/cpp/src/tests/ring_queue_test
+++ b/qpid/cpp/src/tests/ring_queue_test
@@ -48,7 +48,7 @@ receive() {
cleanup() {
rm -f sender_${QUEUE_NAME}_* receiver_${QUEUE_NAME}_*
- qpid-config $BROKER_URL add queue $QUEUE_NAME
+ qpid-config $BROKER_URL del queue $QUEUE_NAME --force
}
log() {
@@ -64,10 +64,11 @@ validate() {
if [[ $RECEIVERS -eq 0 ]]; then
#queue should have $LIMIT messages on it, but need to send an eos also
sender --routing-key $QUEUE_NAME --send-eos 1 < /dev/null
- if [[ $(receiver --queue $QUEUE_NAME --browse | wc -l) -eq $(( $LIMIT - 1)) ]]; then
+ received=$(receiver --queue $QUEUE_NAME --browse | wc -l)
+ if [[ received -eq $(( $LIMIT - 1)) ]]; then
log "queue contains $LIMIT messages as expected"
else
- fail "queue does not contain the expected $LIMIT messages"
+ fail "queue does not contain the expected $LIMIT messages (received $received)"
fi
elif [[ $CONCURRENT -eq 0 ]]; then
#sum of length of all output files should be equal to $LIMIT - $RECEIVERS (1 eos message each)
diff --git a/qpid/cpp/src/tests/run_acl_tests b/qpid/cpp/src/tests/run_acl_tests
index d9b654c7cd..c67e2d421d 100755
--- a/qpid/cpp/src/tests/run_acl_tests
+++ b/qpid/cpp/src/tests/run_acl_tests
@@ -20,7 +20,7 @@
#
# Run the acl tests. $srcdir is set by the Makefile.
-PYTHON_DIR=$srcdir/../../../python
+. `dirname $0`/python_env.sh
DATA_DIR=`pwd`/data_dir
trap stop_brokers INT TERM QUIT
@@ -55,7 +55,7 @@ if test -d ${PYTHON_DIR} ; then
echo "Running acl tests using brokers on ports $LOCAL_PORT"
PYTHONPATH=$PYTHON_DIR:$srcdir
export PYTHONPATH
- $PYTHON_DIR/qpid-python-test -b localhost:$LOCAL_PORT -m acl || EXITCODE=1
+ $PYTHON_COMMANDS/qpid-python-test -b localhost:$LOCAL_PORT -m acl || EXITCODE=1
stop_brokers || EXITCODE=1
test_loading_acl_from_absolute_path || EXITCODE=1
rm -rf $DATA_DIR
diff --git a/qpid/cpp/src/tests/run_cli_tests b/qpid/cpp/src/tests/run_cli_tests
index ea0d591176..bb9605410c 100755
--- a/qpid/cpp/src/tests/run_cli_tests
+++ b/qpid/cpp/src/tests/run_cli_tests
@@ -21,8 +21,8 @@
# Run the cli-utility tests.
MY_DIR=`dirname \`which $0\``
-PYTHON_DIR=${MY_DIR}/../../../python
-CLI_DIR=${PYTHON_DIR}/commands
+. `dirname $0`/python_env.sh
+CLI_DIR=$PYTHON_COMMANDS
trap stop_brokers INT TERM QUIT
@@ -43,7 +43,7 @@ if test -d ${PYTHON_DIR} ; then
echo "Running CLI tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
PYTHONPATH=${PYTHON_DIR}:${MY_DIR}
export PYTHONPATH
- ${PYTHON_DIR}/qpid-python-test -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $@
+ $PYTHON_COMMANDS/qpid-python-test -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $@
RETCODE=$?
stop_brokers
if test x$RETCODE != x0; then
diff --git a/qpid/cpp/src/tests/run_cluster_test b/qpid/cpp/src/tests/run_cluster_test
new file mode 100755
index 0000000000..c022eea1fe
--- /dev/null
+++ b/qpid/cpp/src/tests/run_cluster_test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# Run the tests
+srcdir=`dirname $0`
+. $srcdir/ais_check
+with_ais_group $srcdir/run_test ./cluster_test
diff --git a/qpid/cpp/src/tests/run_cluster_tests b/qpid/cpp/src/tests/run_cluster_tests
index 8b039346db..d1a58f9f6a 100755
--- a/qpid/cpp/src/tests/run_cluster_tests
+++ b/qpid/cpp/src/tests/run_cluster_tests
@@ -22,45 +22,21 @@
# Check that top_builddir and srcdir are set
# If not, assume local run from test dir
if [ -z ${top_builddir} -o -z ${srcdir} ]; then
- srcdir=`pwd`
+ srcdir=`dirname $0`
top_builddir=${srcdir}/../../
fi
TEST_DIR=${top_builddir}/src/tests
-PYTHON_DIR=${srcdir}/../../../python
+. $srcdir/python_env.sh
if test -z $1; then
- CLUSTER_TEST="${PYTHON_DIR}/qpid-python-test -m cluster_tests cluster_tests.ShortTests.\*"
+ CLUSTER_TEST="$PYTHON_COMMANDS/qpid-python-test -m cluster_tests cluster_tests.ShortTests.\*"
else
- CLUSTER_TEST="${PYTHON_DIR}/qpid-python-test -m cluster_tests cluster_tests.LongTests.\*"
+ CLUSTER_TEST="$PYTHON_COMMANDS/qpid-python-test -m cluster_tests cluster_tests.LongTests.\*"
echo "Running $1..."
fi
-
# Check AIS requirements
-id -nG | grep '\<ais\>' > /dev/null || NOGROUP="You are not a member of the ais group."
-ps -u root | grep 'aisexec\|corosync' > /dev/null || NOAISEXEC="The aisexec or corosync daemon is not running as root."
-if ! test -d ${PYTHON_DIR}; then
- NO_PYTHON_DIR="PYTHON_DIR=\"${PYTHON_DIR}\" not found or does not exist."
-fi
-
-if test -n "${NOGROUP}" -o -n "${NOAISEXEC}" -o -n "${NO_PYTHON_DIR}"; then
- cat <<EOF
-
- ======== WARNING: PYTHON CLUSTER TESTS DISABLED ===========
-
- Tests that depend on the openais library (used for clustering)
- and python will not be run because:
-
- ${NOGROUP}
- ${NOAISEXEC}
- ${NO_PYTHON_DIR}
-
- ===========================================================
-
-EOF
- exit 0
-fi
-
+. $srcdir/ais_check
# Check XML exchange requirements
XML_LIB=$srcdir/../.libs/xml.so
@@ -103,7 +79,7 @@ export TMP_DATA_DIR
# Run the test
-sg ais -c "${CLUSTER_TEST}"
+with_ais_group ${CLUSTER_TEST}
RETCODE=$?
if test x${RETCODE} != x0; then
@@ -114,4 +90,4 @@ fi
# Delete cluster store dir if test was successful.
rm -rf ${TMP_DATA_DIR}
-exit 0 \ No newline at end of file
+exit 0
diff --git a/qpid/cpp/src/tests/run_failover_soak b/qpid/cpp/src/tests/run_failover_soak
index 3c9a5589c4..8d5b37f008 100755
--- a/qpid/cpp/src/tests/run_failover_soak
+++ b/qpid/cpp/src/tests/run_failover_soak
@@ -19,29 +19,7 @@
# under the License.
#
-# Check AIS requirements and run tests if found.
-id -ng | grep '\<ais\>' >/dev/null || \
- NOGROUP="The ais group is not your primary group."
-ps -u root | grep 'aisexec\|corosync' >/dev/null || \
- NOAISEXEC="The aisexec/corosync daemon is not running as root"
-
-if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
- cat <<EOF
-
- =========== WARNING: NOT RUNNING AIS TESTS ==============
-
- Tests that depend on the openais library (used for clustering)
- will not be run because:
-
- $NOGROUP
- $NOAISEXEC
-
- ==========================================================
-
-EOF
- exit 0; # A warning, not a failure.
-fi
-
+. `dirname $0`/ais_check
host=127.0.0.1
diff --git a/qpid/cpp/src/tests/run_federation_tests b/qpid/cpp/src/tests/run_federation_tests
index 8640fb728f..3fe4bccb13 100755
--- a/qpid/cpp/src/tests/run_federation_tests
+++ b/qpid/cpp/src/tests/run_federation_tests
@@ -21,7 +21,7 @@
# Run the federation tests.
MY_DIR=`dirname \`which $0\``
-PYTHON_DIR=${MY_DIR}/../../../python
+. `dirname $0`/python_env.sh
trap stop_brokers INT TERM QUIT
@@ -42,7 +42,7 @@ if test -d ${PYTHON_DIR} ; then
echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
PYTHONPATH=${PYTHON_DIR}:${MY_DIR}
export PYTHONPATH
- ${PYTHON_DIR}/qpid-python-test -m federation -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT $@
+ $PYTHON_COMMANDS/qpid-python-test -m federation -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT $@
RETCODE=$?
stop_brokers
if test x$RETCODE != x0; then
diff --git a/qpid/cpp/src/tests/run_federation_tests.ps1 b/qpid/cpp/src/tests/run_federation_tests.ps1
index db3dbf5a11..dd0ea2fe5b 100644
--- a/qpid/cpp/src/tests/run_federation_tests.ps1
+++ b/qpid/cpp/src/tests/run_federation_tests.ps1
@@ -18,42 +18,63 @@
#
# Run the federation tests.
-$srcdir = Split-Path $myInvocation.ScriptName
-$PYTHON_DIR = $srcdir\..\..\..\python
-trap stop_brokers INT TERM QUIT
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping federation tests as python libs not found"
+ exit 1
+}
-start_brokers() {
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }"
+$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
+
+function start_brokers {
# Start 2 brokers, saving the port numbers in LOCAL_PORT, REMOTE_PORT.
- . $srcdir\background.ps1 {
- ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } }
+ . $srcdir\background.ps1 $cmdblock
while (!(Test-Path qpidd.port)) {
Start-Sleep 2
}
set-item -path env:LOCAL_PORT -value (get-content -path qpidd.port -totalcount 1)
Remove-Item qpidd.port
- . $srcdir\background.ps1 {
- ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } }
+ . $srcdir\background.ps1 $cmdblock
while (!(Test-Path qpidd.port)) {
Start-Sleep 2
}
set-item -path env:REMOTE_PORT -value (get-content -path qpidd.port -totalcount 1)
}
-stop_brokers() {
- ..\Debug\qpidd -q --port $LOCAL_PORT | Out-Default
- ..\Debug\qpidd -q --port $REMOTE_PORT | Out-Default
+function stop_brokers {
+ Invoke-Expression "$prog -q --port $env:LOCAL_PORT" | Out-Default
+ Invoke-Expression "$prog -q --port $env:REMOTE_PORT" | Out-Default
+}
+
+trap {
+ &stop_brokers
+ break
}
-if (Test-Path $PYTHON_DIR -pathType Container) {
- start_brokers
- "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
- $env:PYTHONPATH=$PYTHON_DIR
- $srcdir/federation.py -v -s $srcdir\..\..\..\specs\amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT $args
- $RETCODE=$LASTEXITCODE
- stop_brokers
- if ($RETCODE != 0) {
- "FAIL federation tests"
- exit 1
- }
+&start_brokers
+"Running federation tests using brokers on ports $env:LOCAL_PORT $env:REMOTE_PORT"
+$env:PYTHONPATH=$PYTHON_DIR
+python $srcdir/federation.py -v -s $srcdir\..\..\..\specs\amqp.0-10-qpid-errata.xml -b localhost:$env:LOCAL_PORT --remote-port $env:REMOTE_PORT $args
+$RETCODE=$LASTEXITCODE
+&stop_brokers
+if ($RETCODE -ne 0) {
+ "FAIL federation tests"
+ exit 1
}
diff --git a/qpid/cpp/src/tests/run_header_test b/qpid/cpp/src/tests/run_header_test
index 414fecd28f..1b5a3963db 100755
--- a/qpid/cpp/src/tests/run_header_test
+++ b/qpid/cpp/src/tests/run_header_test
@@ -24,7 +24,7 @@
# in both directions
srcdir=`dirname $0`
-PYTHON_DIR=$srcdir/../../../python
+. `dirname $0`/python_env.sh
test -f qpidd.port && QPID_PORT=`cat qpidd.port`
if test -d ${PYTHON_DIR} ; then
diff --git a/qpid/cpp/src/tests/run_header_test.ps1 b/qpid/cpp/src/tests/run_header_test.ps1
index add680f569..c7bc2d788e 100644
--- a/qpid/cpp/src/tests/run_header_test.ps1
+++ b/qpid/cpp/src/tests/run_header_test.ps1
@@ -21,20 +21,33 @@
# TODO: this should be expanded to cover a wider set of types and go
# in both directions
-$srcdir = Split-Path $myInvocation.ScriptName
-$PYTHON_DIR = $srcdir\..\..\..\python
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping header test as python libs not found"
+ exit 0
+}
+
if (Test-Path qpidd.port) {
set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1)
}
-if (Test-Path $PYTHON_DIR -pathType Container) {
- ./header_test -p $QPID_PORT
- $env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH"
- $srcdir/header_test.py "localhost" $QPID_PORT
- exit $LASTEXITCODE
+# Test runs from the tests directory but the test executables are in a
+# subdirectory based on the build type. Look around for it before trying
+# to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = ".\$sub\header_test.exe"
+ if (Test-Path $prog) {
+ break
+ }
}
-else {
- "Skipping header test as python libs not found"
- exit 0
+if (!(Test-Path $prog)) {
+ "Cannot locate header_test.exe"
+ exit 1
}
+Invoke-Expression "$prog -p $env:QPID_PORT" | Write-Output
+$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH"
+Invoke-Expression "python $srcdir/header_test.py localhost $env:QPID_PORT" | Write-Output
+exit $LASTEXITCODE
diff --git a/qpid/cpp/src/tests/run_long_cluster_tests b/qpid/cpp/src/tests/run_long_cluster_tests
index bc1ae8a0c1..cb9c6b219b 100755
--- a/qpid/cpp/src/tests/run_long_cluster_tests
+++ b/qpid/cpp/src/tests/run_long_cluster_tests
@@ -19,4 +19,5 @@
# under the License.
#
-./run_cluster_tests long_cluster_tests
+srcdir=`dirname $0`
+$srcdir/run_cluster_tests long_cluster_tests
diff --git a/qpid/cpp/src/tests/run_ring_queue_test b/qpid/cpp/src/tests/run_ring_queue_test
index fb90075458..9cd3775de1 100755
--- a/qpid/cpp/src/tests/run_ring_queue_test
+++ b/qpid/cpp/src/tests/run_ring_queue_test
@@ -22,9 +22,8 @@
#setup path to find qpid-config and sender/receiver test progs
srcdir=`dirname $0`
-PYTHON_DIR=$srcdir/../../../python
-export PYTHONPATH=$PYTHON_DIR
-export PATH=./:$PYTHON_DIR/commands:$PATH
+. `dirname $0`/python_env.sh
+export PATH=$PWD:$srcdir:$PYTHON_COMMANDS:$PATH
#set port to connect to via env var
test -s qpidd.port && QPID_PORT=`cat qpidd.port`
diff --git a/qpid/cpp/src/tests/run_test.ps1 b/qpid/cpp/src/tests/run_test.ps1
index ebbef07f1d..551368bc9b 100644
--- a/qpid/cpp/src/tests/run_test.ps1
+++ b/qpid/cpp/src/tests/run_test.ps1
@@ -52,7 +52,6 @@ if (Test-Path qpidd.port) {
set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1)
}
-#$p = new-object System.Diagnostics.Process
$si = new-object System.Diagnostics.ProcessStartInfo
$si.WorkingDirectory = $pwd
$si.UseShellExecute = $true
@@ -67,6 +66,6 @@ else {
$si.Arguments = $args[1..$args.length-1]
}
}
-$p = [diagnostics.process]::Start($si)
+$p = [System.Diagnostics.Process]::Start($si)
$p.WaitForExit()
exit $?
diff --git a/qpid/cpp/src/tests/start_broker.ps1 b/qpid/cpp/src/tests/start_broker.ps1
index f2aa20439a..9263262b9f 100644
--- a/qpid/cpp/src/tests/start_broker.ps1
+++ b/qpid/cpp/src/tests/start_broker.ps1
@@ -28,9 +28,26 @@ function Get-ScriptPath
if (Test-Path qpidd.port) {
Remove-Item qpidd.port
}
+
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }"
+$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
$srcdir = Get-ScriptPath
-. $srcdir\background.ps1 {
- ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } }
+. $srcdir\background.ps1 $cmdblock
+
$wait_time = 0
while (!(Test-Path qpidd.port) -and ($wait_time -lt 10)) {
Start-Sleep 2
diff --git a/qpid/cpp/src/tests/start_cluster b/qpid/cpp/src/tests/start_cluster
index 585ba082d5..fb3d27373a 100755
--- a/qpid/cpp/src/tests/start_cluster
+++ b/qpid/cpp/src/tests/start_cluster
@@ -23,20 +23,17 @@
#
# Execute command with the ais group set.
-with_ais_group() {
- id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; }
- echo $* | newgrp ais
-}
+. `dirname $0`/ais_check
rm -f cluster*.log cluster.ports qpidd.port
SIZE=${1:-3}; shift
CLUSTER=`pwd` # Cluster name=pwd, avoid clashes.
-OPTS="-d --no-module-dir --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --auth=no $@"
+OPTS="-d --no-module-dir --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --auth=no --log-enable notice+ --log-enable debug+:cluster $@"
for (( i=0; i<SIZE; ++i )); do
DDIR=`mktemp -d /tmp/start_cluster.XXXXXXXXXX`
- PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS --data-dir=$DDIR` || exit 1
+ PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS --data-dir=$DDIR` || exit 1
echo $PORT >> cluster.ports
done
diff --git a/qpid/cpp/src/tests/stop_broker.ps1 b/qpid/cpp/src/tests/stop_broker.ps1
index 165c7a63b0..4fdeb26e2b 100644
--- a/qpid/cpp/src/tests/stop_broker.ps1
+++ b/qpid/cpp/src/tests/stop_broker.ps1
@@ -21,8 +21,23 @@
Get-Content -path qpidd.port -totalCount 1 | Set-Variable -name qpid_port
Remove-Item qpidd.port
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+
# Piping the output makes the script wait for qpidd to finish.
-..\Debug\qpidd --quit --port $qpid_port | Write-Output
+Invoke-Expression "$prog --quit --port $qpid_port" | Write-Output
$stopped = $?
# Check qpidd.log.
diff --git a/qpid/cpp/src/tests/test_store.cpp b/qpid/cpp/src/tests/test_store.cpp
index 64a96bf71a..f2d3aa65a3 100644
--- a/qpid/cpp/src/tests/test_store.cpp
+++ b/qpid/cpp/src/tests/test_store.cpp
@@ -140,7 +140,8 @@ struct TestStorePlugin : public Plugin {
{
Broker* broker = dynamic_cast<Broker*>(&target);
if (!broker) return;
- broker->setStore (new TestStore(options.name, *broker));
+ boost::shared_ptr<MessageStore> p(new TestStore(options.name, *broker));
+ broker->setStore (p);
}
void initialize(qpid::Plugin::Target&) {}
diff --git a/qpid/cpp/src/tests/topictest.ps1 b/qpid/cpp/src/tests/topictest.ps1
index 04dae23ad9..58ae50c67c 100644
--- a/qpid/cpp/src/tests/topictest.ps1
+++ b/qpid/cpp/src/tests/topictest.ps1
@@ -19,9 +19,6 @@
# Run the C++ topic test
-# Clean up old log files
-Get-Item subscriber_*.log | Remove-Item
-
# Parameters with default values: s (subscribers) m (messages) b (batches)
# h (host) t (false; use transactions)
param (
@@ -32,23 +29,28 @@ param (
[switch] $t # transactional
)
+# Clean up old log files
+Get-Item subscriber_*.log | Remove-Item
+
+if ($t) {
+ $transactional = "--transactional --durable"
+}
+
function subscribe {
- "Start subscriber $args[0]"
- $LOG = "subscriber_$args[0].log"
- . $srcdir\background.ps1 {
- $env:OUTDIR\topic_listener $TRANSACTIONAL > $LOG 2>&1
- if ($LastExitCode -ne 0) { Remove-Item $LOG }
- } -inconsole
+ param ([int]$num)
+ "Start subscriber $num"
+ $LOG = "subscriber_$num.log"
+ $cmdline = "$env:OUTDIR\topic_listener $transactional > $LOG 2>&1
+ if (`$LastExitCode -ne 0) { Remove-Item $LOG }"
+ $cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
+ . $srcdir\background.ps1 $cmdblock
}
-publish() {
- if ($t) {
- $transactional = "--transactional --durable"
- }
- $env:OUTDIR\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional 2>&1
+function publish {
+ Invoke-Expression "$env:OUTDIR\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional" 2>&1
}
-$srcdir = Split-Path $myInvocation.ScriptName
+$srcdir = Split-Path $MyInvocation.MyCommand.Path
if ($broker.length) {
$broker = "-h$broker"
}
diff --git a/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp b/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp
index d51ed90758..a0b665db73 100644
--- a/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp
+++ b/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp
@@ -28,9 +28,23 @@
#include <crtdbg.h>
#include <windows.h>
+#include <iostream>
namespace {
+// Instead of popping up a window for exceptions, just print something out
+LONG _stdcall UnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo)
+{
+ DWORD dwExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode;
+
+ if (dwExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ std::cerr << "\nERROR: ACCESS VIOLATION\n" << std::endl;
+ else
+ std::cerr << "\nERROR: UNHANDLED EXCEPTION\n" << std::endl;
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
struct redirect_errors_to_stderr {
redirect_errors_to_stderr ();
};
@@ -50,6 +64,9 @@ redirect_errors_to_stderr::redirect_errors_to_stderr()
// and can't-open-file message boxes.
SetErrorMode(SEM_FAILCRITICALERRORS);
SetErrorMode(SEM_NOOPENFILEERRORBOX);
+
+ // And this will catch all unhandled exceptions.
+ SetUnhandledExceptionFilter (&UnhandledExceptionFilter);
}
} // namespace
diff --git a/qpid/cpp/src/windows/QpiddBroker.cpp b/qpid/cpp/src/windows/QpiddBroker.cpp
index 5c6eef48f8..5bf9477e6a 100644
--- a/qpid/cpp/src/windows/QpiddBroker.cpp
+++ b/qpid/cpp/src/windows/QpiddBroker.cpp
@@ -133,6 +133,14 @@ void ShutdownHandler::run() {
}
}
+// Console control handler to properly handle ctl-c.
+BOOL CtrlHandler(DWORD ctl)
+{
+ ShutdownEvent shutter; // no pid specified == shut me down
+ shutter.signal();
+ return ((ctl == CTRL_C_EVENT || ctl == CTRL_CLOSE_EVENT) ? TRUE : FALSE);
+}
+
}
struct ProcessControlOptions : public qpid::Options {
@@ -245,6 +253,7 @@ int QpiddBroker::execute (QpiddOptions *options) {
ShutdownHandler waitShut(brokerPtr);
qpid::sys::Thread waitThr(waitShut); // Wait for shutdown event
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
brokerPtr->run();
waitShut.signal(); // In case we shut down some other way
waitThr.join();
diff --git a/qpid/java/broker/etc/log4j.xml b/qpid/java/broker/etc/log4j.xml
index 8ca43ededd..4b71772a0e 100644
--- a/qpid/java/broker/etc/log4j.xml
+++ b/qpid/java/broker/etc/log4j.xml
@@ -87,6 +87,10 @@
<priority value="debug"/>
</category-->
+ <!-- Set the commons logging that the XML parser uses to WARN, it is very chatty at debug -->
+ <logger name="org.apache.commons">
+ <level value="WARN"/>
+ </logger>
<!-- Log all info events to file -->
<root>
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index add5e64ee8..644a33db01 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -27,13 +27,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ContentBody;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.*;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl;
@@ -42,12 +41,7 @@ import org.apache.qpid.server.exchange.NoRouteException;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.Pre0_10CreditManager;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.IncomingMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.UnauthorizedAccessException;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
import org.apache.qpid.server.subscription.ClientDeliveryMethod;
@@ -59,6 +53,7 @@ import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.txn.TransactionalContext;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogMessage;
import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
import org.apache.qpid.server.logging.actors.AMQPChannelActor;
@@ -119,6 +114,11 @@ public class AMQChannel
private final AMQProtocolSession _session;
private boolean _closing;
+ private final ConcurrentMap<AMQQueue, Boolean> _blockingQueues = new ConcurrentHashMap<AMQQueue, Boolean>();
+
+ private final AtomicBoolean _blocking = new AtomicBoolean(false);
+
+
private LogActor _actor;
private LogSubject _logSubject;
@@ -783,16 +783,32 @@ public class AMQChannel
return _unacknowledgedMessageMap;
}
-
+ /**
+ * Called from the ChannelFlowHandler to suspend this Channel
+ * @param suspended boolean, should this Channel be suspended
+ */
public void setSuspended(boolean suspended)
{
-
-
boolean wasSuspended = _suspended.getAndSet(suspended);
if (wasSuspended != suspended)
{
- _actor.message(_logSubject, ChannelMessages.CHN_1002(suspended ? "Stopped" : "Started"));
+ // Log Flow Started before we start the subscriptions
+ if (!suspended)
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_1002("Started"));
+ }
+
+
+ // This section takes two different approaches to perform to perform
+ // the same function. Ensuring that the Subscription has taken note
+ // of the change in Channel State
+ // Here we have become unsuspended and so we ask each the queue to
+ // perform an Async delivery for each of the subscriptions in this
+ // Channel. The alternative would be to ensure that the subscription
+ // had received the change in suspension state. That way the logic
+ // behind decieding to start an async delivery was located with the
+ // Subscription.
if (wasSuspended)
{
// may need to deliver queued messages
@@ -801,6 +817,38 @@ public class AMQChannel
s.getQueue().deliverAsync(s);
}
}
+
+
+ // Here we have become suspended so we need to ensure that each of
+ // the Subscriptions has noticed this change so that we can be sure
+ // they are not still sending messages. Again the code here is a
+ // very simplistic approach to ensure that the change of suspension
+ // has been noticed by each of the Subscriptions. Unlike the above
+ // case we don't actually need to do anything else.
+ if (!wasSuspended)
+ {
+ // may need to deliver queued messages
+ for (Subscription s : _tag2SubscriptionMap.values())
+ {
+ try
+ {
+ s.getSendLock();
+ }
+ finally
+ {
+ s.releaseSendLock();
+ }
+ }
+ }
+
+
+ // Log Suspension only after we have confirmed all suspensions are
+ // stopped.
+ if (suspended)
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_1002("Stopped"));
+ }
+
}
}
@@ -931,4 +979,37 @@ public class AMQChannel
{
return _actor;
}
+
+ public void block(AMQQueue queue)
+ {
+ if(_blockingQueues.putIfAbsent(queue, Boolean.TRUE) == null)
+ {
+
+ if(_blocking.compareAndSet(false,true))
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_1005(queue.getName().toString()));
+ flow(false);
+ }
+ }
+ }
+
+ public void unblock(AMQQueue queue)
+ {
+ if(_blockingQueues.remove(queue))
+ {
+ if(_blocking.compareAndSet(true,false))
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_1006());
+
+ flow(true);
+ }
+ }
+ }
+
+ private void flow(boolean flow)
+ {
+ MethodRegistry methodRegistry = _session.getMethodRegistry();
+ AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow);
+ _session.writeFrame(responseBody.generateFrame(_channelId));
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
index 74bb7ee969..5c73e353de 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
@@ -108,4 +108,14 @@ public class QueueConfiguration
return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap());
}
+ public long getCapacity()
+ {
+ return _config.getLong("capacity", _vHostConfig.getCapacity());
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity());
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index a72c2889d1..641b44bb18 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -104,6 +104,8 @@ public class ServerConfiguration implements SignalHandler
envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth");
envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize");
envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap");
+ envVarMap.put("QPID_QUEUECAPACITY", "capacity");
+ envVarMap.put("QPID_FLOWRESUMECAPACITY", "flowResumeCapacity");
envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer");
envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer");
envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay");
@@ -290,7 +292,6 @@ public class ServerConfiguration implements SignalHandler
return conf;
}
- @Override
public void handle(Signal arg0)
{
try
@@ -508,6 +509,16 @@ public class ServerConfiguration implements SignalHandler
return getConfig().getLong("minimumAlertRepeatGap", 0);
}
+ public long getCapacity()
+ {
+ return getConfig().getLong("capacity", 0L);
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return getConfig().getLong("flowResumeCapacity", getCapacity());
+ }
+
public int getProcessors()
{
return getConfig().getInt("connector.processors", 4);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
index 0273a13262..6c72025ec2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
@@ -166,4 +166,15 @@ public class VirtualHostConfiguration
return _config.getLong("queues.minimumAlertRepeatGap", 0);
}
+
+ public long getCapacity()
+ {
+ return _config.getLong("queues.capacity", 0l);
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return _config.getLong("queues.flowResumeCapacity", getCapacity());
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java
index 1541d3d892..9954719866 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java
@@ -35,13 +35,11 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co
super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION);
}
- @Override
public String getObjectInstanceName()
{
return ConfigurationManagement.TYPE;
}
- @Override
public void reloadSecurityConfiguration() throws Exception
{
ApplicationRegistry.getInstance().getConfiguration().reparseConfigFile();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index c04b6c559c..620799a81f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -73,7 +73,6 @@ public class DefaultExchangeFactory implements ExchangeFactory
return e;
}
- @Override
public void initialise(VirtualHostConfiguration hostConfig)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
index f3cab10ed7..fcf3fd4337 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
@@ -71,7 +71,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.warn("Dropping reject request as message is null for tag:" + deliveryTag);
// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known");
- }
+ }
else
{
if (message.isQueueDeleted())
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
index 5d7adc6371..9918013888 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
@@ -54,6 +54,13 @@ public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenB
AMQProtocolSession session = stateManager.getProtocolSession();
VirtualHost virtualHost = session.getVirtualHost();
+
+ // Protect the broker against out of order frame request.
+ if (virtualHost == null)
+ {
+ throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null);
+ }
+
final AMQChannel channel = new AMQChannel(session,channelId,
virtualHost.getMessageStore());
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java
index 4502710dd6..0059a48c06 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java
@@ -60,4 +60,9 @@ public abstract class AbstractActor implements LogActor
return _rootLogger;
}
+ public String toString()
+ {
+ return _logString;
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java
index 9b928accc0..5d2762fd1d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java
@@ -36,4 +36,12 @@ public class BrokerActor extends AbstractActor
_logString = "[Broker] ";
}
+
+ public BrokerActor(String name, RootMessageLogger logger)
+ {
+ super(logger);
+
+ _logString = "[Broker(" + name + ")] ";
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties
index 5ced7cc0b9..9169a1a651 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties
@@ -249,12 +249,16 @@ CHN-1003 = Close
# 0 - bytes allowed in prefetch
# 1 - number of messagse.
CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number}
+CHN-1005 = Flow Control Enforced (Queue {0})
+CHN-1006 = Flow Control Removed
#Queue
# 0 - owner
# 1 - priority
QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}]
QUE-1002 = Deleted
+QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number}
+QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number}
#Exchange
# 0 - type
@@ -269,4 +273,4 @@ BND-1002 = Deleted
#Subscription
SUB-1001 = Create[ : Durable][ : Arguments : {0}]
SUB-1002 = Close
-SUB-1003 = State : {0} \ No newline at end of file
+SUB-1003 = State : {0}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 2a692344d0..184504717e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -160,6 +160,17 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
void setMinimumAlertRepeatGap(long value);
+ long getCapacity();
+
+ void setCapacity(long capacity);
+
+
+ long getFlowResumeCapacity();
+
+ void setFlowResumeCapacity(long flowResumeCapacity);
+
+
+
void deleteMessageFromTop(StoreContext storeContext) throws AMQException;
long clearQueue(StoreContext storeContext) throws AMQException;
@@ -180,6 +191,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
void stop();
+ void checkCapacity(AMQChannel channel);
+
/**
* ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription
* already exists.
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
index 7509350e65..267ccf43ea 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -26,11 +26,105 @@ import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.configuration.QueueConfiguration;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import java.util.Map;
+import java.util.HashMap;
+
public class AMQQueueFactory
{
public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
+ private abstract static class QueueProperty
+ {
+
+ private final AMQShortString _argumentName;
+
+
+ public QueueProperty(String argumentName)
+ {
+ _argumentName = new AMQShortString(argumentName);
+ }
+
+ public AMQShortString getArgumentName()
+ {
+ return _argumentName;
+ }
+
+
+ public abstract void setPropertyValue(AMQQueue queue, Object value);
+
+ }
+
+ private abstract static class QueueLongProperty extends QueueProperty
+ {
+
+ public QueueLongProperty(String argumentName)
+ {
+ super(argumentName);
+ }
+
+ public void setPropertyValue(AMQQueue queue, Object value)
+ {
+ if(value instanceof Number)
+ {
+ setPropertyValue(queue, ((Number)value).longValue());
+ }
+
+ }
+
+ abstract void setPropertyValue(AMQQueue queue, long value);
+
+
+ }
+
+ private static final QueueProperty[] DECLAREABLE_PROPERTIES = {
+ new QueueLongProperty("x-qpid-maximum-message-age")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageAge(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-maximum-message-size")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageSize(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-maximum-message-count")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageCount(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-minimum-alert-repeat-gap")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMinimumAlertRepeatGap(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-capacity")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setCapacity(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-flow-resume-capacity")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setFlowResumeCapacity(value);
+ }
+ }
+
+ };
+
+
+
public static AMQQueue createAMQQueueImpl(AMQShortString name,
boolean durable,
AMQShortString owner,
@@ -53,6 +147,18 @@ public class AMQQueueFactory
//Register the new queue
virtualHost.getQueueRegistry().registerQueue(q);
q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString()));
+
+ if(arguments != null)
+ {
+ for(QueueProperty p : DECLAREABLE_PROPERTIES)
+ {
+ if(arguments.containsKey(p.getArgumentName()))
+ {
+ p.setPropertyValue(q, arguments.get(p.getArgumentName()));
+ }
+ }
+ }
+
return q;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index dbad5438dc..3b58f05f93 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -42,8 +42,7 @@ public class QueueEntryImpl implements QueueEntry
private final SimpleQueueEntryList _queueEntryList;
- private AMQMessage _message;
-
+ private final AMQMessage _message;
private Set<Subscription> _rejectedBy = null;
@@ -177,13 +176,21 @@ public class QueueEntryImpl implements QueueEntry
public String debugIdentity()
{
- return getMessage().debugIdentity();
+ AMQMessage message = getMessage();
+ if (message == null)
+ {
+ return "null";
+ }
+ else
+ {
+ return message.debugIdentity();
+ }
}
public boolean immediateAndNotDelivered()
{
- return _message.immediateAndNotDelivered();
+ return getMessage().immediateAndNotDelivered();
}
public void setRedelivered(boolean b)
@@ -385,4 +392,5 @@ public class QueueEntryImpl implements QueueEntry
{
return _queueEntryList;
}
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index b14b92b014..d781dc4dea 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -1,11 +1,10 @@
package org.apache.qpid.server.queue;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -35,6 +34,7 @@ import org.apache.qpid.server.logging.subjects.QueueLogSubject;
import org.apache.qpid.server.logging.LogSubject;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.messages.QueueMessages;
+import org.apache.qpid.server.AMQChannel;
/*
*
@@ -96,6 +96,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final Executor _asyncDelivery;
private final AtomicLong _totalMessagesReceived = new AtomicLong();
+ private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>();
+
/** max allowed size(KB) of a single message */
public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize();
@@ -122,6 +124,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private LogSubject _logSubject;
private LogActor _logActor;
+
+ private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity();
+ private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity();
+ private final AtomicBoolean _overfull = new AtomicBoolean(false);
+
protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost)
throws AMQException
{
@@ -508,8 +515,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throws AMQException
{
_deliveredMessages.incrementAndGet();
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug(sub + ": deliverMessage: " + entry.debugIdentity());
+ }
sub.send(entry);
-
}
private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry)
@@ -626,6 +636,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throw new FailedDequeueException(_name.toString(), e);
}
+ checkCapacity();
+
}
private void decrementQueueSize(final QueueEntry entry)
@@ -1170,11 +1182,64 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
- public void deliverAsync()
+ public void checkCapacity(AMQChannel channel)
{
- _stateChangeCount.incrementAndGet();
+ if(_capacity != 0l)
+ {
+ if(_atomicQueueSize.get() > _capacity)
+ {
+ _overfull.set(true);
+ //Overfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_1003(_atomicQueueSize.get(), _capacity));
+
+ if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null)
+ {
+ channel.block(this);
+ }
+
+ if(_atomicQueueSize.get() <= _flowResumeCapacity)
+ {
+
+ //Underfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity));
+
+ channel.unblock(this);
+ _blockedChannels.remove(channel);
+
+ }
+
+ }
+
+
+
+ }
+ }
+
+ private void checkCapacity()
+ {
+ if(_capacity != 0L)
+ {
+ if(_overfull.get() && _atomicQueueSize.get() <= _flowResumeCapacity)
+ {
+ if(_overfull.compareAndSet(true,false))
+ {//Underfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_1004(_atomicQueueSize.get(), _flowResumeCapacity));
+ }
- Runner runner = new Runner();
+
+ for(AMQChannel c : _blockedChannels.keySet())
+ {
+ c.unblock(this);
+ _blockedChannels.remove(c);
+ }
+ }
+ }
+ }
+
+
+ public void deliverAsync()
+ {
+ Runner runner = new Runner(_stateChangeCount.incrementAndGet());
if (_asynchronousRunner.compareAndSet(null, runner))
{
@@ -1187,13 +1252,23 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_asyncDelivery.execute(new SubFlushRunner(sub));
}
+
private class Runner implements ReadWriteRunnable
{
+ String _name;
+ public Runner(long count)
+ {
+ _name = "QueueRunner-" + count + "-" + _logActor;
+ }
+
public void run()
{
+ String originalName = Thread.currentThread().getName();
try
{
+ Thread.currentThread().setName(_name);
CurrentActor.set(_logActor);
+
processQueue(this);
}
catch (AMQException e)
@@ -1203,9 +1278,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
finally
{
CurrentActor.remove();
+ Thread.currentThread().setName(originalName);
}
-
-
}
public boolean isRead()
@@ -1217,6 +1291,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
return true;
}
+
+ public String toString()
+ {
+ return _name;
+ }
}
private class SubFlushRunner implements ReadWriteRunnable
@@ -1230,27 +1309,36 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public void run()
{
- boolean complete = false;
- try
- {
- CurrentActor.set(_sub.getLogActor());
- complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES));
- }
- catch (AMQException e)
- {
- _logger.error(e);
+ String originalName = Thread.currentThread().getName();
+ try{
+ Thread.currentThread().setName("SubFlushRunner-"+_sub);
+
+ boolean complete = false;
+ try
+ {
+ CurrentActor.set(_sub.getLogActor());
+ complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES));
+
+ }
+ catch (AMQException e)
+ {
+ _logger.error(e);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ if (!complete && !_sub.isSuspended())
+ {
+ _asyncDelivery.execute(this);
+ }
}
finally
{
- CurrentActor.remove();
- }
- if (!complete && !_sub.isSuspended())
- {
- _asyncDelivery.execute(this);
+ Thread.currentThread().setName(originalName);
}
-
}
public boolean isRead()
@@ -1278,7 +1366,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
try
{
sub.getSendLock();
- atTail = attemptDelivery(sub);
+ atTail = attemptDelivery(sub);
if (atTail && sub.isAutoClose())
{
unregisterSubscription(sub);
@@ -1308,63 +1396,81 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
return atTail;
}
+ /**
+ * Attempt delivery for the given subscription.
+ *
+ * Looks up the next node for the subscription and attempts to deliver it.
+ *
+ * @param sub
+ * @return true if we have completed all possible deliveries for this sub.
+ * @throws AMQException
+ */
private boolean attemptDelivery(Subscription sub) throws AMQException
{
boolean atTail = false;
boolean advanced = false;
- boolean subActive = sub.isActive();
+ boolean subActive = sub.isActive() && !sub.isSuspended();
if (subActive)
{
QueueEntry node = moveSubscriptionToNextNode(sub);
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug(sub + ": attempting Delivery: " + node.debugIdentity());
+ }
if (!(node.isAcquired() || node.isDeleted()))
{
- if (!sub.isSuspended())
+ if (sub.hasInterest(node))
{
- if (sub.hasInterest(node))
+ if (!sub.wouldSuspend(node))
{
- if (!sub.wouldSuspend(node))
+ if (!sub.isBrowser() && !node.acquire(sub))
{
- if (!sub.isBrowser() && !node.acquire(sub))
- {
- sub.restoreCredit(node);
- }
- else
+ sub.restoreCredit(node);
+ }
+ else
+ {
+ deliverMessage(sub, node);
+
+ if (sub.isBrowser())
{
- deliverMessage(sub, node);
+ QueueEntry newNode = _entries.next(node);
- if (sub.isBrowser())
+ if (newNode != null)
{
- QueueEntry newNode = _entries.next(node);
-
- if (newNode != null)
- {
- advanced = true;
- sub.setLastSeenEntry(node, newNode);
- node = sub.getLastSeenEntry();
- }
+ advanced = true;
+ sub.setLastSeenEntry(node, newNode);
+ node = sub.getLastSeenEntry();
}
+
}
-
- }
- else // Not enough Credit for message and wouldSuspend
- {
- //QPID-1187 - Treat the subscription as suspended for this message
- // and wait for the message to be removed to continue delivery.
- subActive = false;
- node.addStateChangeListener(new QueueEntryListener(sub, node));
}
+
}
- else
+ else // Not enough Credit for message and wouldSuspend
{
- // this subscription is not interested in this node so we can skip over it
- QueueEntry newNode = _entries.next(node);
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- }
+ //QPID-1187 - Treat the subscription as suspended for this message
+ // and wait for the message to be removed to continue delivery.
+
+ // 2009-09-30 : MR : setting subActive = false only causes, this
+ // particular delivery attempt to end. This is called from
+ // flushSubscription and processQueue both of which attempt
+ // delivery a number of times. Won't a bytes limited
+ // subscriber with not enough credit for the next message
+ // create a lot of new QELs? How about a browser that calls
+ // this method LONG.MAX_LONG times!
+ subActive = false;
+ node.addStateChangeListener(new QueueEntryListener(sub, node));
+ }
+ }
+ else
+ {
+ // this subscription is not interested in this node so we can skip over it
+ QueueEntry newNode = _entries.next(node);
+ if (newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
}
}
-
}
atTail = (_entries.next(node) == null) && !advanced;
}
@@ -1409,6 +1515,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug(sub + ": nextNode: " + (node == null ? "null" : node.debugIdentity()));
+ }
+
return node;
}
@@ -1423,6 +1535,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_asynchronousRunner.compareAndSet(runner, null);
+ // For every message enqueue/requeue the we fire deliveryAsync() which
+ // increases _stateChangeCount. If _sCC changes whilst we are in our loop
+ // (detected by setting previousStateChangeCount to stateChangeCount in the loop body)
+ // then we will continue to run for a maximum of iterations.
+ // So whilst delivery/rejection is going on a processQueue thread will be running
while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner))
{
// we want to have one extra loop after every subscription has reached the point where it cannot move
@@ -1442,20 +1559,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//iterate over the subscribers and try to advance their pointer
while (subscriptionIter.advance())
{
- boolean closeConsumer = false;
Subscription sub = subscriptionIter.getNode().getSubscription();
sub.getSendLock();
try
{
- if (sub != null)
- {
-
- QueueEntry node = moveSubscriptionToNextNode(sub);
- if (node != null)
- {
- done = attemptDelivery(sub);
- }
- }
+ done = attemptDelivery(sub);
if (done)
{
if (extraLoops == 0)
@@ -1492,11 +1600,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
// therefore we should schedule this runner again (unless someone beats us to it :-) ).
if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner))
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rescheduling runner:" + runner);
+ }
_asyncDelivery.execute(runner);
}
}
- @Override
public void checkMessageStatus() throws AMQException
{
@@ -1604,6 +1715,27 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+ public long getCapacity()
+ {
+ return _capacity;
+ }
+
+ public void setCapacity(long capacity)
+ {
+ _capacity = capacity;
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return _flowResumeCapacity;
+ }
+
+ public void setFlowResumeCapacity(long flowResumeCapacity)
+ {
+ _flowResumeCapacity = flowResumeCapacity;
+ }
+
+
public Set<NotificationCheck> getNotificationChecks()
{
return _notificationChecks;
@@ -1673,6 +1805,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
setMaximumMessageSize(config.getMaximumMessageSize());
setMaximumMessageCount(config.getMaximumMessageCount());
setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap());
+ _capacity = config.getCapacity();
+ _flowResumeCapacity = config.getFlowResumeCapacity();
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index 9575bfa1ec..1affdd6590 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -102,7 +102,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
- instance.initialise();
+ instance.initialise(instanceID);
}
catch (Exception e)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
index a049d1eb09..831f928832 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
@@ -42,18 +42,22 @@ import java.io.File;
public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
{
+ private String _registryName;
public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException
{
super(new ServerConfiguration(configurationURL));
}
- public void initialise() throws Exception
+ public void initialise(int instanceID) throws Exception
{
_rootMessageLogger = new RootMessageLoggerImpl(_configuration,
new Log4jMessageLogger());
+
+ _registryName = String.valueOf(instanceID);
+
// Set the Actor for current log messages
- CurrentActor.set(new BrokerActor(_rootMessageLogger));
+ CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger));
CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion()));
@@ -83,7 +87,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
public void close() throws Exception
{
//Set the Actor for Broker Shutdown
- CurrentActor.set(new BrokerActor(_rootMessageLogger));
+ CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger));
try
{
super.close();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
index ddb3fce5d2..92accb3499 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
@@ -43,8 +43,9 @@ public interface IApplicationRegistry
* Initialise the application registry. All initialisation must be done in this method so that any components
* that need access to the application registry itself for initialisation are able to use it. Attempting to
* initialise in the constructor will lead to failures since the registry reference will not have been set.
+ * @param instanceID the instanceID that we can use to identify this AR.
*/
- void initialise() throws Exception;
+ void initialise(int instanceID) throws Exception;
/**
* Shutdown this Registry
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
index f852514444..d2bbb795e9 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
@@ -20,16 +20,17 @@
*/
package org.apache.qpid.server.security.access;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.QueueBindBody;
-import org.apache.qpid.framing.QueueDeclareBody;
-import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
-import org.apache.qpid.server.exchange.Exchange;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
public class PrincipalPermissions
{
@@ -41,6 +42,7 @@ public class PrincipalPermissions
private static final Object CREATE_QUEUES_KEY = new Object();
private static final Object CREATE_EXCHANGES_KEY = new Object();
+
private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object();
private static final Object CREATE_QUEUE_QUEUES_KEY = new Object();
private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object();
@@ -80,248 +82,257 @@ public class PrincipalPermissions
{
switch (permission)
{
- case ACCESS:
- break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS
- case BIND:
- break; // All the details are currently included in the create setup.
case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly
- Map consumeRights = (Map) _permissions.get(permission);
-
- if (consumeRights == null)
- {
- consumeRights = new ConcurrentHashMap();
- _permissions.put(permission, consumeRights);
- }
-
- //if we have parametsre
- if (parameters.length > 0)
- {
- AMQShortString queueName = (AMQShortString) parameters[0];
- Boolean temporary = (Boolean) parameters[1];
- Boolean ownQueueOnly = (Boolean) parameters[2];
-
- if (temporary)
- {
- consumeRights.put(CONSUME_TEMPORARY_KEY, true);
- }
- else
- {
- consumeRights.put(CONSUME_TEMPORARY_KEY, false);
- }
-
- if (ownQueueOnly)
- {
- consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true);
- }
- else
- {
- consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false);
- }
-
-
- LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY);
- if (queues == null)
- {
- queues = new LinkedList();
- consumeRights.put(CONSUME_QUEUES_KEY, queues);
- }
-
- if (queueName != null)
- {
- queues.add(queueName);
- }
- }
-
-
+ grantConsume(permission, parameters);
break;
case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName
// , AMQShortString exchangeName , AMQShortString routingKey
-
- Map createRights = (Map) _permissions.get(permission);
-
- if (createRights == null)
- {
- createRights = new ConcurrentHashMap();
- _permissions.put(permission, createRights);
-
- }
-
- //The existence of the empty map mean permission to all.
- if (parameters.length == 0)
- {
- return;
- }
-
- Boolean temporary = (Boolean) parameters[0];
-
- AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
- AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null;
- //Set the routingkey to the specified value or the queueName if present
- AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName;
-
- // Get the queues map
- Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
-
- if (create_queues == null)
- {
- create_queues = new ConcurrentHashMap();
- createRights.put(CREATE_QUEUES_KEY, create_queues);
- }
-
- //Allow all temp queues to be created
- create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary);
-
- //Create empty list of queues
- Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
-
- if (create_queues_queues == null)
- {
- create_queues_queues = new ConcurrentHashMap();
- create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues);
- }
-
- // We are granting CREATE rights to all temporary queues only
- if (parameters.length == 1)
- {
- return;
- }
-
- // if we have a queueName then we need to store any associated exchange / rk bindings
- if (queueName != null)
- {
- Map queue = (Map) create_queues_queues.get(queueName);
- if (queue == null)
- {
- queue = new ConcurrentHashMap();
- create_queues_queues.put(queueName, queue);
- }
-
- if (exchangeName != null)
- {
- queue.put(exchangeName, routingKey);
- }
-
- //If no exchange is specified then the presence of the queueName in the map says any exchange is ok
- }
-
- // Store the exchange that we are being granted rights to. This will be used as part of binding
-
- //Lookup the list of exchanges
- Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
-
- if (create_queues_exchanges == null)
- {
- create_queues_exchanges = new ConcurrentHashMap();
- create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges);
- }
-
- //if we have an exchange
- if (exchangeName != null)
- {
- //Retrieve the list of permitted exchanges.
- Map exchanges = (Map) create_queues_exchanges.get(exchangeName);
-
- if (exchanges == null)
- {
- exchanges = new ConcurrentHashMap();
- create_queues_exchanges.put(exchangeName, exchanges);
- }
-
- //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY
- exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary);
-
- //Store the binding details of queue/rk for this exchange.
- if (queueName != null)
- {
- //Retrieve the list of permitted routingKeys.
- Map rKeys = (Map) exchanges.get(exchangeName);
-
- if (rKeys == null)
- {
- rKeys = new ConcurrentHashMap();
- exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys);
- }
-
- rKeys.put(queueName, routingKey);
- }
- }
+ grantCreateQueue(permission, parameters);
break;
case CREATEEXCHANGE:
// Parameters AMQShortString exchangeName , AMQShortString Class
- Map rights = (Map) _permissions.get(permission);
- if (rights == null)
- {
- rights = new ConcurrentHashMap();
- _permissions.put(permission, rights);
- }
-
- Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY);
- if (create_exchanges == null)
- {
- create_exchanges = new ConcurrentHashMap();
- rights.put(CREATE_EXCHANGES_KEY, create_exchanges);
- }
-
- //Should perhaps error if parameters[0] is null;
- AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null;
- AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct");
-
- //Store the exchangeName / class mapping if the mapping is null
- rights.put(name, className);
- break;
- case DELETE:
+ grantCreateExchange(permission, parameters);
break;
-
case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
- Map publishRights = (Map) _permissions.get(permission);
-
- if (publishRights == null)
- {
- publishRights = new ConcurrentHashMap();
- _permissions.put(permission, publishRights);
- }
-
- if (parameters == null || parameters.length == 0)
- {
- //If we have no parameters then allow publish to all destinations
- // this is signified by having a null value for publish_exchanges
- }
- else
- {
- Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
-
- if (publish_exchanges == null)
- {
- publish_exchanges = new ConcurrentHashMap();
- publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges);
- }
-
-
- HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]);
-
- // Check to see if we have a routing key
- if (parameters.length == 2)
- {
- if (routingKeys == null)
- {
- routingKeys = new HashSet<AMQShortString>();
- }
- //Add routing key to permitted publish destinations
- routingKeys.add(parameters[1]);
- }
-
- // Add the updated routingkey list or null if all values allowed
- publish_exchanges.put(parameters[0], routingKeys);
- }
+ grantPublish(permission, parameters);
break;
+ /* The other cases just fall through to no-op */
+ case DELETE:
+ case ACCESS: // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS
+ case BIND: // All the details are currently included in the create setup.
case PURGE:
- break;
case UNBIND:
break;
}
}
+ private void grantPublish(Permission permission, Object... parameters) {
+ Map publishRights = (Map) _permissions.get(permission);
+
+ if (publishRights == null)
+ {
+ publishRights = new ConcurrentHashMap();
+ _permissions.put(permission, publishRights);
+ }
+
+ if (parameters == null || parameters.length == 0)
+ {
+ //If we have no parameters then allow publish to all destinations
+ // this is signified by having a null value for publish_exchanges
+ }
+ else
+ {
+ Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
+
+ if (publish_exchanges == null)
+ {
+ publish_exchanges = new ConcurrentHashMap();
+ publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges);
+ }
+
+
+ HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]);
+
+ // Check to see if we have a routing key
+ if (parameters.length == 2)
+ {
+ if (routingKeys == null)
+ {
+ routingKeys = new HashSet<AMQShortString>();
+ }
+ //Add routing key to permitted publish destinations
+ routingKeys.add(parameters[1]);
+ }
+
+ // Add the updated routingkey list or null if all values allowed
+ publish_exchanges.put(parameters[0], routingKeys);
+ }
+ }
+
+ private void grantCreateExchange(Permission permission, Object... parameters) {
+ Map rights = (Map) _permissions.get(permission);
+ if (rights == null)
+ {
+ rights = new ConcurrentHashMap();
+ _permissions.put(permission, rights);
+ }
+
+ Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY);
+ if (create_exchanges == null)
+ {
+ create_exchanges = new ConcurrentHashMap();
+ rights.put(CREATE_EXCHANGES_KEY, create_exchanges);
+ }
+
+ //Should perhaps error if parameters[0] is null;
+ AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null;
+ AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct");
+
+ //Store the exchangeName / class mapping if the mapping is null
+ rights.put(name, className);
+ }
+
+ private void grantCreateQueue(Permission permission, Object... parameters) {
+ Map createRights = (Map) _permissions.get(permission);
+
+ if (createRights == null)
+ {
+ createRights = new ConcurrentHashMap();
+ _permissions.put(permission, createRights);
+
+ }
+
+ //The existence of the empty map mean permission to all.
+ if (parameters.length == 0)
+ {
+ return;
+ }
+
+ Boolean temporary = (Boolean) parameters[0];
+
+ AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
+ AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null;
+ //Set the routingkey to the specified value or the queueName if present
+ AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName;
+
+ // Get the queues map
+ Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
+
+ if (create_queues == null)
+ {
+ create_queues = new ConcurrentHashMap();
+ createRights.put(CREATE_QUEUES_KEY, create_queues);
+ }
+
+ //Allow all temp queues to be created
+ create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary);
+
+ //Create empty list of queues
+ Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
+
+ if (create_queues_queues == null)
+ {
+ create_queues_queues = new ConcurrentHashMap();
+ create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues);
+ }
+
+ // We are granting CREATE rights to all temporary queues only
+ if (parameters.length == 1)
+ {
+ return;
+ }
+
+ // if we have a queueName then we need to store any associated exchange / rk bindings
+ if (queueName != null)
+ {
+ Map queue = (Map) create_queues_queues.get(queueName);
+ if (queue == null)
+ {
+ queue = new ConcurrentHashMap();
+ create_queues_queues.put(queueName, queue);
+ }
+
+ if (exchangeName != null)
+ {
+ queue.put(exchangeName, routingKey);
+ }
+
+ //If no exchange is specified then the presence of the queueName in the map says any exchange is ok
+ }
+
+ // Store the exchange that we are being granted rights to. This will be used as part of binding
+
+ //Lookup the list of exchanges
+ Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
+
+ if (create_queues_exchanges == null)
+ {
+ create_queues_exchanges = new ConcurrentHashMap();
+ create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges);
+ }
+
+ //if we have an exchange
+ if (exchangeName != null)
+ {
+ //Retrieve the list of permitted exchanges.
+ Map exchanges = (Map) create_queues_exchanges.get(exchangeName);
+
+ if (exchanges == null)
+ {
+ exchanges = new ConcurrentHashMap();
+ create_queues_exchanges.put(exchangeName, exchanges);
+ }
+
+ //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY
+ exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary);
+
+ //Store the binding details of queue/rk for this exchange.
+ if (queueName != null)
+ {
+ //Retrieve the list of permitted routingKeys.
+ Map rKeys = (Map) exchanges.get(exchangeName);
+
+ if (rKeys == null)
+ {
+ rKeys = new ConcurrentHashMap();
+ exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys);
+ }
+
+ rKeys.put(queueName, routingKey);
+ }
+ }
+ }
+
+ private void grantConsume(Permission permission, Object... parameters) {
+ Map consumeRights = (Map) _permissions.get(permission);
+
+ if (consumeRights == null)
+ {
+ consumeRights = new ConcurrentHashMap();
+ _permissions.put(permission, consumeRights);
+ }
+
+ //if we have parametsre
+ if (parameters.length > 0)
+ {
+ AMQShortString queueName = (AMQShortString) parameters[0];
+ Boolean temporary = (Boolean) parameters[1];
+ Boolean ownQueueOnly = (Boolean) parameters[2];
+
+ if (temporary)
+ {
+ consumeRights.put(CONSUME_TEMPORARY_KEY, true);
+ }
+ else
+ {
+ consumeRights.put(CONSUME_TEMPORARY_KEY, false);
+ }
+
+ if (ownQueueOnly)
+ {
+ consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true);
+ }
+ else
+ {
+ consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false);
+ }
+
+
+ LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY);
+ if (queues == null)
+ {
+ queues = new LinkedList();
+ consumeRights.put(CONSUME_QUEUES_KEY, queues);
+ }
+
+ if (queueName != null)
+ {
+ queues.add(queueName);
+ }
+ }
+ }
+
/**
*
* @param permission the type of permission to check
@@ -346,267 +357,286 @@ public class PrincipalPermissions
return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it.
// The existence of this user specific PP can be validated in the map SimpleXML maintains.
case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey
-
- Exchange exchange = (Exchange) parameters[1];
-
- AMQQueue bind_queueName = (AMQQueue) parameters[2];
- AMQShortString routingKey = (AMQShortString) parameters[3];
-
- //Get all Create Rights for this user
- Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE);
-
- //Look up the Queue Creation Rights
- Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY);
-
- //Lookup the list of queues
- Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY);
-
- // Check and see if we have a queue white list to check
- if (bind_create_queues_queues != null)
- {
- //There a white list for queues
- Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName);
-
- if (exchangeDetails == null) //Then all queue can be bound to all exchanges.
- {
- return AuthzResult.ALLOWED;
- }
-
- // Check to see if we have a white list of routingkeys to check
- Map rkeys = (Map) exchangeDetails.get(exchange.getName());
-
- // if keys is null then any rkey is allowed on this exchange
- if (rkeys == null)
- {
- // There is no routingkey white list
- return AuthzResult.ALLOWED;
- }
- else
- {
- // We have routingKeys so a match must be found to allowed binding
- Iterator keys = rkeys.keySet().iterator();
-
- boolean matched = false;
- while (keys.hasNext() && !matched)
- {
- AMQShortString rkey = (AMQShortString) keys.next();
- if (rkey.endsWith("*"))
- {
- matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString());
- }
- else
- {
- matched = routingKey.equals(rkey);
- }
- }
-
-
- return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
-
-
- }
- else
- {
- //There a is no white list for queues
-
- // So can allow all queues to be bound
- // but we should first check and see if we have a temp queue and validate that we are allowed
- // to bind temp queues.
-
- //Check to see if we have a temporary queue
- if (bind_queueName.isAutoDelete())
- {
- // Check and see if we have an exchange white list.
- Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
-
- // If the exchange exists then we must check to see if temporary queues are allowed here
- if (bind_exchanges != null)
- {
- // Check to see if the requested exchange is allowed.
- Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName());
-
- return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
-
- //no white list so all allowed, drop through to return true below.
- }
-
- // not a temporary queue and no white list so all allowed.
- return AuthzResult.ALLOWED;
- }
-
+ return authoriseBind(parameters);
case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name
-
- Map createRights = (Map) _permissions.get(permission);
-
- // If there are no create rights then deny request
- if (createRights == null)
- {
- return AuthzResult.DENIED;
- }
-
- //Look up the Queue Creation Rights
- Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
-
- //Lookup the list of queues allowed to be created
- Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
-
-
- AMQShortString queueName = (AMQShortString) parameters[1];
- Boolean autoDelete = (Boolean) parameters[0];
-
- if (autoDelete)// we have a temporary queue
- {
- return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
- else
- {
- // If there is a white list then check
- if (create_queues_queues == null || create_queues_queues.containsKey(queueName))
- {
- return AuthzResult.ALLOWED;
- }
- else
- {
- return AuthzResult.DENIED;
- }
-
- }
+ return authoriseCreateQueue(permission, parameters);
case CREATEEXCHANGE:
- Map rights = (Map) _permissions.get(permission);
-
- AMQShortString exchangeName = (AMQShortString) parameters[0];
-
- // If the exchange list is doesn't exist then all is allowed else
- // check the valid exchanges
- if (rights == null || rights.containsKey(exchangeName))
- {
- return AuthzResult.ALLOWED;
- }
- else
- {
- return AuthzResult.DENIED;
- }
+ return authoriseCreateExchange(permission, parameters);
case CONSUME: // Parameters : AMQQueue
-
- if (parameters.length == 1 && parameters[0] instanceof AMQQueue)
- {
- AMQQueue queue = ((AMQQueue) parameters[0]);
- Map queuePermissions = (Map) _permissions.get(permission);
-
- List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY);
-
- Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY);
- Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY);
-
- // If user is allowed to publish to temporary queues and this is a temp queue then allow it.
- if (temporayQueues)
- {
- if (queue.isAutoDelete())
- // This will allow consumption from any temporary queue including ones not owned by this user.
- // Of course the exclusivity will not be broken.
- {
- // if not limited to ownQueuesOnly then ok else check queue Owner.
- return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
- else
- {
- return AuthzResult.DENIED;
- }
- }
-
- // if queues are white listed then ensure it is ok
- if (queues != null)
- {
- // if no queues are listed then ALL are ok othereise it must be specified.
- if (ownQueuesOnly)
- {
- if (queue.getOwner().equals(_user))
- {
- return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
- else
- {
- return AuthzResult.DENIED;
- }
- }
-
- // If we are
- return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
- }
-
- // Can't authenticate without the right parameters
- return AuthzResult.DENIED;
- case DELETE:
- break;
-
+ return authoriseConsume(permission, parameters);
case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
- Map publishRights = (Map) _permissions.get(permission);
-
- if (publishRights == null)
- {
- return AuthzResult.DENIED;
- }
-
- Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
-
- // Having no exchanges listed gives full publish rights to all exchanges
- if (exchanges == null)
- {
- return AuthzResult.ALLOWED;
- }
- // Otherwise exchange must be listed in the white list
-
- // If the map doesn't have the exchange then it isn't allowed
- if (!exchanges.containsKey(((Exchange) parameters[0]).getName()))
- {
- return AuthzResult.DENIED;
- }
- else
- {
-
- // Get valid routing keys
- HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName());
-
- // Having no routingKeys in the map then all are allowed.
- if (routingKeys == null)
- {
- return AuthzResult.ALLOWED;
- }
- else
- {
- // We have routingKeys so a match must be found to allowed binding
- Iterator keys = routingKeys.iterator();
-
-
- AMQShortString publishRKey = (AMQShortString)parameters[1];
-
- boolean matched = false;
- while (keys.hasNext() && !matched)
- {
- AMQShortString rkey = (AMQShortString) keys.next();
-
- if (rkey.endsWith("*"))
- {
- matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1));
- }
- else
- {
- matched = publishRKey.equals(rkey);
- }
- }
- return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
- }
- }
+ return authorisePublish(permission, parameters);
+ /* Fall through */
+ case DELETE:
case PURGE:
- break;
case UNBIND:
- break;
-
+ default:
+ return AuthzResult.DENIED;
}
- return AuthzResult.DENIED;
}
+
+ private AuthzResult authoriseConsume(Permission permission, Object... parameters) {
+ if (parameters.length == 1 && parameters[0] instanceof AMQQueue)
+ {
+ AMQQueue queue = ((AMQQueue) parameters[0]);
+ Map queuePermissions = (Map) _permissions.get(permission);
+
+ if (queuePermissions == null)
+ {
+ //if the outer map is null, the user has no CONSUME rights at all
+ return AuthzResult.DENIED;
+ }
+
+ List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY);
+
+ Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY);
+ Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY);
+
+ // If user is allowed to publish to temporary queues and this is a temp queue then allow it.
+ if (temporayQueues)
+ {
+ if (queue.isAutoDelete())
+ // This will allow consumption from any temporary queue including ones not owned by this user.
+ // Of course the exclusivity will not be broken.
+ {
+ // if not limited to ownQueuesOnly then ok else check queue Owner.
+ return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ // if queues are white listed then ensure it is ok
+ if (queues != null)
+ {
+ // if no queues are listed then ALL are ok othereise it must be specified.
+ if (ownQueuesOnly)
+ {
+ if (queue.getOwner().equals(_user))
+ {
+ return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ // If we are
+ return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ }
+
+ // Can't authenticate without the right parameters
+ return AuthzResult.DENIED;
+ }
+
+ private AuthzResult authorisePublish(Permission permission, Object... parameters) {
+ Map publishRights = (Map) _permissions.get(permission);
+
+ if (publishRights == null)
+ {
+ return AuthzResult.DENIED;
+ }
+
+ Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
+
+ // Having no exchanges listed gives full publish rights to all exchanges
+ if (exchanges == null)
+ {
+ return AuthzResult.ALLOWED;
+ }
+ // Otherwise exchange must be listed in the white list
+
+ // If the map doesn't have the exchange then it isn't allowed
+ if (!exchanges.containsKey(((Exchange) parameters[0]).getName()))
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+
+ // Get valid routing keys
+ HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName());
+
+ // Having no routingKeys in the map then all are allowed.
+ if (routingKeys == null)
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ // We have routingKeys so a match must be found to allowed binding
+ Iterator keys = routingKeys.iterator();
+
+
+ AMQShortString publishRKey = (AMQShortString)parameters[1];
+
+ boolean matched = false;
+ while (keys.hasNext() && !matched)
+ {
+ AMQShortString rkey = (AMQShortString) keys.next();
+
+ if (rkey.endsWith("*"))
+ {
+ matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1));
+ }
+ else
+ {
+ matched = publishRKey.equals(rkey);
+ }
+ }
+ return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ }
+ }
+
+ private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters) {
+ Map rights = (Map) _permissions.get(permission);
+
+ AMQShortString exchangeName = (AMQShortString) parameters[0];
+
+ // If the exchange list is doesn't exist then all is allowed else
+ // check the valid exchanges
+ if (rights == null || rights.containsKey(exchangeName))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters) {
+ Map createRights = (Map) _permissions.get(permission);
+
+ // If there are no create rights then deny request
+ if (createRights == null)
+ {
+ return AuthzResult.DENIED;
+ }
+
+ //Look up the Queue Creation Rights
+ Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
+
+ //Lookup the list of queues allowed to be created
+ Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
+
+
+ AMQShortString queueName = (AMQShortString) parameters[1];
+ Boolean autoDelete = (Boolean) parameters[0];
+
+ if (autoDelete)// we have a temporary queue
+ {
+ return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ else
+ {
+ // If there is a white list then check
+ if (create_queues_queues == null || create_queues_queues.containsKey(queueName))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+
+ }
+ }
+
+ private AuthzResult authoriseBind(Object... parameters) {
+ Exchange exchange = (Exchange) parameters[1];
+
+ AMQQueue bind_queueName = (AMQQueue) parameters[2];
+ AMQShortString routingKey = (AMQShortString) parameters[3];
+
+ //Get all Create Rights for this user
+ Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE);
+
+ //Look up the Queue Creation Rights
+ Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY);
+
+ //Lookup the list of queues
+ Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY);
+
+ // Check and see if we have a queue white list to check
+ if (bind_create_queues_queues != null)
+ {
+ //There a white list for queues
+ Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName);
+
+ if (exchangeDetails == null) //Then all queue can be bound to all exchanges.
+ {
+ return AuthzResult.ALLOWED;
+ }
+
+ // Check to see if we have a white list of routingkeys to check
+ Map rkeys = (Map) exchangeDetails.get(exchange.getName());
+
+ // if keys is null then any rkey is allowed on this exchange
+ if (rkeys == null)
+ {
+ // There is no routingkey white list
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ // We have routingKeys so a match must be found to allowed binding
+ Iterator keys = rkeys.keySet().iterator();
+
+ boolean matched = false;
+ while (keys.hasNext() && !matched)
+ {
+ AMQShortString rkey = (AMQShortString) keys.next();
+ if (rkey.endsWith("*"))
+ {
+ matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString());
+ }
+ else
+ {
+ matched = routingKey.equals(rkey);
+ }
+ }
+
+
+ return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+
+
+ }
+ else
+ {
+ //There a is no white list for queues
+
+ // So can allow all queues to be bound
+ // but we should first check and see if we have a temp queue and validate that we are allowed
+ // to bind temp queues.
+
+ //Check to see if we have a temporary queue
+ if (bind_queueName.isAutoDelete())
+ {
+ // Check and see if we have an exchange white list.
+ Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
+
+ // If the exchange exists then we must check to see if temporary queues are allowed here
+ if (bind_exchanges != null)
+ {
+ // Check to see if the requested exchange is allowed.
+ Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName());
+
+ return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+
+ //no white list so all allowed, drop through to return true below.
+ }
+
+ // not a temporary queue and no white list so all allowed.
+ return AuthzResult.ALLOWED;
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
index a6fae053c2..ca6b68dafa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
@@ -35,28 +35,24 @@ public abstract class BasicACLPlugin implements ACLPlugin
// Returns true or false if the plugin should authorise or deny the request
protected abstract AuthzResult getResult();
- @Override
public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch,
AMQQueue queue, AMQShortString routingKey)
{
return getResult();
}
- @Override
public AuthzResult authoriseConnect(AMQProtocolSession session,
VirtualHost virtualHost)
{
return getResult();
}
- @Override
public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck,
AMQQueue queue)
{
return getResult();
}
- @Override
public AuthzResult authoriseConsume(AMQProtocolSession session,
boolean exclusive, boolean noAck, boolean noLocal, boolean nowait,
AMQQueue queue)
@@ -64,7 +60,6 @@ public abstract class BasicACLPlugin implements ACLPlugin
return getResult();
}
- @Override
public AuthzResult authoriseCreateExchange(AMQProtocolSession session,
boolean autoDelete, boolean durable, AMQShortString exchangeName,
boolean internal, boolean nowait, boolean passive,
@@ -73,7 +68,6 @@ public abstract class BasicACLPlugin implements ACLPlugin
return getResult();
}
- @Override
public AuthzResult authoriseCreateQueue(AMQProtocolSession session,
boolean autoDelete, boolean durable, boolean exclusive,
boolean nowait, boolean passive, AMQShortString queue)
@@ -81,19 +75,16 @@ public abstract class BasicACLPlugin implements ACLPlugin
return getResult();
}
- @Override
public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue)
{
return getResult();
}
- @Override
public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange)
{
return getResult();
}
- @Override
public AuthzResult authorisePublish(AMQProtocolSession session,
boolean immediate, boolean mandatory, AMQShortString routingKey,
Exchange e)
@@ -101,20 +92,17 @@ public abstract class BasicACLPlugin implements ACLPlugin
return getResult();
}
- @Override
public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue)
{
return getResult();
}
- @Override
public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch,
AMQShortString routingKey, AMQQueue queue)
{
return getResult();
}
- @Override
public void setConfiguration(Configuration config)
{
// no-op
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
index 3a81932123..7450322130 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
@@ -211,7 +211,6 @@ public class FirewallPlugin extends AbstractACLPlugin
}
- @Override
public void setConfiguration(Configuration config) throws ConfigurationException
{
// Get default action
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
index 4efe381a8b..8658101cd8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
@@ -42,7 +42,6 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana
return _databases;
}
- @Override
public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException
{
//todo
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
index 72d6afc65c..2893e916cc 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -630,11 +630,19 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public QueueEntry getLastSeenEntry()
{
- return _queueContext.get();
+ QueueEntry entry = _queueContext.get();
+
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug(_logActor + ": lastSeenEntry: " + (entry == null ? "null" : entry.debugIdentity()));
+ }
+
+ return entry;
}
public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue)
{
+ _logger.debug(debugIdentity() + " Setting Last Seen To:" + (newvalue == null ? "nullNV" : newvalue.debugIdentity()));
return _queueContext.compareAndSet(expected,newvalue);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
index 3c71282c57..450852cef7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
@@ -97,6 +97,7 @@ public class LocalTransactionalContext implements TransactionalContext
try
{
QueueEntry entry = _queue.enqueue(getStoreContext(),_message);
+ _queue.checkCapacity(_channel);
if(entry.immediateAndNotDelivered())
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
index 28af36e3db..10d6021d27 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
@@ -91,6 +91,8 @@ public class NonTransactionalContext implements TransactionalContext
public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException
{
QueueEntry entry = queue.enqueue(_storeContext, message);
+ queue.checkCapacity(_channel);
+
//following check implements the functionality
//required by the 'immediate' flag:
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
index b16a289f0a..a131c2a465 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
@@ -31,6 +31,7 @@ import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.AMQException;
import org.apache.commons.configuration.Configuration;
@@ -271,6 +272,15 @@ public class MockAMQQueue implements AMQQueue
//To change body of implemented methods use File | Settings | File Templates.
}
+ public boolean getBlockOnQueueFull()
+ {
+ return false;
+ }
+
+ public void setBlockOnQueueFull(boolean block)
+ {
+ }
+
public long getMinimumAlertRepeatGap()
{
return 0; //To change body of implemented methods use File | Settings | File Templates.
@@ -285,8 +295,8 @@ public class MockAMQQueue implements AMQQueue
{
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
+
- @Override
public void checkMessageStatus() throws AMQException
{
//To change body of implemented methods use File | Settings | File Templates.
@@ -317,6 +327,10 @@ public class MockAMQQueue implements AMQQueue
//To change body of implemented methods use File | Settings | File Templates.
}
+ public void checkCapacity(AMQChannel channel)
+ {
+ }
+
public ManagedObject getManagedObject()
{
return null; //To change body of implemented methods use File | Settings | File Templates.
@@ -327,12 +341,31 @@ public class MockAMQQueue implements AMQQueue
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
- @Override
public void setMinimumAlertRepeatGap(long value)
{
}
+ public long getCapacity()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setCapacity(long capacity)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setFlowResumeCapacity(long flowResumeCapacity)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void configure(QueueConfiguration config)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
index e75ed640aa..4c8ff01be0 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
@@ -22,7 +22,6 @@ package org.apache.qpid.server.registry;
import junit.framework.TestCase;
import org.apache.qpid.server.util.TestApplicationRegistry;
-import org.apache.qpid.AMQException;
import java.security.Security;
import java.security.Provider;
@@ -69,7 +68,7 @@ public class ApplicationRegistryShutdownTest extends TestCase
// Register new providers
try
{
- _registry.initialise();
+ _registry.initialise(ApplicationRegistry.DEFAULT_INSTANCE);
}
catch (Exception e)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java
index 8fef8baa02..6b8201eefb 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java
@@ -27,6 +27,7 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.logging.RootMessageLoggerImpl;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.logging.actors.BrokerActor;
import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger;
import org.apache.qpid.server.management.NoopManagedObjectRegistry;
import org.apache.qpid.server.plugins.PluginManager;
@@ -50,7 +51,7 @@ public class NullApplicationRegistry extends ApplicationRegistry
super(new ServerConfiguration(new PropertiesConfiguration()));
}
- public void initialise() throws Exception
+ public void initialise(int instanceID) throws Exception
{
_logger.info("Initialising NullApplicationRegistry");
@@ -92,6 +93,8 @@ public class NullApplicationRegistry extends ApplicationRegistry
@Override
public void close() throws Exception
{
+ CurrentActor.set(new BrokerActor(_rootMessageLogger));
+
try
{
super.close();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
index 43948c05c4..7b7c86bb80 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
@@ -21,7 +21,6 @@
package org.apache.qpid.server.util;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.configuration.VirtualHostConfiguration;
@@ -31,7 +30,6 @@ import org.apache.qpid.server.management.NoopManagedObjectRegistry;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.security.access.ACLPlugin;
import org.apache.qpid.server.security.access.plugins.AllowAll;
import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
@@ -45,7 +43,6 @@ import org.apache.qpid.server.logging.actors.TestLogActor;
import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Properties;
import java.util.Arrays;
@@ -75,7 +72,7 @@ public class TestApplicationRegistry extends ApplicationRegistry
_config = config;
}
- public void initialise() throws Exception
+ public void initialise(int instanceID) throws Exception
{
_rootMessageLogger = new RootMessageLoggerImpl(_configuration,
new Log4jMessageLogger());
diff --git a/qpid/java/client/src/main/java/log4j.xml b/qpid/java/client/src/main/java/log4j.xml
new file mode 100644
index 0000000000..c27acba818
--- /dev/null
+++ b/qpid/java/client/src/main/java/log4j.xml
@@ -0,0 +1,36 @@
+<!--
+
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache.qpid">
+ <level value="warn"/>
+ <appender-ref ref="console" />
+ </logger>
+
+</log4j:configuration>
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
index 0d2adcec8a..ed122a772e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -313,7 +313,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
protected AMQConnectionDelegate _delegate;
// this connection maximum number of prefetched messages
- protected int _maxPrefetch;
+ private int _maxPrefetch;
//Indicates whether persistent messages are synchronized
private boolean _syncPersistence;
@@ -450,7 +450,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
else
{
- // use the defaul value set for all connections
+ // use the default value set for all connections
_syncPublish = System.getProperty((ClientProperties.SYNC_ACK_PROP_NAME),_syncPublish);
}
@@ -512,7 +512,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
boolean retryAllowed = true;
Exception connectionException = null;
- while (!_connected && retryAllowed)
+ while (!_connected && retryAllowed && brokerDetails != null)
{
ProtocolVersion pe = null;
try
@@ -691,12 +691,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public boolean attemptReconnection()
{
- while (_failoverPolicy.failoverAllowed())
+ BrokerDetails broker = null;
+ while (_failoverPolicy.failoverAllowed() && (broker = _failoverPolicy.getNextBrokerDetails()) != null)
{
try
{
- makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
-
+ makeBrokerConnection(broker);
return true;
}
catch (Exception e)
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
index e5980d8b7d..e6c3473cb1 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
@@ -39,6 +39,15 @@ public interface AMQConnectionDelegate
Session createSession(final boolean transacted, final int acknowledgeMode,
final int prefetchHigh, final int prefetchLow) throws JMSException;
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ XASession createXASession() throws JMSException;
+
XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
void failoverPrep();
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index 927929c94a..4d10180667 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -100,6 +100,18 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
}
/**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
+ /**
* create an XA Session and start it if required.
*/
public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException
@@ -285,7 +297,6 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
_qpidConnection.setIdleTimeout(l);
}
- @Override
public int getMaxChannelID()
{
return Integer.MAX_VALUE;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index 9876393d4c..97d0d0516e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -191,6 +191,18 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
}, _conn).execute();
}
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
private void createChannelOverWire(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
throws AMQException, FailoverException
{
@@ -290,7 +302,6 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
public void setIdleTimeout(long l){}
- @Override
public int getMaxChannelID()
{
return (int) (Math.pow(2, 16)-1);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 2e3e417c95..dd9a00ce10 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -21,7 +21,6 @@
package org.apache.qpid.client;
import java.io.Serializable;
-import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -60,6 +59,7 @@ import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
+import javax.jms.TransactionRolledBackException;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
@@ -113,7 +113,6 @@ import org.slf4j.LoggerFactory;
public abstract class AMQSession<C extends BasicMessageConsumer, P extends BasicMessageProducer> extends Closeable implements Session, QueueSession, TopicSession
{
-
public static final class IdToConsumerMap<C extends BasicMessageConsumer>
{
private final BasicMessageConsumer[] _fastAccessConsumers = new BasicMessageConsumer[16];
@@ -198,16 +197,32 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
* The default value for immediate flag used by producers created by this session is false. That is, a consumer does
* not need to be attached to a queue.
*/
- protected static final boolean DEFAULT_IMMEDIATE = Boolean.parseBoolean(System.getProperty("qpid.default_immediate", "false"));
+ protected final boolean DEFAULT_IMMEDIATE = Boolean.parseBoolean(System.getProperty("qpid.default_immediate", "false"));
/**
* The default value for mandatory flag used by producers created by this session is true. That is, server will not
* silently drop messages where no queue is connected to the exchange for the message.
*/
- protected static final boolean DEFAULT_MANDATORY = Boolean.parseBoolean(System.getProperty("qpid.default_mandatory", "true"));
+ protected final boolean DEFAULT_MANDATORY = Boolean.parseBoolean(System.getProperty("qpid.default_mandatory", "true"));
+
+ protected final boolean DEFAULT_WAIT_ON_SEND = Boolean.parseBoolean(System.getProperty("qpid.default_wait_on_send", "false"));
+
+ /**
+ * The period to wait while flow controlled before sending a log message confirming that the session is still
+ * waiting on flow control being revoked
+ */
+ protected final long FLOW_CONTROL_WAIT_PERIOD = Long.getLong("qpid.flow_control_wait_notify_period",5000L);
+
+ /**
+ * The period to wait while flow controlled before declaring a failure
+ */
+ public static final long DEFAULT_FLOW_CONTROL_WAIT_FAILURE = 120000L;
+ protected final long FLOW_CONTROL_WAIT_FAILURE = Long.getLong("qpid.flow_control_wait_failure",
+ DEFAULT_FLOW_CONTROL_WAIT_FAILURE);
protected final boolean DECLARE_QUEUES =
Boolean.parseBoolean(System.getProperty("qpid.declare_queues", "true"));
+
protected final boolean DECLARE_EXCHANGES =
Boolean.parseBoolean(System.getProperty("qpid.declare_exchanges", "true"));
@@ -244,10 +259,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private int _ticket;
/** Holds the high mark for prefetched message, at which the session is suspended. */
- private int _defaultPrefetchHighMark;
+ private int _prefetchHighMark;
/** Holds the low mark for prefetched messages, below which the session is resumed. */
- private int _defaultPrefetchLowMark;
+ private int _prefetchLowMark;
/** Holds the message listener, if any, which is attached to this session. */
private MessageListener _messageListener = null;
@@ -428,13 +443,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_channelId = channelId;
_messageFactoryRegistry = messageFactoryRegistry;
- _defaultPrefetchHighMark = defaultPrefetchHighMark;
- _defaultPrefetchLowMark = defaultPrefetchLowMark;
+ _prefetchHighMark = defaultPrefetchHighMark;
+ _prefetchLowMark = defaultPrefetchLowMark;
if (_acknowledgeMode == NO_ACKNOWLEDGE)
{
_queue =
- new FlowControllingBlockingQueue(_defaultPrefetchHighMark, _defaultPrefetchLowMark,
+ new FlowControllingBlockingQueue(_prefetchHighMark, _prefetchLowMark,
new FlowControllingBlockingQueue.ThresholdListener()
{
private final AtomicBoolean _suspendState = new AtomicBoolean();
@@ -442,7 +457,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void aboveThreshold(int currentValue)
{
_logger.debug(
- "Above threshold(" + _defaultPrefetchHighMark
+ "Above threshold(" + _prefetchHighMark
+ ") so suspending channel. Current value is " + currentValue);
_suspendState.set(true);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -452,7 +467,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void underThreshold(int currentValue)
{
_logger.debug(
- "Below threshold(" + _defaultPrefetchLowMark
+ "Below threshold(" + _prefetchLowMark
+ ") so unsuspending channel. Current value is " + currentValue);
_suspendState.set(false);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -462,7 +477,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else
{
- _queue = new FlowControllingBlockingQueue(_defaultPrefetchHighMark, null);
+ _queue = new FlowControllingBlockingQueue(_prefetchHighMark, null);
}
}
@@ -759,8 +774,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
+ //Check that we are clean to commit.
+ if (_failedOverDirty)
+ {
+ rollback();
+
+ throw new TransactionRolledBackException("Connection failover has occured since last send. " +
+ "Forced rollback");
+ }
+
- // TGM FIXME: what about failover?
// Acknowledge all delivered messages
while (true)
{
@@ -778,7 +801,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
- throw new JMSAMQException("Failed to commit: " + e.getMessage(), e);
+ throw new JMSAMQException("Failed to commit: " + e.getMessage() + ":" + e.getCause(), e);
}
catch (FailoverException e)
{
@@ -870,7 +893,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, false,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, false,
messageSelector, null, true, true);
}
@@ -878,7 +901,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic), null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), null, null,
false, false);
}
@@ -886,7 +909,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, true, null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, true, null, null,
false, false);
}
@@ -894,7 +917,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -903,7 +926,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -912,7 +935,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, true,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, true,
messageSelector, null, false, false);
}
@@ -1336,17 +1359,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public int getDefaultPrefetch()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchHigh()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchLow()
{
- return _defaultPrefetchLowMark;
+ return _prefetchLowMark;
}
public AMQShortString getDefaultQueueExchangeName()
@@ -1491,6 +1514,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
sendRecover();
+ markClean();
+
if (!isSuspended)
{
suspendChannel(false);
@@ -1559,6 +1584,14 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
suspendChannel(true);
}
+ // Let the dispatcher know that all the incomming messages
+ // should be rolled back(reject/release)
+ _rollbackMark.set(_highestDeliveryTag.get());
+
+ syncDispatchQueue();
+
+ _dispatcher.rollback();
+
releaseForRollback();
sendRollback();
@@ -1851,26 +1884,58 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
void failoverPrep()
{
- startDispatcherIfNecessary();
syncDispatchQueue();
}
void syncDispatchQueue()
{
- final CountDownLatch signal = new CountDownLatch(1);
- _queue.add(new Dispatchable() {
- public void dispatch(AMQSession ssn)
+ if (Thread.currentThread() == _dispatcherThread)
+ {
+ while (!_closed.get() && !_queue.isEmpty())
{
- signal.countDown();
+ Dispatchable disp;
+ try
+ {
+ disp = (Dispatchable) _queue.take();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ // Check just in case _queue becomes empty, it shouldn't but
+ // better than an NPE.
+ if (disp == null)
+ {
+ _logger.debug("_queue became empty during sync.");
+ break;
+ }
+
+ disp.dispatch(AMQSession.this);
}
- });
- try
- {
- signal.await();
}
- catch (InterruptedException e)
+ else
{
- throw new RuntimeException(e);
+ startDispatcherIfNecessary();
+
+ final CountDownLatch signal = new CountDownLatch(1);
+
+ _queue.add(new Dispatchable()
+ {
+ public void dispatch(AMQSession ssn)
+ {
+ signal.countDown();
+ }
+ });
+
+ try
+ {
+ signal.await();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
}
}
@@ -2233,7 +2298,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private P createProducerImpl(Destination destination, boolean mandatory, boolean immediate)
throws JMSException
{
- return createProducerImpl(destination, mandatory, immediate, false);
+ return createProducerImpl(destination, mandatory, immediate, DEFAULT_WAIT_ON_SEND);
}
private P createProducerImpl(final Destination destination, final boolean mandatory,
@@ -2704,15 +2769,26 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void setFlowControl(final boolean active)
{
_flowControl.setFlowControl(active);
+ _logger.warn("Broker enforced flow control " + (active ? "no longer in effect" : "has been enforced"));
}
- public void checkFlowControl() throws InterruptedException
+ public void checkFlowControl() throws InterruptedException, JMSException
{
+ long expiryTime = 0L;
synchronized (_flowControl)
{
- while (!_flowControl.getFlowControl())
+ while (!_flowControl.getFlowControl() &&
+ (expiryTime == 0L ? (expiryTime = System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE)
+ : expiryTime) >= System.currentTimeMillis() )
+ {
+
+ _flowControl.wait(FLOW_CONTROL_WAIT_PERIOD);
+ _logger.warn("Message send delayed by " + (System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE - expiryTime)/1000 + "s due to broker enforced flow control");
+ }
+ if(!_flowControl.getFlowControl())
{
- _flowControl.wait();
+ _logger.error("Message send failed due to timeout waiting on broker enforced flow control");
+ throw new JMSException("Unable to send message for " + FLOW_CONTROL_WAIT_FAILURE/1000 + " seconds due to broker enforced flow control");
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index 0644bd88a8..1587d6a6bf 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -414,9 +414,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public void releaseForRollback()
{
- startDispatcherIfNecessary();
- syncDispatchQueue();
- _dispatcher.rollback();
getQpidSession().messageRelease(_txRangeSet, Option.SET_REDELIVERED);
_txRangeSet.clear();
_txSize = 0;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index d7196c0abb..bc1453beaf 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -195,6 +195,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void releaseForRollback()
{
+ // Reject all the messages that have been received in this session and
+ // have not yet been acknowledged. Should look to remove
+ // _deliveredMessageTags and use _txRangeSet as used by 0-10.
+ // Otherwise messages will be able to arrive out of order to a second
+ // consumer on the queue. Whilst this is within the JMS spec it is not
+ // user friendly and avoidable.
while (true)
{
Long tag = _deliveredMessageTags.poll();
@@ -205,11 +211,6 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
rejectMessage(tag, true);
}
-
- if (_dispatcher != null)
- {
- _dispatcher.rollback();
- }
}
public void rejectMessage(long deliveryTag, boolean requeue)
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
index 2dfecc80ac..667785c441 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
@@ -779,6 +779,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
else
{
_session.addDeliveredMessage(msg.getDeliveryTag());
+ _session.markDirty();
}
break;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
index 5ff6066ddc..44ce59975a 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -60,7 +60,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
/**
* Priority of messages created by this producer.
*/
- private int _messagePriority;
+ private int _messagePriority = Message.DEFAULT_PRIORITY;
/**
* Time to live of messages. Specified in milliseconds but AMQ has 1 second resolution.
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java b/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
index 20fa68605a..43025bd724 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
@@ -47,7 +47,7 @@ public class XAConnectionImpl extends AMQConnection implements XAConnection, XAQ
public synchronized XASession createXASession() throws JMSException
{
checkNotClosed();
- return _delegate.createXASession(_maxPrefetch, _maxPrefetch / 2);
+ return _delegate.createXASession();
}
//-- Interface XAQueueConnection
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java b/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
index 3627618e68..be0d283470 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
@@ -39,7 +39,7 @@ public class ClientProperties
* type: long
*/
public static final String MAX_PREFETCH_PROP_NAME = "max_prefetch";
- public static final String MAX_PREFETCH_DEFAULT = "5000";
+ public static final String MAX_PREFETCH_DEFAULT = "500";
/**
* When true a sync command is sent after every persistent messages.
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
index 8223cd5394..7761215450 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
@@ -21,6 +21,7 @@
package org.apache.qpid.client.failover;
import org.apache.qpid.AMQDisconnectedException;
+import org.apache.qpid.AMQException;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.AMQStateManager;
@@ -134,6 +135,7 @@ public class FailoverHandler implements Runnable
// a slightly more complex state model therefore I felt it was worthwhile doing this.
AMQStateManager existingStateManager = _amqProtocolHandler.getStateManager();
+ // Use a fresh new StateManager for the reconnection attempts
_amqProtocolHandler.setStateManager(new AMQStateManager());
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
index 9c791730ca..0e3333940a 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
@@ -39,6 +39,7 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
private static final BasicReturnMethodHandler _basicReturnMethodHandler = BasicReturnMethodHandler.getInstance();
private static final ChannelCloseMethodHandler _channelCloseMethodHandler = ChannelCloseMethodHandler.getInstance();
private static final ChannelFlowOkMethodHandler _channelFlowOkMethodHandler = ChannelFlowOkMethodHandler.getInstance();
+ private static final ChannelFlowMethodHandler _channelFlowMethodHandler = ChannelFlowMethodHandler.getInstance();
private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance();
private static final ConnectionOpenOkMethodHandler _connectionOpenOkMethodHandler = ConnectionOpenOkMethodHandler.getInstance();
private static final ConnectionRedirectMethodHandler _connectionRedirectMethodHandler = ConnectionRedirectMethodHandler.getInstance();
@@ -159,7 +160,8 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
{
- return false;
+ _channelFlowMethodHandler.methodReceived(_session, body, channelId);
+ return true;
}
public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index 06a1fe2696..e645f4f214 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -308,7 +308,6 @@ public class AMQProtocolHandler implements ProtocolEngine
*/
public void exception(Throwable cause)
{
- _logger.info("AS: HELLO");
if (_failoverState == FailoverState.NOT_STARTED)
{
// if (!(cause instanceof AMQUndeliveredException) && (!(cause instanceof AMQAuthenticationException)))
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
index 67cda957fb..a3d015eadc 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
@@ -253,7 +253,7 @@ public abstract class BlockingWaiter<T>
}
else
{
- System.err.println("WARNING: new error arrived while old one not yet processed");
+ System.err.println("WARNING: new error '" + e == null ? "null" : e.getMessage() + "' arrived while old one not yet processed:" + _error.getMessage());
}
try
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
index e05a7ab6e2..960661daea 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
@@ -189,7 +189,8 @@ public class FailoverExchangeMethod implements FailoverMethod, MessageListener
{
synchronized (_brokerListLock)
{
- return _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ _currentBrokerDetail = _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ return _currentBrokerDetail;
}
}
@@ -214,7 +215,15 @@ public class FailoverExchangeMethod implements FailoverMethod, MessageListener
broker.getHost().equals(_currentBrokerDetail.getHost()) &&
broker.getPort() == _currentBrokerDetail.getPort())
{
- return getNextBrokerDetails();
+ if (_connectionDetails.getBrokerCount() > 1)
+ {
+ return getNextBrokerDetails();
+ }
+ else
+ {
+ _failedAttemps ++;
+ return null;
+ }
}
String delayStr = broker.getProperty(BrokerDetails.OPTIONS_CONNECT_DELAY);
diff --git a/qpid/java/common/bin/qpid-run b/qpid/java/common/bin/qpid-run
index 0b5070d937..63bb648fd8 100755
--- a/qpid/java/common/bin/qpid-run
+++ b/qpid/java/common/bin/qpid-run
@@ -111,6 +111,7 @@ if [ -n "$QPID_LOG_SUFFIX" ]; then
fi
log $INFO System Properties set to $SYSTEM_PROPS
+log $INFO QPID_OPTS set to $QPID_OPTS
program=$(basename $0)
sourced=${BASH_SOURCE[0]}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java b/qpid/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
index 3c1ea22595..7d8a5b7b36 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
@@ -51,7 +51,6 @@ public class ConsoleOutput implements Sender<ByteBuffer>
System.out.println("CLOSED");
}
- @Override
public void setIdleTimeout(long l)
{
// TODO Auto-generated method stub
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java
index 98dba9fed1..cb3387c6d3 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java
@@ -110,7 +110,7 @@ public interface LoggingManagement
* Reloads the log4j configuration file, applying any changes made.
*
* @throws IOException
- * @since Qpid JMX API 1.3
+ * @since Qpid JMX API 1.4
*/
@MBeanOperation(name = "reloadConfigFile", description = "Reload the log4j xml configuration file", impact = MBeanOperationInfo.ACTION)
void reloadConfigFile() throws IOException;
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
index c158c26857..5819631dba 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
@@ -43,7 +43,7 @@ public interface ServerInformation
* Qpid JMX API 1.1 can be assumed.
*/
int QPID_JMX_API_MAJOR_VERSION = 1;
- int QPID_JMX_API_MINOR_VERSION = 3;
+ int QPID_JMX_API_MINOR_VERSION = 4;
/**
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
index cd6f7ff808..9259d36d79 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
@@ -48,7 +48,7 @@ public abstract class ApplicationRegistry
//max supported broker management interface supported by this release of the management console
public static final int SUPPORTED_QPID_JMX_API_MAJOR_VERSION = 1;
- public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 3;
+ public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 4;
public static final String DATA_DIR = System.getProperty("user.home") + File.separator + ".qpidmc";
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java
index 1b1d08aa67..536033368f 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java
@@ -349,7 +349,7 @@ public class ConfigurationFileTabControl extends TabControl
_logWatchIntervalLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD));
_logWatchIntervalLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, true));
- if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ if(_ApiVersion.greaterThanOrEqualTo(1, 4))
{
Group reloadConfigFileGroup = new Group(attributesComposite, SWT.SHADOW_NONE);
reloadConfigFileGroup.setBackground(attributesComposite.getBackground());
diff --git a/qpid/java/module.xml b/qpid/java/module.xml
index 0c32414647..5796af928a 100644
--- a/qpid/java/module.xml
+++ b/qpid/java/module.xml
@@ -261,6 +261,7 @@
<jvmarg value="${jvm.args}"/>
<sysproperty key="amqj.logging.level" value="${amqj.logging.level}"/>
+ <sysproperty key="amqj.server.logging.level" value="${amqj.server.logging.level}"/>
<sysproperty key="amqj.protocol.logging.level" value="${amqj.protocol.logging.level}"/>
<sysproperty key="log4j.debug" value="${log4j.debug}"/>
<sysproperty key="root.logging.level" value="${root.logging.level}"/>
@@ -269,6 +270,7 @@
<sysproperty key="java.naming.provider.url" value="${java.naming.provider.url}"/>
<sysproperty key="broker" value="${broker}"/>
<sysproperty key="broker.clean" value="${broker.clean}"/>
+ <sysproperty key="broker.clean.between.tests" value="${broker.clean.between.tests}"/>
<sysproperty key="broker.version" value="${broker.version}"/>
<sysproperty key="broker.ready" value="${broker.ready}" />
<sysproperty key="broker.stopped" value="${broker.stopped}" />
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java
index 52120019f5..e7975f8d24 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java
@@ -78,15 +78,23 @@ public class BrokerStartupTest extends AbstractTestLogging
// Add an invalid value
_broker += " -l invalid";
- // The release-bin build of the broker uses this log4j configuration
- // so set up the broker environment to use it for this test.
- // Also include -Dlog4j.debug so we can validate that it picked up this config
- setBrokerEnvironment("QPID_OPTS", "-Dlog4j.debug -Dlog4j.configuration=file:" + System.getProperty(QPID_HOME) + "/../broker/src/main/java/log4j.properties");
+ // The broker has a built in default log4j configuration set up
+ // so if the the broker cannot load the -l value it will use default
+ // use this default. Test that this is correctly loaded, by
+ // including -Dlog4j.debug so we can validate.
+ setBrokerEnvironment("QPID_OPTS", "-Dlog4j.debug");
// Disable all client logging so we can test for broker DEBUG only.
- Logger.getRootLogger().setLevel(Level.WARN);
- Logger.getLogger("qpid.protocol").setLevel(Level.WARN);
- Logger.getLogger("org.apache.qpid").setLevel(Level.WARN);
+ setLoggerLevel(Logger.getRootLogger(), Level.WARN);
+ setLoggerLevel(Logger.getLogger("qpid.protocol"), Level.WARN);
+ setLoggerLevel(Logger.getLogger("org.apache.qpid"), Level.WARN);
+
+ // Set the broker to use info level logging, which is the qpid-server
+ // default. Rather than debug which is the test default.
+ setBrokerOnlySystemProperty("amqj.server.logging.level", "info");
+ // Set the logging defaults to info for this test.
+ setBrokerOnlySystemProperty("amqj.logging.level", "info");
+ setBrokerOnlySystemProperty("root.logging.level", "info");
startBroker();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
new file mode 100644
index 0000000000..f1a1c1a9a8
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
@@ -0,0 +1,330 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.failover;
+
+import org.apache.mina.common.WriteTimeoutException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+import org.apache.qpid.AMQConnectionClosedException;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test case based on user reported error.
+ *
+ * Summary:
+ * A user has reported message loss from their application. On bouncing of
+ * the broker the 'lost' messages are delivered to the broker.
+ *
+ * Note:
+ * The client was using Spring so that may influence the situation.
+ *
+ * Issue:
+ * The log files show 7 instances of the following which result in 7
+ * missing messages.
+ *
+ * The client log files show:
+ *
+ * The broker log file show:
+ *
+ *
+ * 7 missing messages have delivery tags 5-11. Which says that they are
+ * sequentially the next message from the broker.
+ *
+ * The only way for the 'without a handler' log to occur is if the consumer
+ * has been removed from the look up table of the dispatcher.
+ * And the only way for the 'null message' log to occur on the broker is is
+ * if the message does not exist in the unacked-map
+ *
+ * The consumer is only removed from the list during session
+ * closure and failover.
+ *
+ * If the session was closed then the broker would requeue the unacked
+ * messages so the potential exists to have an empty map but the broker
+ * will not send a message out after the unacked map has been cleared.
+ *
+ * When failover occurs the _consumer map is cleared and the consumers are
+ * resubscribed. This is down without first stopping any existing
+ * dispatcher so there exists the potential to receive a message after
+ * the _consumer map has been cleared which is how the 'without a handler'
+ * log statement occurs.
+ *
+ * Scenario:
+ *
+ * Looking over logs the sequence that best fits the events is as follows:
+ * - Something causes Mina to be delayed causing the WriteTimoutException.
+ * - This exception is recevied by AMQProtocolHandler#exceptionCaught
+ * - As the WriteTimeoutException is an IOException this will cause
+ * sessionClosed to be called to start failover.
+ * + This is potentially the issues here. All IOExceptions are treated
+ * as connection failure events.
+ * - Failover Runs
+ * + Failover assumes that the previous connection has been closed.
+ * + Failover binds the existing objects (AMQConnection/Session) to the
+ * new connection objects.
+ * - Everything is reported as being successfully failed over.
+ * However, what is neglected is that the original connection has not
+ * been closed.
+ * + So what occurs is that the broker sends a message to the consumer on
+ * the original connection, as it was not notified of the client
+ * failing over.
+ * As the client failover reuses the original AMQSession and Dispatcher
+ * the new messages the broker sends to the old consumer arrives at the
+ * client and is processed by the same AMQSession and Dispatcher.
+ * However, as the failover process cleared the _consumer map and
+ * resubscribe the consumers the Dispatcher does not recognise the
+ * delivery tag and so logs the 'without a handler' message.
+ * - The Dispatcher then attempts to reject the message, however,
+ * + The AMQSession/Dispatcher pair have been swapped to using a new Mina
+ * ProtocolSession as part of the failover process so the reject is
+ * sent down the second connection. The broker receives the Reject
+ * request but as the Message was sent on a different connection the
+ * unacknowledgemap is empty and a 'message is null' log message
+ * produced.
+ *
+ * Test Strategy:
+ *
+ * It should be easy to demonstrate if we can send an IOException to
+ * AMQProtocolHandler#exceptionCaught and then try sending a message.
+ *
+ * The current unknowns here are the type of consumers that are in use.
+ * If it was an exclusive queue(Durable Subscription) then why did the
+ * resubscribe not fail.
+ *
+ * If it was not exclusive then why did the messages not round robin?
+ */
+public class MessageDisappearWithIOExceptionTest extends FailoverBaseCase implements ConnectionListener
+{
+ private CountDownLatch _failoverOccured = new CountDownLatch(1);
+ AMQConnection _connection;
+ Session _session;
+ Queue _queue;
+ MessageConsumer _consumer;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ stopBroker(getFailingPort());
+
+ }
+
+ /**
+ * Test Summary:
+ *
+ * Create a queue consumer and send 10 messages to the broker.
+ *
+ * Consume the first message.
+ * This will pull the rest into the prefetch
+ *
+ * Send an IOException to the MinaProtocolHandler.
+ *
+ * This will force failover to occur.
+ *
+ * 9 messages would normally be expected but it is expected that none will
+ * arrive. As they are still in the prefetch of the first session.
+ *
+ * To free the messages we need to close all connections.
+ * - Simply doing connection.close() and retesting will not be enough as
+ * the original connection's IO layer will still exist and is nolonger
+ * connected to the connection object as a result of failover.
+ *
+ * - Test will need to retain a reference to the original connection IO so
+ * that it can be closed releasing the messages to validate that the
+ * messages have indeed been 'lost' on that sesssion.
+ */
+ public void test() throws Exception
+ {
+ initialiseConnection();
+
+ // Create Producer
+ // Send 10 messages
+ List<Message> messages = sendNumberedBytesMessage(_session, _queue, 10);
+
+ // Consume first messasge
+ Message received = _consumer.receive(2000);
+
+ // Verify received messages
+ assertNotNull("First message not received.", received);
+ assertEquals("Incorrect message Received",
+ messages.remove(0).getIntProperty("count"),
+ received.getIntProperty("count"));
+
+ // Allow ack to be sent to broker, by performing a synchronous command
+ // along the session.
+// _session.createConsumer(_session.createTemporaryQueue()).close();
+
+ //Retain IO Layer
+ AMQProtocolSession protocolSession = _connection.getProtocolHandler().getProtocolSession();
+
+ // Send IO Exception - causing failover
+ _connection.getProtocolHandler().
+ exception(new WriteTimeoutException("WriteTimeoutException to cause failover."));
+
+ // Verify Failover occured through ConnectionListener
+ assertTrue("Failover did not occur",
+ _failoverOccured.await(4000, TimeUnit.MILLISECONDS));
+
+ //Verify new protocolSession is not the same as the original
+ assertNotSame("Protocol Session has not changed",
+ protocolSession,
+ _connection.getProtocolHandler().getProtocolSession());
+
+ /***********************************/
+ // This verifies that the bug has been resolved
+
+ // Attempt to consume again. Expect 9 messages
+ for (int count = 1; count < 10; count++)
+ {
+ received = _consumer.receive(2000);
+ assertNotNull("Expected message not received:" + count, received);
+ assertEquals(messages.remove(0).getIntProperty("count"),
+ received.getIntProperty("count"));
+ }
+
+ //Verify there are no more messages
+ received = _consumer.receive(1000);
+ assertNull("Message receieved when there should be none:" + received,
+ received);
+
+// /***********************************/
+// // This verifies that the bug exists
+//
+// // Attempt to consume remaining 9 messages.. Expecting NONE.
+// // receiving just one message should fail so no need to fail 9 times
+// received = _consumer.receive(1000);
+// assertNull("Message receieved when it should be null:" + received, received);
+//
+//// //Close the Connection which you would assume would free the messages
+//// _connection.close();
+////
+//// // Reconnect
+//// initialiseConnection();
+////
+//// // We should still be unable to receive messages
+//// received = _consumer.receive(1000);
+//// assertNull("Message receieved when it should be null:" + received, received);
+////
+//// _connection.close();
+//
+// // Close original IO layer. Expecting messages to be released
+// protocolSession.closeProtocolSession();
+//
+// // Reconnect and all should be good.
+//// initialiseConnection();
+//
+// // Attempt to consume again. Expect 9 messages
+// for (int count = 1; count < 10; count++)
+// {
+// received = _consumer.receive(2000);
+// assertNotNull("Expected message not received:" + count, received);
+// assertEquals(messages.remove(0).getIntProperty("count"),
+// received.getIntProperty("count"));
+// }
+//
+// //Verify there are no more messages
+// received = _consumer.receive(1000);
+// assertNull("Message receieved when there should be none:" + received,
+// received);
+ }
+
+ private void initialiseConnection()
+ throws Exception
+ {
+ //Create Connection
+ _connection = (AMQConnection) getConnection();
+ _connection.setConnectionListener(this);
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = _session.createQueue(getTestQueueName());
+
+ // Create Consumer
+ _consumer = _session.createConsumer(_queue);
+
+ //Start connection
+ _connection.start();
+ }
+
+ /** QpidTestCase back port to this release */
+
+ // modified from QTC as sendMessage is not testable.
+ // - should be renamed sendBlankBytesMessage
+ // - should be renamed sendNumberedBytesMessage
+ public List<Message> sendNumberedBytesMessage(Session session, Destination destination,
+ int count) throws Exception
+ {
+ List<Message> messages = new ArrayList<Message>(count);
+
+ MessageProducer producer = session.createProducer(destination);
+
+ for (int i = 0; i < count; i++)
+ {
+ Message next = session.createMessage();
+
+ next.setIntProperty("count", i);
+
+ producer.send(next);
+
+ messages.add(next);
+ }
+
+ producer.close();
+ return messages;
+ }
+
+ public void bytesSent(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover to occur
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover to occur
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverOccured.countDown();
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java
index 4f50aba61d..b00a71315e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java
@@ -160,7 +160,7 @@ public class BrokerLoggingTest extends AbstractTestLogging
// Set the broker.ready string to check for the _log4j default that
// is still present on standard out.
- System.setProperty(BROKER_READY, "Qpid Broker Ready");
+ setTestClientSystemProperty(BROKER_READY, "Qpid Broker Ready");
startBroker();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java
index dfb5cde247..83f0f87bc5 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java
@@ -63,7 +63,6 @@ import java.util.concurrent.TimeUnit;
*/
public class DeepQueueConsumeWithSelector extends QpidTestCase implements MessageListener
{
- private static final String INDEX = "index";
private static final int MESSAGE_COUNT = 10000;
private static final int BATCH_SIZE = MESSAGE_COUNT / 10;
@@ -129,9 +128,7 @@ public class DeepQueueConsumeWithSelector extends QpidTestCase implements Messag
@Override
public Message createNextMessage(Session session, int msgCount) throws JMSException
{
- Message message = session.createTextMessage("Message :" + msgCount);
-
- message.setIntProperty(INDEX, msgCount);
+ Message message = super.createNextMessage(session,msgCount);
if ((msgCount % BATCH_SIZE) == 0 )
{
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
new file mode 100644
index 0000000000..f220760511
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
@@ -0,0 +1,393 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.*;
+import javax.naming.NamingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.io.IOException;
+
+public class ProducerFlowControlTest extends AbstractTestLogging
+{
+ private static final int TIMEOUT = 1500;
+
+
+ private static final Logger _logger = Logger.getLogger(ProducerFlowControlTest.class);
+
+ protected final String QUEUE = "ProducerFlowControl";
+
+ private static final int MSG_COUNT = 50;
+
+ private Connection producerConnection;
+ private MessageProducer producer;
+ private Session producerSession;
+ private Queue queue;
+ private Connection consumerConnection;
+ private Session consumerSession;
+
+
+ private MessageConsumer consumer;
+ private final AtomicInteger _sentMessages = new AtomicInteger();
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _monitor.reset();
+
+ producerConnection = getConnection();
+ producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ producerConnection.start();
+
+ consumerConnection = getConnection();
+ consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ }
+
+ public void tearDown() throws Exception
+ {
+ producerConnection.close();
+ consumerConnection.close();
+ super.tearDown();
+ }
+
+ public void testCapacityExceededCausesBlock()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+
+ assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message incorrectly sent after one message received", 4, _sentMessages.get());
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message not sent after two messages received", 5, _sentMessages.get());
+
+ }
+
+ public void testBrokerLogMessages()
+ throws JMSException, NamingException, AMQException, InterruptedException, IOException
+ {
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+ List<String> results = _monitor.findMatches("QUE-1003");
+
+ assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ while(consumer.receive(1000) != null);
+
+ results = _monitor.findMatches("QUE-1004");
+
+ assertEquals("Did not find correct number of QUE_1004 queue underfull messages", 1, results.size());
+
+
+
+ }
+
+
+ public void testClientLogMessages()
+ throws JMSException, NamingException, AMQException, InterruptedException, IOException
+ {
+ setTestClientSystemProperty("qpid.flow_control_wait_failure","3000");
+ setTestClientSystemProperty("qpid.flow_control_wait_notify_period","1000");
+
+ Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) session).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) session).declareAndBind((AMQDestination)queue);
+ producer = session.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(10000);
+ List<String> results = _monitor.findMatches("Message send delayed by");
+ assertEquals("Incorrect number of delay messages logged by client",3,results.size());
+ results = _monitor.findMatches("Message send failed due to timeout waiting on broker enforced flow control");
+ assertEquals("Incorrect number of send failure messages logged by client",1,results.size());
+
+
+
+ }
+
+
+ public void testFlowControlOnCapacityResumeEqual()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",1000);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+
+ assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message incorrectly sent after one message received", 5, _sentMessages.get());
+
+
+ }
+
+
+ public void testFlowControlSoak()
+ throws Exception, NamingException, AMQException, InterruptedException
+ {
+ _sentMessages.set(0);
+ final int numProducers = 10;
+ final int numMessages = 100;
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",6000);
+ arguments.put("x-qpid-flow-resume-capacity",3000);
+
+ ((AMQSession) consumerSession).createQueue(new AMQShortString(QUEUE), false, false, false, arguments);
+
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) consumerSession).declareAndBind((AMQDestination)queue);
+ consumerConnection.start();
+
+ Connection[] producers = new Connection[numProducers];
+ for(int i = 0 ; i < numProducers; i ++)
+ {
+
+ producers[i] = getConnection();
+ producers[i].start();
+ Session session = producers[i].createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer myproducer = session.createProducer(queue);
+ MessageSender sender = sendMessagesAsync(myproducer, session, numMessages, 50L);
+ }
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+ for(int j = 0; j < numProducers * numMessages; j++)
+ {
+
+ Message msg = consumer.receive(5000);
+ Thread.sleep(50L);
+ assertNotNull("Message not received("+j+"), sent: "+_sentMessages.get(), msg);
+
+ }
+
+
+
+ Message msg = consumer.receive(500);
+ assertNull("extra message received", msg);
+
+
+ for(int i = 0; i < numProducers; i++)
+ {
+ producers[i].close();
+ }
+
+ }
+
+
+
+ public void testSendTimeout()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ setTestClientSystemProperty("qpid.flow_control_wait_failure","3000");
+ Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) session).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = new AMQQueue("amq.direct",QUEUE);
+ ((AMQSession) session).declareAndBind((AMQDestination)queue);
+ producer = session.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(10000);
+
+ Exception e = sender.getException();
+
+ assertNotNull("No timeout exception on sending", e);
+
+ }
+
+ private MessageSender sendMessagesAsync(final MessageProducer producer,
+ final Session producerSession,
+ final int numMessages,
+ long sleepPeriod)
+ {
+ MessageSender sender = new MessageSender(producer, producerSession, numMessages,sleepPeriod);
+ new Thread(sender).start();
+ return sender;
+ }
+
+ private void sendMessages(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod)
+ throws JMSException
+ {
+
+ for (int msg = 0; msg < numMessages; msg++)
+ {
+ producer.send(nextMessage(msg, producerSession));
+ _sentMessages.incrementAndGet();
+
+ try
+ {
+ Thread.sleep(sleepPeriod);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+
+ private static final byte[] BYTE_300 = new byte[300];
+
+
+ private Message nextMessage(int msg, Session producerSession) throws JMSException
+ {
+ BytesMessage send = producerSession.createBytesMessage();
+ send.writeBytes(BYTE_300);
+ send.setIntProperty("msg", msg);
+
+ return send;
+ }
+
+
+ private class MessageSender implements Runnable
+ {
+ private final MessageProducer _producer;
+ private final Session _producerSession;
+ private final int _numMessages;
+
+
+
+ private JMSException _exception;
+ private long _sleepPeriod;
+
+ public MessageSender(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod)
+ {
+ _producer = producer;
+ _producerSession = producerSession;
+ _numMessages = numMessages;
+ _sleepPeriod = sleepPeriod;
+ }
+
+ public void run()
+ {
+ try
+ {
+ sendMessages(_producer, _producerSession, _numMessages, _sleepPeriod);
+ }
+ catch (JMSException e)
+ {
+ _exception = e;
+ }
+ }
+
+ public JMSException getException()
+ {
+ return _exception;
+ }
+ }
+} \ No newline at end of file
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
index bb7b5efc75..3e5470d5cb 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
@@ -21,27 +21,34 @@
package org.apache.qpid.server.security.acl;
-
-import junit.framework.TestCase;
-
-import org.apache.log4j.BasicConfigurator;
-import org.apache.log4j.Logger;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.client.*;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
-import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.AMQException;
-import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+
-import javax.jms.*;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.ExceptionListener;
import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
import javax.naming.NamingException;
-
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -54,6 +61,14 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void setUp() throws Exception
{
+ //Performing setUp here would result in a broker with the default ACL test config
+
+ //Each test now calls the private setUpACLTest to allow them to make
+ //individual customisations to the base ACL settings
+ }
+
+ private void setUpACLTest() throws Exception
+ {
final String QPID_HOME = System.getProperty("QPID_HOME");
if (QPID_HOME == null)
@@ -73,8 +88,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + getBroker() + "?retries='0''";
}
- public void testAccessAuthorized() throws AMQException, URLSyntaxException
+ public void testAccessAuthorized() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -96,6 +113,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testAccessNoRights() throws Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("guest", "guest");
@@ -120,8 +139,40 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
}
}
- public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException
+ public void testGuestConsumeWithCreateRightsAndWithoutConsumeRights() throws NamingException, ConfigurationException, IOException, Exception
+ {
+ //Customise the ACL config to give the guest user some create (could be any, non-consume) rights to
+ //force creation of a PrincipalPermissions instance to perform the consume rights check against.
+ setConfigurationProperty("virtualhosts.virtualhost.test.security.access_control_list.create.queues.queue.users.user", "guest");
+
+ setUpACLTest();
+
+ try
+ {
+ Connection conn = getConnection("guest", "guest");
+
+ Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ conn.start();
+
+ sesh.createConsumer(sesh.createQueue("example.RequestQueue"));
+
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ Throwable cause = e.getLinkedException();
+
+ assertNotNull("There was no liked exception", cause);
+ assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
+ assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+ }
+ }
+
+ public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -142,6 +193,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testClientConsumeFromNamedQueueInvalid() throws NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -167,8 +220,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
}
}
- public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException
+ public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -191,6 +246,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testClientCreateNamedQueue() throws NamingException, JMSException, AMQException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -212,8 +269,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
}
}
- public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException
+ public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -239,8 +298,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
}
}
- public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException
+ public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -271,6 +332,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -311,8 +374,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
assertTrue("Did not get AMQAuthenticationException thrown", foundCorrectException);
}
- public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
@@ -333,6 +398,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("client", "guest");
@@ -358,6 +425,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
@@ -391,8 +460,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
return (Connection) connection;
}
- public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException
+ public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
@@ -414,6 +485,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
@@ -436,6 +509,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerCreateTemporaryQueueInvalid() throws NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
@@ -461,6 +536,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException, Exception
{
+ setUpACLTest();
+
Connection connection = null;
try
{
@@ -492,6 +569,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
*/
public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
//Set up the Server
Connection serverConnection = getConnection("server", "guest");
@@ -572,6 +651,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener, E
public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
try
{
Connection conn = getConnection("server", "guest");
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
index 62b54d3086..f9cf48a2b1 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
@@ -61,7 +61,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
setupSession();
- _queue = _clientSession.createQueue(getName()+System.currentTimeMillis());
+ _queue = _clientSession.createQueue(getTestQueueName());
_clientSession.createConsumer(_queue).close();
//Ensure there are no messages on the queue to start with.
@@ -497,7 +497,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
if (msgCount == failPoint)
{
- failBroker();
+ failBroker(getFailingPort());
}
}
@@ -529,7 +529,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
sendMessages("connection2", messages);
}
- failBroker();
+ failBroker(getFailingPort());
checkQueueDepth(messages);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java
index 39e2b892a9..ff766c907d 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java
@@ -22,64 +22,172 @@ package org.apache.qpid.test.client;
import org.apache.qpid.test.utils.*;
import javax.jms.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import junit.framework.ComparisonFailure;
+import junit.framework.AssertionFailedError;
/**
- * RollbackOrderTest
+ * RollbackOrderTest, QPID-1864, QPID-1871
+ *
+ * Description:
+ *
+ * The problem that this test is exposing is that the dispatcher used to be capable
+ * of holding on to a message when stopped. This ment that when the rollback was
+ * called and the dispatcher stopped it may have hold of a message. So after all
+ * the local queues(preDeliveryQueue, SynchronousQueue, PostDeliveryTagQueue)
+ * have been cleared the client still had a single message, the one the
+ * dispatcher was holding on to.
+ *
+ * As a result the TxRollback operation would run and then release the dispatcher.
+ * Whilst the dispatcher would then proceed to reject the message it was holiding
+ * the Broker would already have resent that message so the rejection would silently
+ * fail.
+ *
+ * And the client would receieve that single message 'early', depending on the
+ * number of messages already recevied when rollback was called.
+ *
+ *
+ * Aims:
+ *
+ * The tests puts 50 messages on to the queue.
+ *
+ * The test then tries to cause the dispatcher to stop whilst it is in the process
+ * of moving a message from the preDeliveryQueue to a consumers sychronousQueue.
+ *
+ * To exercise this path we have 50 message flowing to the client to give the
+ * dispatcher a bit of work to do moving messages.
+ *
+ * Then we loop - 10 times
+ * - Validating that the first message received is always message 1.
+ * - Receive a few more so that there are a few messages to reject.
+ * - call rollback, to try and catch the dispatcher mid process.
+ *
+ * Outcome:
+ *
+ * The hope is that we catch the dispatcher mid process and cause a BasicReject
+ * to fail. Which will be indicated in the log but will also cause that failed
+ * rejected message to be the next to be delivered which will not be message 1
+ * as expected.
+ *
+ * We are testing a race condition here but we can check through the log file if
+ * the race condition occured. However, performing that check will only validate
+ * the problem exists and will not be suitable as part of a system test.
*
*/
-
public class RollbackOrderTest extends QpidTestCase
{
- private Connection conn;
- private Queue queue;
- private Session ssn;
- private MessageProducer prod;
- private MessageConsumer cons;
+ private Connection _connection;
+ private Queue _queue;
+ private Session _session;
+ private MessageConsumer _consumer;
@Override public void setUp() throws Exception
{
super.setUp();
- conn = getConnection();
- conn.start();
- ssn = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
- queue = ssn.createQueue("rollback-order-test-queue");
- prod = ssn.createProducer(queue);
- cons = ssn.createConsumer(queue);
- for (int i = 0; i < 5; i++)
- {
- TextMessage msg = ssn.createTextMessage("message " + (i+1));
- prod.send(msg);
- }
- ssn.commit();
+ _connection = getConnection();
+
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _queue = _session.createQueue(getTestQueueName());
+ _consumer = _session.createConsumer(_queue);
+
+ //Send more messages so it is more likely that the dispatcher is
+ // processing on rollback.
+ sendMessage(_session, _queue, 50);
+ _session.commit();
+
}
public void testOrderingAfterRollback() throws Exception
{
- for (int i = 0; i < 10; i++)
+ //Start the session now so we
+ _connection.start();
+
+ for (int i = 0; i < 20; i++)
{
- TextMessage msg = (TextMessage) cons.receive();
- assertEquals("message 1", msg.getText());
- ssn.rollback();
+ Message msg = _consumer.receive();
+ assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX));
+
+ // Pull additional messages through so we have some reject work to do
+ for (int m=0; m < 5 ; m++)
+ {
+ _consumer.receive();
+ }
+
+ System.err.println("ROT-Rollback");
+ _logger.warn("ROT-Rollback");
+ _session.rollback();
}
}
- @Override public void tearDown() throws Exception
+ public void testOrderingAfterRollbackOnMessage() throws Exception
{
- while (true)
+ final CountDownLatch count= new CountDownLatch(20);
+ final Exception exceptions[] = new Exception[20];
+ final AtomicBoolean failed = new AtomicBoolean(false);
+
+ _consumer.setMessageListener(new MessageListener()
{
- Message msg = cons.receiveNoWait();
- if (msg == null)
+
+ public void onMessage(Message message)
{
- break;
+
+ Message msg = message;
+ try
+ {
+ count.countDown();
+ assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX));
+
+ _session.rollback();
+ }
+ catch (JMSException e)
+ {
+ System.out.println("Error:" + e.getMessage());
+ exceptions[(int)count.getCount()] = e;
+ }
+ catch (AssertionFailedError cf)
+ {
+ // End Test if Equality test fails
+ while (count.getCount() != 0)
+ {
+ count.countDown();
+ }
+
+ System.out.println("Error:" + cf.getMessage());
+ System.err.println(cf.getMessage());
+ cf.printStackTrace();
+ failed.set(true);
+ }
}
- else
+ });
+ //Start the session now so we
+ _connection.start();
+
+ count.await();
+
+ for (Exception e : exceptions)
+ {
+ if (e != null)
{
- msg.acknowledge();
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ failed.set(true);
}
}
- ssn.commit();
+
+// _consumer.close();
+ _connection.close();
+
+ assertFalse("Exceptions thrown during test run, Check Std.err.", failed.get());
+ }
+
+ @Override public void tearDown() throws Exception
+ {
+
+ drainQueue(_queue);
+
super.tearDown();
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
index dfc3bb7b42..c307176f3f 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
@@ -37,7 +37,6 @@ import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQSession_0_10;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ConnectionListener;
import org.apache.qpid.jms.ConnectionURL;
@@ -58,13 +57,12 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
private Session consumerSession;
private MessageConsumer consumer;
- private static int usedBrokers = 0;
private CountDownLatch failoverComplete;
- private static final long DEFAULT_FAILOVER_TIME = 10000L;
private boolean CLUSTERED = Boolean.getBoolean("profile.clustered");
private int seed;
private Random rand;
-
+ private int _currentPort = getFailingPort();
+
@Override
protected void setUp() throws Exception
{
@@ -227,7 +225,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
_logger.info("Failing over");
- causeFailure(DEFAULT_FAILOVER_TIME);
+ causeFailure(_currentPort, DEFAULT_FAILOVER_TIME);
// Check that you produce and consume the rest of messages.
_logger.debug("==================");
@@ -242,10 +240,10 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
_logger.debug("==================");
}
- private void causeFailure(long delay)
+ private void causeFailure(int port, long delay)
{
- failBroker();
+ failBroker(port);
_logger.info("Awaiting Failover completion");
try
@@ -268,7 +266,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
Message msg = consumer.receive();
assertNotNull("Expected msgs not received", msg);
- causeFailure(DEFAULT_FAILOVER_TIME);
+ causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME);
Exception failure = null;
try
@@ -314,7 +312,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
long failTime = System.nanoTime() + FAILOVER_DELAY * 1000000;
//Fail the first broker
- causeFailure(FAILOVER_DELAY + DEFAULT_FAILOVER_TIME);
+ causeFailure(getFailingPort(), FAILOVER_DELAY + DEFAULT_FAILOVER_TIME);
//Reconnection should occur
assertTrue("Failover did not take long enough", System.nanoTime() > failTime);
@@ -344,15 +342,15 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
_logger.debug("===================================================================");
runP2PFailover(numMessages, false,false, false);
- startBroker(getFailingPort());
+ startBroker(_currentPort);
if (useAltPort)
{
- setFailingPort(altPort);
+ _currentPort = altPort;
useAltPort = false;
}
else
{
- setFailingPort(stdPort);
+ _currentPort = stdPort;
useAltPort = true;
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
index 5a5e23baa5..a09589b121 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
@@ -1,31 +1,248 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.test.client.message;
-import javax.jms.Connection;
-import javax.jms.Destination;
+import java.util.concurrent.CountDownLatch;
+
+import javax.jms.DeliveryMode;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import junit.framework.Assert;
-import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.BasicMessageProducer;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-public class SelectorTest extends QpidTestCase
+public class SelectorTest extends QpidTestCase implements MessageListener
{
- private static final Logger _logger = Logger.getLogger(SelectorTest.class);
+ private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
- public void testSelectorWithJMSMessageID() throws Exception
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private int count;
+ public String _connectionString = "vm://:1";
+ private static final String INVALID_SELECTOR = "Cost LIKE 5";
+ CountDownLatch _responseLatch = new CountDownLatch(1);
+
+ private static final String BAD_MATHS_SELECTOR = " 1 % 5";
+
+ private static final long RECIEVE_TIMEOUT = 1000;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ init((AMQConnection) getConnection("guest", "guest"));
+ }
+
+ private void init(AMQConnection connection) throws JMSException
+ {
+ init(connection, new AMQQueue(connection, getTestQueueName(), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws JMSException
+ {
+ _connection = connection;
+ _destination = destination;
+ connection.start();
+ }
+
+ public void onMessage(Message message)
+ {
+ count++;
+ _logger.info("Got Message:" + message);
+ _responseLatch.countDown();
+ }
+
+ public void testUsingOnMessage() throws Exception
+ {
+ String selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
+ // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
+
+ Session session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ // _session.createConsumer(destination).setMessageListener(this);
+ session.createConsumer(_destination, selector).setMessageListener(this);
+
+ try
+ {
+ Message msg = session.createTextMessage("Message");
+ msg.setJMSPriority(1);
+ msg.setIntProperty("Cost", 2);
+ msg.setStringProperty("property-with-hyphen", "wibble");
+ msg.setJMSType("Special");
+
+ _logger.info("Sending Message:" + msg);
+
+ ((BasicMessageProducer) session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
+ _logger.info("Message sent, waiting for response...");
+
+ _responseLatch.await();
+
+ if (count > 0)
+ {
+ _logger.info("Got message");
+ }
+
+ if (count == 0)
+ {
+ fail("Did not get message!");
+ // throw new RuntimeException("Did not get message!");
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ else
+ {
+ System.out.println("SUCCESS!!");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ }
+
+ }
+
+ public void testUnparsableSelectors() throws Exception
{
- Connection conn = getConnection();
- conn.start();
- Session session = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
+ AMQSession session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ boolean caught = false;
- Destination dest = session.createQueue("SelectorQueue");
+ //Try Creating a Browser
+ try
+ {
+ session.createBrowser(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Consumer
+ try
+ {
+ session.createConsumer(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Receiever
+ try
+ {
+ session.createReceiver(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ try
+ {
+ session.createReceiver(session.createQueue("Ping"), BAD_MATHS_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
- MessageProducer prod = session.createProducer(dest);
- MessageConsumer consumer = session.createConsumer(dest,"JMSMessageID IS NOT NULL");
+ }
+
+ public void testRuntimeSelectorError() throws JMSException
+ {
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(_destination , "testproperty % 5 = 1");
+ MessageProducer producer = session.createProducer(_destination);
+ Message sentMsg = session.createTextMessage();
+
+ sentMsg.setIntProperty("testproperty", 1); // 1 % 5
+ producer.send(sentMsg);
+ Message recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNotNull(recvd);
+
+ sentMsg.setStringProperty("testproperty", "hello"); // "hello" % 5 makes no sense
+ producer.send(sentMsg);
+ try
+ {
+ recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNull(recvd);
+ }
+ catch (Exception e)
+ {
+
+ }
+ assertTrue("Connection should be closed", _connection.isClosed());
+ }
+
+ public void testSelectorWithJMSMessageID() throws Exception
+ {
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ MessageProducer prod = session.createProducer(_destination);
+ MessageConsumer consumer = session.createConsumer(_destination,"JMSMessageID IS NOT NULL");
for (int i=0; i<2; i++)
{
@@ -54,7 +271,7 @@ public class SelectorTest extends QpidTestCase
Message msg3 = consumer.receive(1000);
Assert.assertNull("Msg3 should be null", msg3);
session.commit();
- consumer = session.createConsumer(dest,"JMSMessageID IS NULL");
+ consumer = session.createConsumer(_destination,"JMSMessageID IS NULL");
Message msg4 = consumer.receive(1000);
Message msg5 = consumer.receive(1000);
@@ -62,4 +279,32 @@ public class SelectorTest extends QpidTestCase
Assert.assertNotNull("Msg4 should not be null", msg4);
Assert.assertNotNull("Msg5 should not be null", msg5);
}
+
+ public static void main(String[] argv) throws Exception
+ {
+ SelectorTest test = new SelectorTest();
+ test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
+
+ try
+ {
+ while (true)
+ {
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.setUp();
+ }
+ test.testUsingOnMessage();
+
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.tearDown();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java
new file mode 100644
index 0000000000..4b45a96c20
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java
@@ -0,0 +1,193 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+public class Acknowledge2ConsumersTest extends FailoverBaseCase
+{
+ protected static int NUM_MESSAGES = 100;
+ protected Connection _con;
+ protected Queue _queue;
+ private Session _producerSession;
+ private Session _consumerSession;
+ private MessageConsumer _consumerA;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _queue = (Queue) getInitialContext().lookup("queue");
+
+ //Create Producer put some messages on the queue
+ _con = getConnection();
+ }
+
+ private void init(boolean transacted, int mode) throws JMSException
+ {
+ _producerSession = _con.createSession(true, Session.SESSION_TRANSACTED);
+ _consumerSession = _con.createSession(transacted, mode);
+ _consumerA = _consumerSession.createConsumer(_queue);
+ _con.start();
+ }
+
+ /**
+ * Produces Messages that
+ *
+ * @param transacted
+ * @param mode
+ *
+ * @throws Exception
+ */
+ private void test2ConsumersAcking(boolean transacted, int mode) throws Exception
+ {
+ init(transacted, mode);
+
+ // These should all end up being prefetched by sessionA
+ sendMessage(_producerSession, _queue, NUM_MESSAGES / 2);
+
+ //Create a second consumer (consumerB) to consume some of the messages
+ MessageConsumer consumerB = _consumerSession.createConsumer(_queue);
+
+ // These messages should be roundrobined between A and B
+ sendMessage(_producerSession, _queue, NUM_MESSAGES / 2);
+
+ int count = 0;
+ //Use consumerB to receive messages it has
+ Message msg = consumerB.receive(1500);
+ while (msg != null)
+ {
+ if (mode == Session.CLIENT_ACKNOWLEDGE)
+ {
+ msg.acknowledge();
+ }
+ count++;
+ msg = consumerB.receive(1500);
+ }
+ if (transacted)
+ {
+ _consumerSession.commit();
+ }
+
+ // Close the consumers
+ _consumerA.close();
+ consumerB.close();
+
+ // and close the session to release any prefetched messages.
+ _consumerSession.close();
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count,
+ ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
+
+ // Clean up messages that may be left on the queue
+ _consumerSession = _con.createSession(transacted, mode);
+ _consumerA = _consumerSession.createConsumer(_queue);
+ msg = _consumerA.receive(1500);
+ while (msg != null)
+ {
+ if (mode == Session.CLIENT_ACKNOWLEDGE)
+ {
+ msg.acknowledge();
+ }
+ msg = _consumerA.receive(1500);
+ }
+ _consumerA.close();
+ if (transacted)
+ {
+ _consumerSession.commit();
+ }
+ _consumerSession.close();
+ }
+
+ public void test2ConsumersAutoAck() throws Exception
+ {
+ test2ConsumersAcking(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ public void test2ConsumersClientAck() throws Exception
+ {
+ test2ConsumersAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void test2ConsumersTx() throws Exception
+ {
+ test2ConsumersAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+
+
+//
+// /**
+// * Check that session level acknowledge does correctly ack all previous
+// * values. Send 3 messages(0,1,2) then ack 1 and 2. If session ack is
+// * working correctly then acking 1 will also ack 0. Acking 2 will not
+// * attempt to re-ack 0 and 1.
+// *
+// * @throws Exception
+// */
+// public void testSessionAck() throws Exception
+// {
+// init(false, Session.CLIENT_ACKNOWLEDGE);
+//
+// sendMessage(_producerSession, _queue, 3);
+// Message msg;
+//
+// // Drop msg 0
+// _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// // Take msg 1
+// msg = _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// assertNotNull("Message 1 not correctly received.", msg);
+// assertEquals("Incorrect message received", 1, msg.getIntProperty(INDEX));
+//
+// // This should also ack msg 0
+// msg.acknowledge();
+//
+// // Take msg 2
+// msg = _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// assertNotNull("Message 2 not correctly received.", msg);
+// assertEquals("Incorrect message received", 2, msg.getIntProperty(INDEX));
+//
+// // This should just ack msg 2
+// msg.acknowledge();
+//
+// _consumerA.close();
+// _consumerSession.close();
+//
+// assertEquals("Queue not empty.", 0,
+// ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
+// _con.close();
+//
+//
+// }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
new file mode 100644
index 0000000000..f22a405fc3
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
@@ -0,0 +1,356 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class AcknowledgeAfterFailoverOnMessageTest extends AcknowledgeOnMessageTest implements ConnectionListener
+{
+
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+ private MessageListener _listener = null;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ NUM_MESSAGES = 10;
+ }
+
+ /**
+ * Override default init to add connectionListener so we can verify that
+ * failover took place
+ *
+ * @param transacted create a transacted session for this test
+ * @param mode if not transacted what ack mode to use for this test
+ *
+ * @throws Exception if a problem occured during test setup.
+ */
+ @Override
+ public void init(boolean transacted, int mode) throws Exception
+ {
+ super.init(transacted, mode);
+ ((AMQConnection) _connection).setConnectionListener(this);
+ // Override the listener for the dirtyAck testing.
+ if (_listener != null)
+ {
+ _consumer.setMessageListener(_listener);
+ }
+ }
+
+ protected void prepBroker(int count) throws Exception
+ {
+ //Stop the connection whilst we repopulate the broker, or the no_ack
+ // test will drain the msgs before we can check we put the right number
+ // back on again.
+// _connection.stop();
+
+ Connection connection = getConnection();
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, count, NUM_MESSAGES - count, 0);
+
+ if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
+ {
+ assertEquals("Wrong number of messages on queue", count,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+ }
+
+ connection.close();
+
+// _connection.start();
+ }
+
+ @Override
+ public void doAcknowlegement(Message msg) throws JMSException
+ {
+ //Acknowledge current message
+ super.doAcknowlegement(msg);
+
+ int msgCount = msg.getIntProperty(INDEX);
+
+ if (msgCount % 2 == 0)
+ {
+ failBroker(getFailingPort());
+ }
+ else
+ {
+ failBroker(getPort());
+ }
+
+ try
+ {
+ prepBroker(NUM_MESSAGES - msgCount - 1);
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ try
+ {
+
+ if (msgCount % 2 == 0)
+ {
+ startBroker(getFailingPort());
+ }
+ else
+ {
+ startBroker(getPort());
+ }
+ }
+ catch (Exception e)
+ {
+ fail("Unable to start failover broker," + e.getMessage());
+ }
+
+ }
+
+ int msgCount = 0;
+ boolean cleaned = false;
+
+ class DirtyAckingHandler implements MessageListener
+ {
+ /**
+ * Validate first message but do nothing with it.
+ *
+ * Failover
+ *
+ * The receive the message again
+ *
+ * @param message
+ */
+ public void onMessage(Message message)
+ {
+ // Stop processing if we have an error and had to stop running.
+ if (_receviedAll.getCount() == 0)
+ {
+ _logger.debug("Dumping msgs due to error(" + _causeOfFailure.get().getMessage() + "):" + message);
+ return;
+ }
+
+ try
+ {
+ // Check we have the next message as expected
+ assertNotNull("Message " + msgCount + " not correctly received.", message);
+ assertEquals("Incorrect message received", msgCount, message.getIntProperty(INDEX));
+
+ if (msgCount == 0 && _failoverCompleted.getCount() != 0)
+ {
+ // This is the first message we've received so lets fail the broker
+
+ failBroker(getFailingPort());
+
+ repopulateBroker();
+
+ _logger.error("Received first msg so failing over");
+
+ return;
+ }
+
+ msgCount++;
+
+ // Don't acknowlege the first message after failover so we can commit
+ // them together
+ if (msgCount == 1)
+ {
+ _logger.error("Received first msg after failover ignoring:" + msgCount);
+
+ // Acknowledge the first message if we are now on the cleaned pass
+ if (cleaned)
+ {
+ _receviedAll.countDown();
+ }
+
+ return;
+ }
+
+ if (_consumerSession.getTransacted())
+ {
+ try
+ {
+ _consumerSession.commit();
+ if (!cleaned)
+ {
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ //expected path
+ }
+ }
+ else
+ {
+ try
+ {
+ message.acknowledge();
+ if (!cleaned)
+ {
+ fail("Session is dirty we should get an IllegalStateException");
+ }
+ }
+ catch (javax.jms.IllegalStateException ise)
+ {
+ assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
+ // Recover the sesion and try again.
+ _consumerSession.recover();
+ }
+ }
+
+ // Acknowledge the last message if we are in a clean state
+ // this will then trigger test teardown.
+ if (cleaned)
+ {
+ _receviedAll.countDown();
+ }
+
+ //Reset message count so we can try again.
+ msgCount = 0;
+ cleaned = true;
+ }
+ catch (Exception e)
+ {
+ // If something goes wrong stop and notifiy main thread.
+ fail(e);
+ }
+ }
+ }
+
+ /**
+ * Test that Acking/Committing a message received before failover causes
+ * an exception at commit/ack time.
+ *
+ * Expected behaviour is that in:
+ * * tx mode commit() throws a transacted RolledBackException
+ * * client ack mode throws an IllegalStateException
+ *
+ * @param transacted is this session trasacted
+ * @param mode What ack mode should be used if not trasacted
+ *
+ * @throws Exception if something goes wrong.
+ */
+ protected void testDirtyAcking(boolean transacted, int mode) throws Exception
+ {
+ NUM_MESSAGES = 2;
+ _listener = new DirtyAckingHandler();
+
+ super.testAcking(transacted, mode);
+ }
+
+ public void testDirtyClientAck() throws Exception
+ {
+ testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void testDirtyAckingTransacted() throws Exception
+ {
+ testDirtyAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+ private void repopulateBroker() throws Exception
+ {
+ // Repopulate this new broker so we can test what happends after failover
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ // Use an exception so that we use our local fail() that notifies the main thread of failure
+ throw new Exception("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+
+ }
+ catch (Exception e)
+ {
+ // Use an exception so that we use our local fail() that notifies the main thread of failure
+ fail(e);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
new file mode 100644
index 0000000000..eb36522fac
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
@@ -0,0 +1,306 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ */
+public class AcknowledgeAfterFailoverTest extends AcknowledgeTest implements ConnectionListener
+{
+
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ // This must be even for the test to run correctly.
+ // Otherwise we will kill the standby broker
+ // not the one we are connected to.
+ // The test will still pass but it will not be exactly
+ // as described.
+ NUM_MESSAGES = 6;
+ }
+
+ /**
+ * Override default init to add connectionListener so we can verify that
+ * failover took place
+ *
+ * @param transacted create a transacted session for this test
+ * @param mode if not transacted what ack mode to use for this test
+ * @throws Exception if a problem occured during test setup.
+ */
+ @Override
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ super.init(transacted, mode);
+ ((AMQConnection) _connection).setConnectionListener(this);
+ }
+
+ protected void prepBroker(int count) throws Exception
+ {
+ if (count % 2 == 1)
+ {
+ failBroker(getFailingPort());
+ }
+ else
+ {
+ failBroker(getPort());
+ }
+
+ Connection connection = getConnection();
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, count, NUM_MESSAGES - count, 0);
+
+ if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
+ {
+ assertEquals("Wrong number of messages on queue", count,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+ }
+
+ connection.close();
+
+ try
+ {
+ if (count % 2 == 1)
+ {
+ startBroker(getFailingPort());
+ }
+ else
+ {
+ startBroker(getPort());
+ }
+ }
+ catch (Exception e)
+ {
+ fail("Unable to start failover broker," + e.getMessage());
+ }
+ }
+
+ @Override
+ public void doAcknowlegement(Message msg) throws JMSException
+ {
+ //Acknowledge current message
+ super.doAcknowlegement(msg);
+
+ try
+ {
+ prepBroker(NUM_MESSAGES - msg.getIntProperty(INDEX) - 1);
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Test that Acking/Committing a message received before failover causes
+ * an exception at commit/ack time.
+ *
+ * Expected behaviour is that in:
+ * * tx mode commit() throws a transacted RolledBackException
+ * * client ack mode throws an IllegalStateException
+ *
+ * @param transacted is this session trasacted
+ * @param mode What ack mode should be used if not trasacted
+ *
+ * @throws Exception if something goes wrong.
+ */
+ protected void testDirtyAcking(boolean transacted, int mode) throws Exception
+ {
+ NUM_MESSAGES = 2;
+ //Test Dirty Failover Fails
+ init(transacted, mode);
+
+ _connection.start();
+
+ Message msg = _consumer.receive(1500);
+
+ int count = 0;
+ assertNotNull("Message " + count + " not correctly received.", msg);
+ assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX));
+
+ //Don't acknowledge just prep the next broker. Without changing count
+ // Prep the new broker to have all all the messages so we can validate
+ // that they can all be correctly received.
+ try
+ {
+
+ //Stop the connection so we can validate the number of message count
+ // on the queue is correct after failover
+ _connection.stop();
+ failBroker(getFailingPort());
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();//getConnectionFactory("connection1").getConnectionURL());
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+
+ //restart connection
+ _connection.start();
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ // Consume the next message - don't check what it is as a normal would
+ // assume it is msg 1 but as we've fallen over it is msg 0 again.
+ msg = _consumer.receive(1500);
+
+ if (_consumerSession.getTransacted())
+ {
+ try
+ {
+ _consumerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ //expected path
+ }
+ }
+ else
+ {
+ try
+ {
+ msg.acknowledge();
+ fail("Session is dirty we should get an IllegalStateException");
+ }
+ catch (javax.jms.IllegalStateException ise)
+ {
+ assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
+ // Recover the sesion and try again.
+ _consumerSession.recover();
+ }
+ }
+
+ msg = _consumer.receive(1500);
+ // Validate we now get the first message back
+ assertEquals(0, msg.getIntProperty(INDEX));
+
+ msg = _consumer.receive(1500);
+ // and the second message
+ assertEquals(1, msg.getIntProperty(INDEX));
+
+ // And now verify that we can now commit the clean session
+ if (_consumerSession.getTransacted())
+ {
+ _consumerSession.commit();
+ }
+ else
+ {
+ msg.acknowledge();
+ }
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ public void testDirtyClientAck() throws Exception
+ {
+ testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void testDirtyAckingTransacted() throws Exception
+ {
+ testDirtyAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ fail("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ fail("Failover was interuppted");
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java
new file mode 100644
index 0000000000..4254727d36
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java
@@ -0,0 +1,170 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.JMSAMQException;
+import org.apache.qpid.client.failover.FailoverException;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AcknowledgeOnMessageTest extends AcknowledgeTest implements MessageListener
+{
+ protected CountDownLatch _receviedAll;
+ protected AtomicReference<Exception> _causeOfFailure = new AtomicReference<Exception>(null);
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ @Override
+ public void init(boolean transacted, int mode) throws Exception
+ {
+ _receviedAll = new CountDownLatch(NUM_MESSAGES);
+
+ super.init(transacted, mode);
+ _consumer.setMessageListener(this);
+ }
+
+ /**
+ * @param transacted
+ * @param mode
+ *
+ * @throws Exception
+ */
+ protected void testAcking(boolean transacted, int mode) throws Exception
+ {
+ init(transacted, mode);
+
+ _connection.start();
+
+ int lastCount = (int) _receviedAll.getCount();
+
+ boolean complete = _receviedAll.await(5000L, TimeUnit.MILLISECONDS);
+
+ while (!complete)
+ {
+ int currentCount = (int) _receviedAll.getCount();
+
+ // make sure we have received a message in the last cycle.
+ if (lastCount == currentCount)
+ {
+ break;
+ }
+ // Remember the currentCount as the lastCount for the next cycle.
+ // so we can exit if things get locked up.
+ lastCount = currentCount;
+
+ complete = _receviedAll.await(5000L, TimeUnit.MILLISECONDS);
+ }
+
+ if (!complete)
+ {
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+ else
+ {
+ fail("All messages not received missing:" + _receviedAll.getCount() + "/" + NUM_MESSAGES);
+ }
+ }
+
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+
+ try
+ {
+ _consumer.close();
+ }
+ catch (JMSAMQException amqe)
+ {
+ if (amqe.getLinkedException() instanceof FailoverException)
+ {
+ fail("QPID-143 : Auto Ack can acknowledge message from previous session after failver. If failover occurs between deliver and ack.");
+ }
+ // else Rethrow for TestCase to catch.
+ throw amqe;
+ }
+
+ _consumerSession.close();
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue));
+ }
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ int count = NUM_MESSAGES - (int) _receviedAll.getCount();
+
+ assertEquals("Incorrect message received", count, message.getIntProperty(INDEX));
+
+ count++;
+ if (count < NUM_MESSAGES)
+ {
+ //Send the next message
+ _producer.send(createNextMessage(_consumerSession, count));
+ }
+
+ doAcknowlegement(message);
+
+ _receviedAll.countDown();
+ }
+ catch (Exception e)
+ {
+ // This will end the test run by counting down _receviedAll
+ fail(e);
+ }
+ }
+
+ /**
+ * Pass the given exception back to the waiting thread to fail the test run.
+ *
+ * @param e The exception that is causing the test to fail.
+ */
+ protected void fail(Exception e)
+ {
+ _causeOfFailure.set(e);
+ // End the test.
+ while (_receviedAll.getCount() != 0)
+ {
+ _receviedAll.countDown();
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
index c367a0856c..7c9a77eb53 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
@@ -1,7 +1,5 @@
-package org.apache.qpid.test.unit.ack;
-
/*
- *
+ *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -21,133 +19,138 @@ package org.apache.qpid.test.unit.ack;
*
*/
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
+import javax.jms.MessageProducer;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-import org.apache.qpid.test.utils.QpidTestCase;
-
-public class AcknowledgeTest extends QpidTestCase
+public class AcknowledgeTest extends FailoverBaseCase
{
- protected static int NUM_MESSAGES = 100;
- protected Connection _con;
+ protected int NUM_MESSAGES;
+ protected Connection _connection;
protected Queue _queue;
- private MessageProducer _producer;
- private Session _producerSession;
- private Session _consumerSession;
- private MessageConsumer _consumerA;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ protected MessageProducer _producer;
@Override
protected void setUp() throws Exception
{
super.setUp();
- _queue = (Queue) getInitialContext().lookup("queue");
+ NUM_MESSAGES = 5;
+
+ _queue = getTestQueue();
//Create Producer put some messages on the queue
- _con = getConnection();
- _con.start();
+ _connection = getConnection();
}
- private void init(boolean transacted, int mode) throws JMSException {
- _producerSession = _con.createSession(true, Session.AUTO_ACKNOWLEDGE);
- _consumerSession = _con.createSession(transacted, mode);
- _producer = _producerSession.createProducer(_queue);
- _consumerA = _consumerSession.createConsumer(_queue);
- }
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ _consumerSession = _connection.createSession(transacted, mode);
+ _consumer = _consumerSession.createConsumer(_queue);
+ _producer = _consumerSession.createProducer(_queue);
+
+ // These should all end up being prefetched by session
+ sendMessage(_consumerSession, _queue, 1);
+
+ assertEquals("Wrong number of messages on queue", 1,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
/**
- * Produces and consumes messages an either ack or commit the receipt of those messages
- *
* @param transacted
* @param mode
+ *
* @throws Exception
*/
- private void testMessageAck(boolean transacted, int mode) throws Exception
+ protected void testAcking(boolean transacted, int mode) throws Exception
{
- init(transacted, mode);
- sendMessage(_producerSession, _queue, NUM_MESSAGES/2);
- _producerSession.commit();
- MessageConsumer consumerB = _consumerSession.createConsumer(_queue);
- sendMessage(_producerSession, _queue, NUM_MESSAGES/2);
- _producerSession.commit();
+ init(transacted, mode);
+
+ _connection.start();
+
+ Message msg = _consumer.receive(1500);
+
int count = 0;
- Message msg = consumerB.receive(1500);
- while (msg != null)
+ while (count < NUM_MESSAGES)
{
- if (mode == Session.CLIENT_ACKNOWLEDGE)
+ assertNotNull("Message " + count + " not correctly received.", msg);
+ assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX));
+ count++;
+
+ if (count < NUM_MESSAGES)
{
- msg.acknowledge();
+ //Send the next message
+ _producer.send(createNextMessage(_consumerSession, count));
}
- count++;
- msg = consumerB.receive(1500);
+
+ doAcknowlegement(msg);
+
+ msg = _consumer.receive(1500);
}
- if (transacted)
- {
- _consumerSession.commit();
- }
- _consumerA.close();
- consumerB.close();
- _consumerSession.close();
- assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count,
- ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
-
- // Clean up messages that may be left on the queue
- _consumerSession = _con.createSession(transacted, mode);
- _consumerA = _consumerSession.createConsumer(_queue);
- msg = _consumerA.receive(1500);
- while (msg != null)
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * Perform the acknowledgement of messages if additionally required.
+ *
+ * @param msg
+ *
+ * @throws JMSException
+ */
+ protected void doAcknowlegement(Message msg) throws JMSException
+ {
+ if (_consumerSession.getTransacted())
{
- if (mode == Session.CLIENT_ACKNOWLEDGE)
- {
- msg.acknowledge();
- }
- msg = _consumerA.receive(1500);
+ _consumerSession.commit();
}
- _consumerA.close();
- if (transacted)
+
+ if (_consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
{
- _consumerSession.commit();
+ msg.acknowledge();
}
- _consumerSession.close();
}
-
- public void test2ConsumersAutoAck() throws Exception
+
+ public void testClientAck() throws Exception
{
- testMessageAck(false, Session.AUTO_ACKNOWLEDGE);
+ testAcking(false, Session.CLIENT_ACKNOWLEDGE);
}
- public void test2ConsumersClientAck() throws Exception
+ public void testAutoAck() throws Exception
{
- testMessageAck(true, Session.CLIENT_ACKNOWLEDGE);
+ testAcking(false, Session.AUTO_ACKNOWLEDGE);
}
-
- public void test2ConsumersTx() throws Exception
+
+ public void testTransacted() throws Exception
{
- testMessageAck(true, Session.AUTO_ACKNOWLEDGE);
+ testAcking(true, Session.SESSION_TRANSACTED);
}
-
- public void testIndividualAck() throws Exception
+
+ public void testDupsOk() throws Exception
{
- init(false, Session.CLIENT_ACKNOWLEDGE);
- sendMessage(_producerSession, _queue, 3);
- _producerSession.commit();
- Message msg = null;
- for (int i = 0; i < 2; i++)
- {
- msg = _consumerA.receive(RECEIVE_TIMEOUT);
- ((AbstractJMSMessage)msg).acknowledgeThis();
- }
- msg = _consumerA.receive(RECEIVE_TIMEOUT);
- msg.acknowledge();
- _con.close();
+ testAcking(false, Session.DUPS_OK_ACKNOWLEDGE);
}
-
+
+ public void testNoAck() throws Exception
+ {
+ testAcking(false, AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ public void testPreAck() throws Exception
+ {
+ testAcking(false, AMQSession.PRE_ACKNOWLEDGE);
+ }
+
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java
new file mode 100644
index 0000000000..834b17430b
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.jms.Session;
+
+import javax.jms.Message;
+import javax.jms.Queue;
+
+public class FailoverBeforeConsumingRecoverTest extends RecoverTest
+{
+
+ @Override
+ protected void initTest() throws Exception
+ {
+ super.initTest();
+ failBroker(getFailingPort());
+
+ Queue queue = _consumerSession.createQueue(getTestQueueName());
+ sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
new file mode 100644
index 0000000000..6c4b7ba01b
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+/**
+ * This is a quick manual test to validate acking after failover with a
+ * transacted session.
+ *
+ * Start an external broker then run this test. Std Err will print.
+ * Sent Message: 1
+ * Received Message: 1
+ *
+ * You can then restart the external broker, which will cause failover, which
+ * will be complete when the following appears.
+ *
+ * Failover Complete
+ *
+ * A second message send/receive cycle is then done to validate that the
+ * connection/session are still working.
+ *
+ */
+public class QuickAcking extends QpidTestCase implements ConnectionListener
+{
+ protected AMQConnection _connection;
+ protected Queue _queue;
+ protected Session _session;
+ protected MessageConsumer _consumer;
+ private CountDownLatch _failedOver;
+ private static final String INDEX = "INDEX";
+ private int _count = 0;
+
+ public void setUp()
+ {
+ // Prevent broker startup. Broker must be run manually.
+ }
+
+ public void test() throws Exception
+ {
+ _failedOver = new CountDownLatch(1);
+
+ _connection = new AMQConnection("amqp://guest:guest@client/test?brokerlist='localhost?retries='20'&connectdelay='2000''");
+
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _queue = _session.createQueue("QAtest");
+ _consumer = _session.createConsumer(_queue);
+ _connection.setConnectionListener(this);
+ _connection.start();
+
+ sendAndReceive();
+
+ _failedOver.await();
+
+ sendAndReceive();
+
+ }
+
+ private void sendAndReceive()
+ throws Exception
+ {
+ sendMessage();
+
+ Message message = _consumer.receive();
+
+ if (message.getIntProperty(INDEX) != _count)
+ {
+ throw new Exception("Incorrect message recieved:" + _count);
+ }
+
+ if (_session.getTransacted())
+ {
+ _session.commit();
+ }
+ System.err.println("Recevied Message:" + _count);
+ }
+
+ private void sendMessage() throws JMSException
+ {
+ MessageProducer producer = _session.createProducer(_queue);
+ Message message = _session.createMessage();
+ _count++;
+ message.setIntProperty(INDEX, _count);
+
+ producer.send(message);
+ if (_session.getTransacted())
+ {
+ _session.commit();
+ }
+ producer.close();
+
+ System.err.println("Sent Message:" + _count);
+ }
+
+ public void bytesSent(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bytesReceived(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ System.err.println("Failover Complete");
+ _failedOver.countDown();
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
index 7434fcbb30..4a123cb1dc 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
@@ -23,8 +23,7 @@ import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.test.utils.QpidTestCase;
-
+import org.apache.qpid.test.utils.FailoverBaseCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,16 +34,21 @@ import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.TextMessage;
-
import java.util.concurrent.atomic.AtomicInteger;
-public class RecoverTest extends QpidTestCase
+public class RecoverTest extends FailoverBaseCase
{
- private static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
+ static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
private Exception _error;
private AtomicInteger count;
+ protected AMQConnection _connection;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ static final int SENT_COUNT = 4;
+
+ @Override
protected void setUp() throws Exception
{
super.setUp();
@@ -52,134 +56,110 @@ public class RecoverTest extends QpidTestCase
count = new AtomicInteger();
}
- protected void tearDown() throws Exception
+ protected void initTest() throws Exception
{
- super.tearDown();
- count = null;
- }
+ _connection = (AMQConnection) getConnection("guest", "guest");
- public void testRecoverResendsMsgs() throws Exception
- {
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
-
- Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"),
- new AMQShortString("someQ"), false, true);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
- // force synch to ensure the consumer has resulted in a bound queue
- // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
- // This is the default now
+ _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue queue = _consumerSession.createQueue(getTestQueueName());
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- MessageProducer producer = producerSession.createProducer(queue);
+ _consumer = _consumerSession.createConsumer(queue);
_logger.info("Sending four messages");
- producer.send(producerSession.createTextMessage("msg1"));
- producer.send(producerSession.createTextMessage("msg2"));
- producer.send(producerSession.createTextMessage("msg3"));
- producer.send(producerSession.createTextMessage("msg4"));
-
- con2.close();
-
+ sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT);
_logger.info("Starting connection");
- con.start();
- TextMessage tm = (TextMessage) consumer.receive();
- tm.acknowledge();
- _logger.info("Received and acknowledged first message");
- consumer.receive();
- consumer.receive();
- consumer.receive();
- _logger.info("Received all four messages. Calling recover with three outstanding messages");
- // no ack for last three messages so when I call recover I expect to get three messages back
- consumerSession.recover();
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg2", tm.getText());
+ _connection.start();
+ }
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg3", tm.getText());
+ protected Message validateNextMessages(int nextCount, int startIndex) throws JMSException
+ {
+ Message message = null;
+ for (int index = 0; index < nextCount; index++)
+ {
+ message = _consumer.receive(3000);
+ assertEquals(startIndex + index, message.getIntProperty(INDEX));
+ }
+ return message;
+ }
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm.getText());
+ protected void validateRemainingMessages(int remaining) throws JMSException
+ {
+ int index = SENT_COUNT - remaining;
- _logger.info("Received redelivery of three messages. Acknowledging last message");
- tm.acknowledge();
+ Message message = null;
+ while (index != SENT_COUNT)
+ {
+ message = _consumer.receive(3000);
+ assertEquals(index++, message.getIntProperty(INDEX));
+ }
+
+ if (message != null)
+ {
+ _logger.info("Received redelivery of three messages. Acknowledging last message");
+ message.acknowledge();
+ }
_logger.info("Calling acknowledge with no outstanding messages");
// all acked so no messages to be delivered
- consumerSession.recover();
+ _consumerSession.recover();
- tm = (TextMessage) consumer.receiveNoWait();
- assertNull(tm);
+ message = _consumer.receiveNoWait();
+ assertNull(message);
_logger.info("No messages redelivered as is expected");
-
- con.close();
}
- public void testRecoverResendsMsgsAckOnEarlier() throws Exception
+ public void testRecoverResendsMsgs() throws Exception
{
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ initTest();
- Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"),
- new AMQShortString("someQ"), false, true);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
- // force synch to ensure the consumer has resulted in a bound queue
- // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
- // This is the default now
+ Message message = validateNextMessages(1, 0);
+ message.acknowledge();
+ _logger.info("Received and acknowledged first message");
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- MessageProducer producer = producerSession.createProducer(queue);
+ _consumer.receive();
+ _consumer.receive();
+ _consumer.receive();
+ _logger.info("Received all four messages. Calling recover with three outstanding messages");
+ // no ack for last three messages so when I call recover I expect to get three messages back
- _logger.info("Sending four messages");
- producer.send(producerSession.createTextMessage("msg1"));
- producer.send(producerSession.createTextMessage("msg2"));
- producer.send(producerSession.createTextMessage("msg3"));
- producer.send(producerSession.createTextMessage("msg4"));
+ _consumerSession.recover();
- con2.close();
+ validateRemainingMessages(3);
+ }
- _logger.info("Starting connection");
- con.start();
- TextMessage tm = (TextMessage) consumer.receive();
- consumer.receive();
- tm.acknowledge();
+ public void testRecoverResendsMsgsAckOnEarlier() throws Exception
+ {
+ initTest();
+
+ Message message = validateNextMessages(2, 0);
+ message.acknowledge();
_logger.info("Received 2 messages, acknowledge() first message, should acknowledge both");
- consumer.receive();
- consumer.receive();
+ _consumer.receive();
+ _consumer.receive();
_logger.info("Received all four messages. Calling recover with two outstanding messages");
// no ack for last three messages so when I call recover I expect to get three messages back
- consumerSession.recover();
- TextMessage tm3 = (TextMessage) consumer.receive(3000);
- assertEquals("msg3", tm3.getText());
+ _consumerSession.recover();
+
+ Message message2 = _consumer.receive(3000);
+ assertEquals(2, message2.getIntProperty(INDEX));
- TextMessage tm4 = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm4.getText());
+ Message message3 = _consumer.receive(3000);
+ assertEquals(3, message3.getIntProperty(INDEX));
_logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message");
- ((org.apache.qpid.jms.Message) tm3).acknowledgeThis();
+ ((org.apache.qpid.jms.Message) message2).acknowledgeThis();
_logger.info("Calling recover");
// all acked so no messages to be delivered
- consumerSession.recover();
+ _consumerSession.recover();
- tm4 = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm4.getText());
- ((org.apache.qpid.jms.Message) tm4).acknowledgeThis();
+ message3 = _consumer.receive(3000);
+ assertEquals(3, message3.getIntProperty(INDEX));
+ ((org.apache.qpid.jms.Message) message3).acknowledgeThis();
- _logger.info("Calling recover");
// all acked so no messages to be delivered
- consumerSession.recover();
-
- tm = (TextMessage) consumer.receiveNoWait();
- assertNull(tm);
- _logger.info("No messages redelivered as is expected");
-
- con.close();
+ validateRemainingMessages(0);
}
public void testAcknowledgePerConsumer() throws Exception
@@ -188,11 +168,11 @@ public class RecoverTest extends QpidTestCase
Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"),
+ false, true);
Queue queue2 =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"),
+ false, true);
MessageConsumer consumer = consumerSession.createConsumer(queue);
MessageConsumer consumer2 = consumerSession.createConsumer(queue2);
@@ -231,8 +211,8 @@ public class RecoverTest extends QpidTestCase
final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"),
+ false, true);
MessageConsumer consumer = consumerSession.createConsumer(queue);
MessageProducer producer = consumerSession.createProducer(queue);
producer.send(consumerSession.createTextMessage("hello"));
@@ -240,50 +220,50 @@ public class RecoverTest extends QpidTestCase
final Object lock = new Object();
consumer.setMessageListener(new MessageListener()
- {
+ {
- public void onMessage(Message message)
+ public void onMessage(Message message)
+ {
+ try
{
- try
+ count.incrementAndGet();
+ if (count.get() == 1)
{
- count.incrementAndGet();
- if (count.get() == 1)
+ if (message.getJMSRedelivered())
{
- if (message.getJMSRedelivered())
- {
- setError(
+ setError(
new Exception("Message marked as redilvered on what should be first delivery attempt"));
- }
-
- consumerSession.recover();
}
- else if (count.get() == 2)
+
+ consumerSession.recover();
+ }
+ else if (count.get() == 2)
+ {
+ if (!message.getJMSRedelivered())
{
- if (!message.getJMSRedelivered())
- {
- setError(
+ setError(
new Exception(
- "Message not marked as redilvered on what should be second delivery attempt"));
- }
- }
- else
- {
- System.err.println(message);
- fail("Message delivered too many times!: " + count);
+ "Message not marked as redilvered on what should be second delivery attempt"));
}
}
- catch (JMSException e)
+ else
{
- _logger.error("Error recovering session: " + e, e);
- setError(e);
+ System.err.println(message);
+ fail("Message delivered too many times!: " + count);
}
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error recovering session: " + e, e);
+ setError(e);
+ }
- synchronized (lock)
- {
- lock.notify();
- }
+ synchronized (lock)
+ {
+ lock.notify();
}
- });
+ }
+ });
con.start();
@@ -323,9 +303,4 @@ public class RecoverTest extends QpidTestCase
{
_error = e;
}
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(RecoverTest.class);
- }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
deleted file mode 100644
index c42e4c7582..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.basic;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.BasicMessageProducer;
-import org.apache.qpid.client.state.StateWaiter;
-import org.apache.qpid.url.URLSyntaxException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jms.Connection;
-import javax.jms.DeliveryMode;
-import javax.jms.InvalidSelectorException;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import java.util.concurrent.CountDownLatch;
-
-public class SelectorTest extends QpidTestCase implements MessageListener
-{
- private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
-
- private AMQConnection _connection;
- private AMQDestination _destination;
- private AMQSession _session;
- private int count;
- public String _connectionString = "vm://:1";
- private static final String INVALID_SELECTOR = "Cost LIKE 5";
- CountDownLatch _responseLatch = new CountDownLatch(1);
-
- protected void setUp() throws Exception
- {
- super.setUp();
- init((AMQConnection) getConnection("guest", "guest"));
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
- private void init(AMQConnection connection) throws JMSException
- {
- init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true));
- }
-
- private void init(AMQConnection connection, AMQDestination destination) throws JMSException
- {
- _connection = connection;
- _destination = destination;
- connection.start();
-
- String selector = null;
- selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
- // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
-
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- // _session.createConsumer(destination).setMessageListener(this);
- _session.createConsumer(destination, selector).setMessageListener(this);
- }
-
- public void test() throws Exception
- {
- try
- {
-
- init((AMQConnection) getConnection("guest", "guest", randomize("Client")));
-
- Message msg = _session.createTextMessage("Message");
- msg.setJMSPriority(1);
- msg.setIntProperty("Cost", 2);
- msg.setStringProperty("property-with-hyphen", "wibble");
- msg.setJMSType("Special");
-
- _logger.info("Sending Message:" + msg);
-
- ((BasicMessageProducer) _session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
- _logger.info("Message sent, waiting for response...");
-
- _responseLatch.await();
-
- if (count > 0)
- {
- _logger.info("Got message");
- }
-
- if (count == 0)
- {
- fail("Did not get message!");
- // throw new RuntimeException("Did not get message!");
- }
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- System.out.println("SUCCESS!!");
- }
- }
- catch (InterruptedException e)
- {
- _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- _logger.debug("URL:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
- catch (AMQException e)
- {
- _logger.debug("AMQ:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
-
- finally
- {
- if (_session != null)
- {
- _session.close();
- }
- if (_connection != null)
- {
- _connection.close();
- }
- }
- }
-
-
- public void testInvalidSelectors() throws Exception
- {
- Connection connection = null;
-
- try
- {
- connection = getConnection("guest", "guest", randomize("Client"));
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- }
- catch (JMSException e)
- {
- fail(e.getMessage());
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- fail("Error:" + e.getMessage());
- }
-
- //Try Creating a Browser
- try
- {
- _session.createBrowser(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Consumer
- try
- {
- _session.createConsumer(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Receiever
- try
- {
- _session.createReceiver(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- finally
- {
- if (_session != null)
- {
- try
- {
- _session.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- if (_connection != null)
- {
- try
- {
- _connection.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- }
- }
-
- public void onMessage(Message message)
- {
- count++;
- _logger.info("Got Message:" + message);
- _responseLatch.countDown();
- }
-
- private static String randomize(String in)
- {
- return in + System.currentTimeMillis();
- }
-
- public static void main(String[] argv) throws Exception
- {
- SelectorTest test = new SelectorTest();
- test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
-
- try
- {
- while (true)
- {
- if (test._connectionString.contains("vm://:1"))
- {
- test.setUp();
- }
- test.test();
-
- if (test._connectionString.contains("vm://:1"))
- {
- test.tearDown();
- }
- }
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(SelectorTest.class);
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
index 1f90f1e29f..6b69ccab6c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
@@ -31,6 +31,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.Destination;
+import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
@@ -105,7 +106,8 @@ public class JMSPropertiesTest extends QpidTestCase
assertEquals("JMS Type mismatch", sentMsg.getJMSType(), rm.getJMSType());
assertEquals("JMS Reply To mismatch", sentMsg.getJMSReplyTo(), rm.getJMSReplyTo());
assertTrue("JMSMessageID Does not start ID:", rm.getJMSMessageID().startsWith("ID:"));
-
+ assertEquals("JMS Default priority should be 4",Message.DEFAULT_PRIORITY,rm.getJMSPriority());
+
//Validate that the JMSX values are correct
assertEquals("JMSXGroupID is not as expected:", JMSXGroupID_VALUE, rm.getStringProperty("JMSXGroupID"));
assertEquals("JMSXGroupSeq is not as expected:", JMSXGroupSeq_VALUE, rm.getIntProperty("JMSXGroupSeq"));
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java
new file mode 100644
index 0000000000..248042d2c4
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java
@@ -0,0 +1,403 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.publish;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * QPID-1816 : Whilst testing Acknoledgement after failover this completes testing
+ * of the client after failover. When we have a dirty session we should receive
+ * an error if we attempt to publish. This test ensures that both in the synchronous
+ * and asynchronous message delivery paths we receive the expected exceptions at
+ * the expected time.
+ */
+public class DirtyTrasactedPubilshTest extends FailoverBaseCase implements ConnectionListener
+{
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+
+ protected int NUM_MESSAGES;
+ protected Connection _connection;
+ protected Queue _queue;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ protected MessageProducer _producer;
+
+ private static final String MSG = "MSG";
+ private static final String SEND_FROM_ON_MESSAGE_TEXT = "sendFromOnMessage";
+ protected CountDownLatch _receviedAll;
+ protected AtomicReference<Exception> _causeOfFailure = new AtomicReference<Exception>(null);
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ NUM_MESSAGES = 10;
+
+ _queue = getTestQueue();
+
+ //Create Producer put some messages on the queue
+ _connection = getConnection();
+ }
+
+ /**
+ * Initialise the test variables
+ * @param transacted is this a transacted test
+ * @param mode if not trasacted then what ack mode to use
+ * @throws Exception if there is a setup issue.
+ */
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ _consumerSession = _connection.createSession(transacted, mode);
+ _consumer = _consumerSession.createConsumer(_queue);
+ _producer = _consumerSession.createProducer(_queue);
+
+ // These should all end up being prefetched by session
+ sendMessage(_consumerSession, _queue, 1);
+
+ assertEquals("Wrong number of messages on queue", 1,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * If a transacted session has failed over whilst it has uncommitted sent
+ * data then we need to throw a TransactedRolledbackException on commit()
+ *
+ * The alternative would be to maintain a replay buffer so that the message
+ * could be resent. This is not currently implemented
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testDirtySendingSynchronousTransacted() throws Exception
+ {
+ Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ // Ensure we get failover notifications
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ // Create and send message 0
+ Message msg = producerSession.createMessage();
+ msg.setIntProperty(INDEX, 0);
+ producer.send(msg);
+
+ // DON'T commit message .. fail connection
+
+ failBroker(getFailingPort());
+
+ // Ensure destination exists for sending
+ producerSession.createConsumer(_queue).close();
+
+ // Send the next message
+ msg.setIntProperty(INDEX, 1);
+ try
+ {
+ producer.send(msg);
+ fail("Should fail with Qpid as we provide early warning of the dirty session via a JMSException.");
+ }
+ catch (JMSException jmse)
+ {
+ assertEquals("Early warning of dirty session not correct",
+ "Failover has occurred and session is dirty so unable to send.", jmse.getMessage());
+ }
+
+ // Ignore that the session is dirty and attempt to commit to validate the
+ // exception is thrown. AND that the above failure notification did NOT
+ // clean up the session.
+
+ try
+ {
+ producerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ // Normal path.
+ }
+
+ // Resending of messages should now work ok as the commit was forcilbly rolledback
+ msg.setIntProperty(INDEX, 0);
+ producer.send(msg);
+ msg.setIntProperty(INDEX, 1);
+ producer.send(msg);
+
+ producerSession.commit();
+
+ assertEquals("Wrong number of messages on queue", 2,
+ ((AMQSession) producerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * If a transacted session has failed over whilst it has uncommitted sent
+ * data then we need to throw a TransactedRolledbackException on commit()
+ *
+ * The alternative would be to maintain a replay buffer so that the message
+ * could be resent. This is not currently implemented
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testDirtySendingOnMessageTransacted() throws Exception
+ {
+ NUM_MESSAGES = 1;
+ _receviedAll = new CountDownLatch(NUM_MESSAGES);
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ init(true, Session.SESSION_TRANSACTED);
+
+ _consumer.setMessageListener(new MessageListener()
+ {
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ // Create and send message 0
+ Message msg = _consumerSession.createMessage();
+ msg.setIntProperty(INDEX, 0);
+ _producer.send(msg);
+
+ // DON'T commit message .. fail connection
+
+ failBroker(getFailingPort());
+
+ // rep
+ repopulateBroker();
+
+ // Destination will exist as this failBroker will populate
+ // the queue with 1 message
+
+ // Send the next message
+ msg.setIntProperty(INDEX, 1);
+ try
+ {
+ _producer.send(msg);
+ fail("Should fail with Qpid as we provide early warning of the dirty session via a JMSException.");
+ }
+ catch (JMSException jmse)
+ {
+ assertEquals("Early warning of dirty session not correct",
+ "Failover has occurred and session is dirty so unable to send.", jmse.getMessage());
+ }
+
+ // Ignore that the session is dirty and attempt to commit to validate the
+ // exception is thrown. AND that the above failure notification did NOT
+ // clean up the session.
+
+ try
+ {
+ _consumerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ // Normal path.
+ }
+
+ // Resend messages
+ msg.setIntProperty(INDEX, 0);
+ msg.setStringProperty(MSG, SEND_FROM_ON_MESSAGE_TEXT);
+ _producer.send(msg);
+ msg.setIntProperty(INDEX, 1);
+ msg.setStringProperty(MSG, SEND_FROM_ON_MESSAGE_TEXT);
+ _producer.send(msg);
+
+ _consumerSession.commit();
+
+ // Stop this consumer .. can't do _consumer.stop == DEADLOCK
+ // this doesn't seem to stop dispatcher running
+ _connection.stop();
+
+ // Signal that the onMessage send part of test is complete
+ // main thread can validate that messages are correct
+ _receviedAll.countDown();
+
+ }
+ catch (Exception e)
+ {
+ fail(e);
+ }
+
+ }
+
+ });
+
+ _connection.start();
+
+ if (!_receviedAll.await(10000L, TimeUnit.MILLISECONDS))
+ {
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+ else
+ {
+ fail("All messages not received:" + _receviedAll.getCount() + "/" + NUM_MESSAGES);
+ }
+ }
+
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+
+ _consumer.close();
+ _consumerSession.close();
+
+ _consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _connection.start();
+
+ // Validate that we could send the messages as expected.
+ assertEquals("Wrong number of messages on queue", 3,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+
+ MessageConsumer consumer = _consumerSession.createConsumer(_queue);
+
+ //Validate the message sent to setup the failed over broker.
+ Message message = consumer.receive(1000);
+ assertNotNull("Message " + 0 + " not received.", message);
+ assertEquals("Incorrect message received", 0, message.getIntProperty(INDEX));
+
+ // Validate the two messages sent from within the onMessage
+ for (int index = 0; index <= 1; index++)
+ {
+ message = consumer.receive(1000);
+ assertNotNull("Message " + index + " not received.", message);
+ assertEquals("Incorrect message received", index, message.getIntProperty(INDEX));
+ assertEquals("Incorrect message text for message:" + index, SEND_FROM_ON_MESSAGE_TEXT, message.getStringProperty(MSG));
+ }
+
+ assertNull("Extra message received.", consumer.receiveNoWait());
+
+ _consumerSession.close();
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue));
+ }
+
+ private void repopulateBroker() throws Exception
+ {
+ // Repopulate this new broker so we can test what happends after failover
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port int the port of the broker to fail.
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ fail("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ fail("Failover was interuppted");
+ }
+ }
+
+ /**
+ * Pass the given exception back to the waiting thread to fail the test run.
+ *
+ * @param e The exception that is causing the test to fail.
+ */
+ protected void fail(Exception e)
+ {
+ _causeOfFailure.set(e);
+ // End the test.
+ while (_receviedAll.getCount() != 0)
+ {
+ _receviedAll.countDown();
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
index 64bd1503ba..0426c4f45f 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
@@ -20,44 +20,43 @@
*/
package org.apache.qpid.test.utils;
-import javax.jms.Connection;
-import javax.jms.JMSException;
+import org.apache.qpid.util.FileUtils;
+
import javax.naming.NamingException;
-import org.apache.qpid.util.FileUtils;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class FailoverBaseCase extends QpidTestCase
{
+ protected static final Logger _logger = LoggerFactory.getLogger(FailoverBaseCase.class);
public static int FAILING_VM_PORT = 2;
- public static int FAILING_PORT = DEFAULT_PORT + 100;
+ public static int FAILING_PORT = Integer.parseInt(System.getProperty("test.port.alt"));
+ public static final long DEFAULT_FAILOVER_TIME = 10000L;
protected int failingPort;
-
- private boolean failedOver = false;
- public FailoverBaseCase()
+ protected int getFailingPort()
{
if (_broker.equals(VM))
{
- failingPort = FAILING_VM_PORT;
+ return FAILING_VM_PORT;
}
else
{
- failingPort = FAILING_PORT;
+ return FAILING_PORT;
}
}
-
- protected int getFailingPort()
- {
- return failingPort;
- }
protected void setUp() throws java.lang.Exception
{
super.setUp();
- setSystemProperty("QPID_WORK", System.getProperty("java.io.tmpdir")+"/"+getFailingPort());
- startBroker(failingPort);
+ // Set QPID_WORK to $QPID_WORK/<getFailingPort()>
+ // or /tmp/<getFailingPort()> if QPID_WORK not set.
+ setSystemProperty("QPID_WORK", System.getProperty("QPID_WORK") + "/" + getFailingPort());
+ startBroker(getFailingPort());
}
/**
@@ -66,42 +65,52 @@ public class FailoverBaseCase extends QpidTestCase
* @return a connection
* @throws Exception
*/
- public Connection getConnection() throws JMSException, NamingException
+ @Override
+ public AMQConnectionFactory getConnectionFactory() throws NamingException
{
- Connection conn =
- (Boolean.getBoolean("profile.use_ssl"))?
- getConnectionFactory("failover.ssl").createConnection("guest", "guest"):
- getConnectionFactory("failover").createConnection("guest", "guest");
- _connections.add(conn);
- return conn;
+ _logger.info("get ConnectionFactory");
+ if (_connectionFactory == null)
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ _connectionFactory = getConnectionFactory("failover.ssl");
+ }
+ else
+ {
+ _connectionFactory = getConnectionFactory("failover");
+ }
+ }
+ return _connectionFactory;
}
+
public void tearDown() throws Exception
{
- stopBroker(_broker.equals(VM)?FAILING_PORT:FAILING_PORT);
- super.tearDown();
- FileUtils.deleteDirectory(System.getProperty("java.io.tmpdir")+"/"+getFailingPort());
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ // Ensure we shutdown any secondary brokers, even if we are unable
+ // to cleanly tearDown the QTC.
+ stopBroker(getFailingPort());
+ FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort());
+ }
}
- /**
- * Only used of VM borker.
- */
- public void failBroker()
+ public void failBroker(int port)
{
- failedOver = true;
try
{
- stopBroker(getFailingPort());
+ stopBroker(port);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
-
- protected void setFailingPort(int p)
- {
- failingPort = p;
- }
+
+
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
index 76e4118c96..6c1b1c7b8d 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -22,8 +22,10 @@ import junit.framework.TestResult;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.qpid.AMQException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.transport.TransportConnection;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ConnectionURL;
@@ -32,6 +34,7 @@ import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import org.apache.qpid.server.store.DerbyMessageStore;
import org.apache.qpid.url.URLSyntaxException;
+import org.apache.log4j.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,13 +73,18 @@ public class QpidTestCase extends TestCase
protected final String QpidHome = System.getProperty("QPID_HOME");
protected File _configFile = new File(System.getProperty("broker.config"));
- private static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class);
+ protected static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class);
protected long RECEIVE_TIMEOUT = 1000l;
- private Map<String, String> _setProperties = new HashMap<String, String>();
+ private Map<String, String> _propertiesSetForTestOnly = new HashMap<String, String>();
+ private Map<String, String> _propertiesSetForBroker = new HashMap<String, String>();
+ private Map<org.apache.log4j.Logger, Level> _loggerLevelSetForTest = new HashMap<org.apache.log4j.Logger, Level>();
+
private XMLConfiguration _testConfiguration = new XMLConfiguration();
+ protected static final String INDEX = "index";
+
/**
* Some tests are excluded when the property test.excludes is set to true.
* An exclusion list is either a file (prop test.excludesfile) which contains one test name
@@ -147,6 +155,7 @@ public class QpidTestCase extends TestCase
private static final String BROKER_LANGUAGE = "broker.language";
private static final String BROKER = "broker";
private static final String BROKER_CLEAN = "broker.clean";
+ private static final String BROKER_CLEAN_BETWEEN_TESTS = "broker.clean.between.tests";
private static final String BROKER_VERSION = "broker.version";
protected static final String BROKER_READY = "broker.ready";
private static final String BROKER_STOPPED = "broker.stopped";
@@ -169,6 +178,7 @@ public class QpidTestCase extends TestCase
protected String _brokerLanguage = System.getProperty(BROKER_LANGUAGE, JAVA);
protected String _broker = System.getProperty(BROKER, VM);
private String _brokerClean = System.getProperty(BROKER_CLEAN, null);
+ private Boolean _brokerCleanBetweenTests = Boolean.getBoolean(BROKER_CLEAN_BETWEEN_TESTS);
private String _brokerVersion = System.getProperty(BROKER_VERSION, VERSION_08);
private String _output = System.getProperty(TEST_OUTPUT);
@@ -177,7 +187,7 @@ public class QpidTestCase extends TestCase
private Map<Integer, Process> _brokers = new HashMap<Integer, Process>();
private InitialContext _initialContext;
- private AMQConnectionFactory _connectionFactory;
+ protected AMQConnectionFactory _connectionFactory;
private String _testName;
@@ -235,6 +245,19 @@ public class QpidTestCase extends TestCase
{
_logger.error("exception stopping broker", e);
}
+
+ if(_brokerCleanBetweenTests)
+ {
+ try
+ {
+ cleanBroker();
+ }
+ catch (Exception e)
+ {
+ _logger.error("exception cleaning up broker", e);
+ }
+ }
+
_logger.info("========== stop " + _testName + " ==========");
if (redirected)
@@ -451,6 +474,15 @@ public class QpidTestCase extends TestCase
env.put("QPID_PNAME", "-DPNAME=QPBRKR -DTNAME=\"" + _testName + "\"");
env.put("QPID_WORK", System.getProperty("QPID_WORK"));
+
+ // Use the environment variable to set amqj.logging.level for the broker
+ // The value used is a 'server' value in the test configuration to
+ // allow a differentiation between the client and broker logging levels.
+ if (System.getProperty("amqj.server.logging.level") != null)
+ {
+ setBrokerEnvironment("AMQJ_LOGGING_LEVEL", System.getProperty("amqj.server.logging.level"));
+ }
+
// Add all the environment settings the test requested
if (!_env.isEmpty())
{
@@ -460,13 +492,27 @@ public class QpidTestCase extends TestCase
}
}
+
+ // Add default test logging levels that are used by the log4j-test
+ // Use the convenience methods to push the current logging setting
+ // in to the external broker's QPID_OPTS string.
+ if (System.getProperty("amqj.protocol.logging.level") != null)
+ {
+ setSystemProperty("amqj.protocol.logging.level");
+ }
+ if (System.getProperty("root.logging.level") != null)
+ {
+ setSystemProperty("root.logging.level");
+ }
+
+
String QPID_OPTS = " ";
// Add all the specified system properties to QPID_OPTS
- if (!_setProperties.isEmpty())
+ if (!_propertiesSetForBroker.isEmpty())
{
- for (String key : _setProperties.keySet())
+ for (String key : _propertiesSetForBroker.keySet())
{
- QPID_OPTS += "-D" + key + "=" + System.getProperty(key) + " ";
+ QPID_OPTS += "-D" + key + "=" + _propertiesSetForBroker.get(key) + " ";
}
if (env.containsKey("QPID_OPTS"))
@@ -489,7 +535,7 @@ public class QpidTestCase extends TestCase
if (!p.await(30, TimeUnit.SECONDS))
{
- _logger.info("broker failed to become ready:" + p.getStopLine());
+ _logger.info("broker failed to become ready (" + p.ready + "):" + p.getStopLine());
//Ensure broker has stopped
process.destroy();
cleanBroker();
@@ -667,28 +713,87 @@ public class QpidTestCase extends TestCase
}
/**
+ * Set a System property that is to be applied only to the external test
+ * broker.
+ *
+ * This is a convenience method to enable the setting of a -Dproperty=value
+ * entry in QPID_OPTS
+ *
+ * This is only useful for the External Java Broker tests.
+ *
+ * @param property the property name
+ * @param value the value to set the property to
+ */
+ protected void setBrokerOnlySystemProperty(String property, String value)
+ {
+ if (!_propertiesSetForBroker.containsKey(property))
+ {
+ _propertiesSetForBroker.put(property, value);
+ }
+
+ }
+
+ /**
+ * Set a System (-D) property for this test run.
+ *
+ * This convenience method copies the current VMs System Property
+ * for the external VM Broker.
+ *
+ * @param property the System property to set
+ */
+ protected void setSystemProperty(String property)
+ {
+ setSystemProperty(property, System.getProperty(property));
+ }
+
+ /**
* Set a System property for the duration of this test.
*
* When the test run is complete the value will be reverted.
*
+ * The values set using this method will also be propogated to the external
+ * Java Broker via a -D value defined in QPID_OPTS.
+ *
+ * If the value should not be set on the broker then use
+ * setTestClientSystemProperty().
+ *
* @param property the property to set
* @param value the new value to use
*/
protected void setSystemProperty(String property, String value)
{
- if (!_setProperties.containsKey(property))
+ // Record the value for the external broker
+ _propertiesSetForBroker.put(property, value);
+
+ //Set the value for the test client vm aswell.
+ setTestClientSystemProperty(property, value);
+ }
+
+ /**
+ * Set a System (-D) property for the external Broker of this test.
+ *
+ * @param property The property to set
+ * @param value the value to set it to.
+ */
+ protected void setTestClientSystemProperty(String property, String value)
+ {
+ if (!_propertiesSetForTestOnly.containsKey(property))
{
- _setProperties.put(property, System.getProperty(property));
- }
+ // Record the current value so we can revert it later.
+ _propertiesSetForTestOnly.put(property, System.getProperty(property));
+ }
System.setProperty(property, value);
}
+ /**
+ * Restore the System property values that were set before this test run.
+ */
protected void revertSystemProperties()
{
- for (String key : _setProperties.keySet())
+ for (String key : _propertiesSetForTestOnly.keySet())
{
- String value = _setProperties.get(key);
+ String value = _propertiesSetForTestOnly.get(key);
if (value != null)
{
System.setProperty(key, value);
@@ -698,6 +803,12 @@ public class QpidTestCase extends TestCase
System.clearProperty(key);
}
}
+
+ _propertiesSetForTestOnly.clear();
+
+ // We don't change the current VMs settings for Broker only properties
+ // so we can just clear this map
+ _propertiesSetForBroker.clear();
}
/**
@@ -712,6 +823,40 @@ public class QpidTestCase extends TestCase
}
/**
+ * Adjust the VMs Log4j Settings just for this test run
+ *
+ * @param logger the logger to change
+ * @param level the level to set
+ */
+ protected void setLoggerLevel(org.apache.log4j.Logger logger, Level level)
+ {
+ assertNotNull("Cannot set level of null logger", logger);
+ assertNotNull("Cannot set Logger("+logger.getName()+") to null level.",level);
+
+ if (!_loggerLevelSetForTest.containsKey(logger))
+ {
+ // Record the current value so we can revert it later.
+ _loggerLevelSetForTest.put(logger, logger.getLevel());
+ }
+
+ logger.setLevel(level);
+ }
+
+ /**
+ * Restore the logging levels defined by this test.
+ */
+ protected void revertLoggingLevels()
+ {
+ for (org.apache.log4j.Logger logger : _loggerLevelSetForTest.keySet())
+ {
+ logger.setLevel(_loggerLevelSetForTest.get(logger));
+ }
+
+ _loggerLevelSetForTest.clear();
+
+ }
+
+ /**
* Check whether the broker is an 0.8
*
* @return true if the broker is an 0_8 version, false otherwise.
@@ -786,7 +931,7 @@ public class QpidTestCase extends TestCase
{
if (Boolean.getBoolean("profile.use_ssl"))
{
- _connectionFactory = getConnectionFactory("ssl");
+ _connectionFactory = getConnectionFactory("default.ssl");
}
else
{
@@ -876,15 +1021,32 @@ public class QpidTestCase extends TestCase
return getClass().getSimpleName() + "-" + getName();
}
+ /**
+ * Return a Queue specific for this test.
+ * Uses getTestQueueName() as the name of the queue
+ * @return
+ */
+ public Queue getTestQueue()
+ {
+ return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, getTestQueueName());
+ }
+
+
protected void tearDown() throws java.lang.Exception
{
- // close all the connections used by this test.
- for (Connection c : _connections)
+ try
{
- c.close();
+ // close all the connections used by this test.
+ for (Connection c : _connections)
+ {
+ c.close();
+ }
+ }
+ finally{
+ // Ensure any problems with close does not interfer with property resets
+ revertSystemProperties();
+ revertLoggingLevels();
}
-
- revertSystemProperties();
}
/**
@@ -921,17 +1083,23 @@ public class QpidTestCase extends TestCase
public List<Message> sendMessage(Session session, Destination destination,
int count) throws Exception
{
- return sendMessage(session, destination, count, 0);
+ return sendMessage(session, destination, count, 0, 0);
}
public List<Message> sendMessage(Session session, Destination destination,
int count, int batchSize) throws Exception
{
+ return sendMessage(session, destination, count, 0, batchSize);
+ }
+
+ public List<Message> sendMessage(Session session, Destination destination,
+ int count, int offset, int batchSize) throws Exception
+ {
List<Message> messages = new ArrayList<Message>(count);
MessageProducer producer = session.createProducer(destination);
- for (int i = 0; i < count; i++)
+ for (int i = offset; i < (count + offset); i++)
{
Message next = createNextMessage(session, i);
@@ -950,8 +1118,11 @@ public class QpidTestCase extends TestCase
}
// Ensure we commit the last messages
- if (session.getTransacted() && (batchSize > 0) &&
- (count / batchSize != 0))
+ // Commit the session if we are transacted and
+ // we have no batchSize or
+ // our count is not divible by batchSize.
+ if (session.getTransacted() &&
+ ( batchSize == 0 || count % batchSize != 0))
{
session.commit();
}
@@ -961,7 +1132,11 @@ public class QpidTestCase extends TestCase
public Message createNextMessage(Session session, int msgCount) throws JMSException
{
- return session.createMessage();
+ Message message = session.createMessage();
+ message.setIntProperty(INDEX, msgCount);
+
+ return message;
+
}
public ConnectionURL getConnectionURL() throws NamingException
diff --git a/qpid/java/test-profiles/010Excludes b/qpid/java/test-profiles/010Excludes
index f03d62667d..757a1e425c 100644..100755
--- a/qpid/java/test-profiles/010Excludes
+++ b/qpid/java/test-profiles/010Excludes
@@ -92,3 +92,12 @@ org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#*
// QPID-2084 : this test needs more work for 0-10
org.apache.qpid.test.unit.client.DynamicQueueExchangeCreateTest#*
+
+// QPID-2118 : 0-10 Java client has differrent error handling to 0-8 code path
+org.apache.qpid.test.client.message.SelectorTest#testRuntimeSelectorError
+
+//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
+org.apache.qpid.server.queue.ProducerFlowControlTest#*
+
+//QPID-1950 : Commit to test this failure. This is a MINA only failure so it cannot be tested when using 010.
+org.apache.qpid.server.failover.MessageDisappearWithIOExceptionTest#*
diff --git a/qpid/java/test-profiles/08Excludes b/qpid/java/test-profiles/08Excludes
index b277c6d929..6f3898384d 100644
--- a/qpid/java/test-profiles/08Excludes
+++ b/qpid/java/test-profiles/08Excludes
@@ -14,8 +14,6 @@ org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
// QPID-1823: this takes ages to run
org.apache.qpid.client.SessionCreateTest#*
-org.apache.qpid.test.client.RollbackOrderTest#*
-
// QPID-2097 exclude it from the InVM test runs until InVM JMX Interface is reliable
org.apache.qpid.management.jmx.ManagementActorLoggingTest#*
org.apache.qpid.server.queue.ModelTest#*
diff --git a/qpid/java/test-profiles/08StandaloneExcludes b/qpid/java/test-profiles/08StandaloneExcludes
index de876e06bb..ee781fb80f 100644
--- a/qpid/java/test-profiles/08StandaloneExcludes
+++ b/qpid/java/test-profiles/08StandaloneExcludes
@@ -39,8 +39,6 @@ org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
// QPID-1823: this takes ages to run
org.apache.qpid.client.SessionCreateTest#*
-org.apache.qpid.test.client.RollbackOrderTest#*
-
// This test requires the standard configuration file for validation.
// Excluding here does not reduce test coverage.
org.apache.qpid.server.configuration.ServerConfigurationFileTest#*
diff --git a/qpid/java/test-profiles/Excludes b/qpid/java/test-profiles/Excludes
index a72d3bc86c..aa60554c04 100644
--- a/qpid/java/test-profiles/Excludes
+++ b/qpid/java/test-profiles/Excludes
@@ -19,3 +19,15 @@ org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#*
// QPID-2081 :The configuration changes are now highlighting the close race condition
org.apache.qpid.server.security.acl.SimpleACLTest#*
+
+// QPID-1816 : Client Ack has not been addressed
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testDirtyClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testDirtyClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testClientAck
+
+
+// QPID-143 : Failover can occur between receive and ack but we don't stop the ack.
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testAutoAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testDupsOk
+
diff --git a/qpid/java/test-profiles/default.testprofile b/qpid/java/test-profiles/default.testprofile
index 86a5b2efb3..28127e5c4c 100644
--- a/qpid/java/test-profiles/default.testprofile
+++ b/qpid/java/test-profiles/default.testprofile
@@ -11,11 +11,14 @@ max_prefetch=1000
log=debug
amqj.logging.level=${log}
+amqj.server.logging.level=${log}
amqj.protocol.logging.level=${log}
root.logging.level=warn
log4j.configuration=file:///${test.profiles}/log4j-test.xml
log4j.debug=false
+# Note test-provider.properties also has variables of same name.
+# Keep in sync
test.port=15672
test.mport=18999
#Note : Management will start open second port on: mport + 100 : 19099
diff --git a/qpid/java/test-profiles/log4j-test.xml b/qpid/java/test-profiles/log4j-test.xml
index 0aaa7d8686..2d77942a81 100644
--- a/qpid/java/test-profiles/log4j-test.xml
+++ b/qpid/java/test-profiles/log4j-test.xml
@@ -29,10 +29,10 @@
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
+ <param name="ImmediateFlush" value="true"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%t %d %p [%c{4}] %m%n"/>
</layout>
- <param name="ImmediateFlush" value="true"/>
</appender>
<logger name="org.apache.qpid">
@@ -46,6 +46,10 @@
<logger name="org.apache.qpid.test.utils.QpidTestCase">
<level value="ALL"/>
</logger>
+
+ <logger name="org.apache.commons">
+ <level value="WARN"/>
+ </logger>
<root>
<level value="${root.logging.level}"/>
diff --git a/qpid/java/test-profiles/test-provider.properties b/qpid/java/test-profiles/test-provider.properties
index e5cb18da0b..8cea012c1d 100644
--- a/qpid/java/test-profiles/test-provider.properties
+++ b/qpid/java/test-profiles/test-provider.properties
@@ -19,20 +19,23 @@
#
#
-test.port=5672
-test.port.ssl=5671
-test.port.alt=5772
-test.port.alt.ssl=5771
+# Copied from default.testprofile
+test.port=15672
+test.mport=18999
+#Note : Java Management will start open second port on: mport + 100 : 19099
+test.port.ssl=15671
+test.port.alt=25672
+test.port.alt.ssl=25671
+
connectionfactory.default = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port}'
+connectionfactory.default.ssl = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.ssl}?ssl='true''
connectionfactory.default.vm = amqp://username:password@clientid/test?brokerlist='vm://:1'
-connectionfactory.ssl = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.ssl}?ssl='true''
connectionfactory.failover = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt};tcp://localhost:${test.port}'&sync_ack='true'&sync_publish='all'&failover='roundrobin?cyclecount='20''
-
connectionfactory.failover.ssl = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt.ssl}?ssl='true';tcp://localhost:${test.port.ssl}?ssl='true''&sync_ack='true'&sync_publish='all'&failover='roundrobin?cyclecount='20''
+connectionfactory.failover.vm = amqp://username:password@clientid/test?brokerlist='vm://:2;vm://:1'&failover='roundrobin?cyclecount='20''
-connectionfactory.failover.vm = amqp://username:password@clientid/test?brokerlist='vm://:2;vm://:1'
connectionfactory.connection1 = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port}'
connectionfactory.connection2 = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt}'
connectionfactory.connection1.vm = amqp://username:password@clientid/test?brokerlist='vm://:1'
diff --git a/qpid/python/Makefile b/qpid/python/Makefile
index 31547c8f57..ff4a9af4f1 100644
--- a/qpid/python/Makefile
+++ b/qpid/python/Makefile
@@ -36,7 +36,7 @@ SRCS=$(shell find $(DIRS) -name "*.py") qpid_config.py
BUILD=build
TARGETS=$(SRCS:%.py=$(BUILD)/%.py)
-PYCC=python -c "import compileall, sys; compileall.compile_dir(sys.argv[1])"
+PYCC=python -O -c "import compileall; compileall.main()"
all: build
diff --git a/qpid/python/examples/api/drain b/qpid/python/examples/api/drain
new file mode 100755
index 0000000000..485985f16d
--- /dev/null
+++ b/qpid/python/examples/api/drain
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from qpid.messaging import *
+from qpid.util import URL
+
+parser = optparse.OptionParser(usage="usage: %prog [options] ADDRESS ...",
+ description="Drain messages from the supplied address.")
+parser.add_option("-b", "--broker", default="localhost",
+ help="connect to specified BROKER (default %default)")
+parser.add_option("-t", "--timeout", type=float, default=0,
+ help="timeout in seconds to wait before exiting (default %default)")
+parser.add_option("-f", "--forever", action="store_true",
+ help="ignore timeout and wait forever")
+
+opts, args = parser.parse_args()
+
+url = URL(opts.broker)
+if args:
+ addr = args.pop(0)
+else:
+ parser.error("address is required")
+if opts.forever:
+ timeout = None
+else:
+ timeout = opts.timeout
+
+# XXX: should make URL default the port for us
+conn = Connection.open(url.host, url.port or AMQP_PORT,
+ username=url.user, password=url.password)
+ssn = conn.session()
+rcv = ssn.receiver(addr)
+
+while True:
+ try:
+ print rcv.fetch(timeout=timeout)
+ ssn.acknowledge()
+ except Empty:
+ break
+ except ReceiveError, e:
+ print e
+ break
+
+conn.close()
diff --git a/qpid/python/examples/api/ping b/qpid/python/examples/api/ping
new file mode 100755
index 0000000000..59b367cca6
--- /dev/null
+++ b/qpid/python/examples/api/ping
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse, time
+from qpid.messaging import *
+from qpid.util import URL
+
+parser = optparse.OptionParser(usage="usage: %prog [options] ADDRESS [ CONTENT ... ]",
+ description="Drain messages from the supplied address.")
+parser.add_option("-b", "--broker", default="localhost",
+ help="connect to specified BROKER (default %default)")
+parser.add_option("-c", "--count", type=int, default=1,
+ help="stop after count messages have been sent, zero disables (default %default)")
+parser.add_option("-t", "--timeout", type=float, default=None,
+ help="exit after the specified time")
+parser.add_option("-m", "--map", action="store_true",
+ help="interpret content as map")
+parser.add_option("-i", "--id", help="use the supplied id instead of generating one")
+
+opts, args = parser.parse_args()
+
+url = URL(opts.broker)
+if opts.id is None:
+ ping_id = str(uuid4())
+else:
+ ping_id = opts.id
+if args:
+ addr = args.pop(0)
+else:
+ parser.error("address is required")
+if args:
+ content = " ".join(args)
+ if opts.map:
+ content = eval(content)
+else:
+ content = None
+
+# XXX: should make URL default the port for us
+conn = Connection.open(url.host, url.port or AMQP_PORT,
+ username=url.user, password=url.password)
+ssn = conn.session()
+snd = ssn.sender(addr)
+
+count = 0
+start = time.time()
+while (opts.count == 0 or count < opts.count) and \
+ (opts.timeout is None or time.time() - start < opts.timeout):
+ msg = Message(content)
+ msg.properties["ping-id"] = "%s:%s" % (ping_id, count)
+
+ try:
+ snd.send(msg)
+ count += 1
+ print msg
+ except SendError, e:
+ print e
+ break
+
+conn.close()
diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test
index 528acaa124..b569020368 100755
--- a/qpid/python/qpid-python-test
+++ b/qpid/python/qpid-python-test
@@ -20,7 +20,7 @@
# TODO: summarize, test harness preconditions (e.g. broker is alive)
-import fcntl, logging, optparse, os, struct, sys, termios, traceback, types
+import logging, optparse, os, struct, sys, traceback, types
from fnmatch import fnmatchcase as match
from getopt import GetoptError
from logging import getLogger, StreamHandler, Formatter, Filter, \
@@ -126,27 +126,33 @@ def is_included(path):
def is_smart():
return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb"
-def width():
- if is_smart():
- s = struct.pack("HHHH", 0, 0, 0, 0)
- fd_stdout = sys.stdout.fileno()
- x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
- rows, cols, xpx, ypx = struct.unpack("HHHH", x)
- return cols
- else:
- try:
- return int(os.environ.get("COLUMNS", "80"))
- except ValueError:
- return 80
+try:
+ import fcntl, termios
-WIDTH = width()
+ def width():
+ if is_smart():
+ s = struct.pack("HHHH", 0, 0, 0, 0)
+ fd_stdout = sys.stdout.fileno()
+ x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
+ rows, cols, xpx, ypx = struct.unpack("HHHH", x)
+ return cols
+ else:
+ try:
+ return int(os.environ.get("COLUMNS", "80"))
+ except ValueError:
+ return 80
-def resize(sig, frm):
- global WIDTH
WIDTH = width()
-import signal
-signal.signal(signal.SIGWINCH, resize)
+ def resize(sig, frm):
+ global WIDTH
+ WIDTH = width()
+
+ import signal
+ signal.signal(signal.SIGWINCH, resize)
+
+except ImportError:
+ WIDTH = 80
def vt100_attrs(*attrs):
return "\x1B[%sm" % ";".join(map(str, attrs))
diff --git a/qpid/python/qpid/address.py b/qpid/python/qpid/address.py
new file mode 100644
index 0000000000..5976d4889b
--- /dev/null
+++ b/qpid/python/qpid/address.py
@@ -0,0 +1,171 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import re
+
+TYPES = []
+
+class Type:
+
+ def __init__(self, name, pattern=None):
+ self.name = name
+ self.pattern = pattern
+ if self.pattern:
+ TYPES.append(self)
+
+ def __repr__(self):
+ return self.name
+
+LBRACE = Type("LBRACE", r"\{")
+RBRACE = Type("RBRACE", r"\}")
+COLON = Type("COLON", r":")
+COMMA = Type("COMMA", r",")
+SLASH = Type("SLASH", r"/")
+ID = Type("ID", r'[a-zA-Z_][a-zA-Z0-9_.-]*')
+NUMBER = Type("NUMBER", r'[+-]?[0-9]*\.?[0-9]+')
+STRING = Type("STRING", r""""(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'""")
+WSPACE = Type("WSPACE", r"[ \n\r\t]+")
+EOF = Type("EOF")
+
+class Token:
+
+ def __init__(self, type, value):
+ self.type = type
+ self.value = value
+
+ def __repr__(self):
+ return "%s: %r" % (self.type, self.value)
+
+joined = "|".join(["(%s)" % t.pattern for t in TYPES])
+LEXER = re.compile(joined)
+
+class LexError(Exception):
+ pass
+
+def line_info(st, pos):
+ idx = 0
+ lineno = 1
+ column = 0
+ line_pos = 0
+ while idx < pos:
+ if st[idx] == "\n":
+ lineno += 1
+ column = 0
+ line_pos = idx
+ column += 1
+ idx += 1
+
+ end = st.find("\n", line_pos)
+ if end < 0:
+ end = len(st)
+ line = st[line_pos:end]
+
+ return line, lineno, column
+
+def lex(st):
+ pos = 0
+ while pos < len(st):
+ m = LEXER.match(st, pos)
+ if m is None:
+ line, ln, col = line_info(st, pos)
+ raise LexError("unrecognized character in <string>:%s,%s: %s" % (ln, col, line))
+ else:
+ idx = m.lastindex
+ t = Token(TYPES[idx - 1], m.group(idx))
+ yield t
+ pos = m.end()
+ yield Token(EOF, None)
+
+class ParseError(Exception): pass
+
+class Parser:
+
+ def __init__(self, tokens):
+ self.tokens = [t for t in tokens if t.type is not WSPACE]
+ self.idx = 0
+
+ def next(self):
+ return self.tokens[self.idx]
+
+ def matches(self, *types):
+ return self.next().type in types
+
+ def eat(self, *types):
+ if types and not self.matches(*types):
+ raise ParseError("expecting %s -- got %s" % (", ".join(map(str, types)), self.next()))
+ else:
+ t = self.next()
+ self.idx += 1
+ return t
+
+ def parse(self):
+ result = self.address()
+ self.eat(EOF)
+ return result
+
+ def address(self):
+ name = self.eat(ID).value
+ subject = None
+ options = None
+ if self.matches(SLASH):
+ self.eat(SLASH)
+ if self.matches(ID):
+ subject = self.eat(ID).value
+ else:
+ subject = ""
+ elif self.matches(LBRACE):
+ options = self.map()
+ return name, subject, options
+
+ def map(self):
+ self.eat(LBRACE)
+ result = {}
+ while True:
+ if self.matches(RBRACE):
+ self.eat(RBRACE)
+ break
+ else:
+ if self.matches(ID):
+ n, v = self.nameval()
+ result[n] = v
+ elif self.matches(COMMA):
+ self.eat(COMMA)
+ else:
+ raise ParseError("expecting (ID, COMMA), got %s" % self.next())
+ return result
+
+ def nameval(self):
+ name = self.eat(ID).value
+ self.eat(COLON)
+ val = self.value()
+ return (name, val)
+
+ def value(self):
+ if self.matches(NUMBER, STRING):
+ return eval(self.eat().value)
+ elif self.matches(ID):
+ return self.eat().value
+ elif self.matches(LBRACE):
+ return self.map()
+ else:
+ raise ParseError("expecting (NUMBER, STRING, LBRACE) got %s" % self.next())
+
+def parse(addr):
+ return Parser(lex(addr)).parse()
+
+__all__ = ["parse"]
diff --git a/qpid/python/qpid/compat.py b/qpid/python/qpid/compat.py
index 49273193df..53ab757e89 100644
--- a/qpid/python/qpid/compat.py
+++ b/qpid/python/qpid/compat.py
@@ -17,6 +17,8 @@
# under the License.
#
+import sys
+
try:
set = set
except NameError:
@@ -30,6 +32,13 @@ except ImportError:
try:
from traceback import format_exc
except ImportError:
- import sys, traceback
+ import traceback
def format_exc():
return "".join(traceback.format_exception(*sys.exc_info()))
+
+if tuple(sys.version_info[0:2]) < (2, 4):
+ from select import select as old_select
+ def select(rlist, wlist, xlist, timeout=None):
+ return old_select(list(rlist), list(wlist), list(xlist), timeout)
+else:
+ from select import select
diff --git a/qpid/python/qpid/driver.py b/qpid/python/qpid/driver.py
index 2e07c82a0d..7c293fe146 100644
--- a/qpid/python/qpid/driver.py
+++ b/qpid/python/qpid/driver.py
@@ -17,25 +17,23 @@
# under the License.
#
-import compat, connection, socket, sys, time
+import address, compat, connection, socket, struct, sys, time
from concurrency import synchronized
-from datatypes import RangedSet, Message as Message010
-from exceptions import Timeout
+from datatypes import RangedSet, Serial
+from exceptions import Timeout, VersionError
+from framing import OpEncoder, SegmentEncoder, FrameEncoder, FrameDecoder, SegmentDecoder, OpDecoder
from logging import getLogger
from messaging import get_codec, ConnectError, Message, Pattern, UNLIMITED
-from ops import delivery_mode
-from session import Client, INCOMPLETE, SessionDetached
+from ops import *
+from selector import Selector
from threading import Condition, Thread
from util import connect
log = getLogger("qpid.messaging")
-def parse_addr(address):
- parts = address.split("/", 1)
- if len(parts) == 1:
- return parts[0], None
- else:
- return parts[0], parts[i1]
+def addr2reply_to(addr):
+ name, subject, options = address.parse(addr)
+ return ReplyTo(name, subject)
def reply_to2addr(reply_to):
if reply_to.routing_key is None:
@@ -50,287 +48,617 @@ class Attachment:
def __init__(self, target):
self.target = target
+# XXX
+
DURABLE_DEFAULT=True
+# XXX
+
FILTER_DEFAULTS = {
"topic": Pattern("*")
}
-def delegate(handler, session):
- class Delegate(Client):
-
- def message_transfer(self, cmd):
- return handler._message_transfer(session, cmd)
- return Delegate
+# XXX
+
+CLIENT_PROPERTIES = {"product": "qpid python client",
+ "version": "development",
+ "platform": os.name,
+ "qpid.client_process": os.path.basename(sys.argv[0]),
+ "qpid.client_pid": os.getpid(),
+ "qpid.client_ppid": os.getppid()}
+
+def noop(): pass
+
+class SessionState:
+
+ def __init__(self, driver, session, name, channel):
+ self.driver = driver
+ self.session = session
+ self.name = name
+ self.channel = channel
+ self.detached = False
+ self.committing = False
+ self.aborting = False
+
+ # sender state
+ self.sent = Serial(0)
+ self.acknowledged = RangedSet()
+ self.completions = {}
+ self.min_completion = self.sent
+ self.max_completion = self.sent
+ self.results = {}
+
+ # receiver state
+ self.received = None
+ self.executed = RangedSet()
+
+ # XXX: need to periodically exchange completion/known_completion
+
+ def write_query(self, query, handler):
+ id = self.sent
+ query.sync = True
+ self.write_cmd(query, lambda: handler(self.results.pop(id)))
+
+ def write_cmd(self, cmd, completion=noop):
+ if self.detached:
+ raise Exception("detached")
+ cmd.id = self.sent
+ self.sent += 1
+ self.completions[cmd.id] = completion
+ self.max_completion = cmd.id
+ self.write_op(cmd)
+
+ def write_op(self, op):
+ op.channel = self.channel
+ self.driver.write_op(op)
+
+# XXX
+HEADER="!4s4B"
+
+EMPTY_DP = DeliveryProperties()
+EMPTY_MP = MessageProperties()
class Driver:
def __init__(self, connection):
self.connection = connection
self._lock = self.connection._lock
- self._wakeup_cond = Condition()
- self._socket = None
- self._conn = None
+
+ self._selector = Selector.default()
+ self.reset()
+
+ def reset(self):
+ self._opening = False
+ self._closing = False
self._connected = False
self._attachments = {}
- self._modcount = self.connection._modcount
- self.thread = Thread(target=self.run)
- self.thread.setDaemon(True)
- # XXX: need to figure out how to join on this thread
+ self._channel_max = 65536
+ self._channels = 0
+ self._sessions = {}
+
+ self._socket = None
+ self._buf = ""
+ self._hdr = ""
+ self._op_enc = OpEncoder()
+ self._seg_enc = SegmentEncoder()
+ self._frame_enc = FrameEncoder()
+ self._frame_dec = FrameDecoder()
+ self._seg_dec = SegmentDecoder()
+ self._op_dec = OpDecoder()
+ self._timeout = None
+
+ for ssn in self.connection.sessions.values():
+ for m in ssn.acked + ssn.unacked + ssn.incoming:
+ m._transfer_id = None
+ for snd in ssn.senders:
+ snd.linked = False
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+ rcv.linked = False
+
+ @synchronized
def wakeup(self):
- self._wakeup_cond.acquire()
- try:
- self._wakeup_cond.notifyAll()
- finally:
- self._wakeup_cond.release()
+ self.dispatch()
+ self._selector.wakeup()
def start(self):
- self.thread.start()
+ self._selector.register(self)
+
+ def fileno(self):
+ return self._socket.fileno()
- def run(self):
- while True:
- self._wakeup_cond.acquire()
+ @synchronized
+ def reading(self):
+ return self._socket is not None
+
+ @synchronized
+ def writing(self):
+ return self._socket is not None and self._buf
+
+ @synchronized
+ def timing(self):
+ return self._timeout
+
+ @synchronized
+ def readable(self):
+ error = None
+ recoverable = False
+ try:
+ data = self._socket.recv(64*1024)
+ if data:
+ log.debug("READ: %r", data)
+ else:
+ log.debug("ABORTED: %s", self._socket.getpeername())
+ error = "connection aborted"
+ recoverable = True
+ except socket.error, e:
+ error = e
+ recoverable = True
+
+ if not error:
try:
- if self.connection._modcount <= self._modcount:
- self._wakeup_cond.wait(10)
- finally:
- self._wakeup_cond.release()
- self.dispatch(self.connection._modcount)
+ if len(self._hdr) < 8:
+ r = 8 - len(self._hdr)
+ self._hdr += data[:r]
+ data = data[r:]
+
+ if len(self._hdr) == 8:
+ self.do_header(self._hdr)
+
+ self._frame_dec.write(data)
+ self._seg_dec.write(*self._frame_dec.read())
+ self._op_dec.write(*self._seg_dec.read())
+ for op in self._op_dec.read():
+ self.assign_id(op)
+ log.debug("RCVD: %r", op)
+ op.dispatch(self)
+ except VersionError, e:
+ error = e
+ except:
+ msg = compat.format_exc()
+ error = msg
+
+ if error:
+ self._error(error, recoverable)
+ else:
+ self.dispatch()
+
+ self.connection._waiter.notifyAll()
+
+ def assign_id(self, op):
+ if isinstance(op, Command):
+ sst = self.get_sst(op)
+ op.id = sst.received
+ sst.received += 1
@synchronized
- def dispatch(self, modcount):
+ def writeable(self):
try:
- if self._conn is None and self.connection._connected:
+ n = self._socket.send(self._buf)
+ log.debug("SENT: %r", self._buf[:n])
+ self._buf = self._buf[n:]
+ except socket.error, e:
+ self._error(e, True)
+ self.connection._waiter.notifyAll()
+
+ @synchronized
+ def timeout(self):
+ log.warn("retrying ...")
+ self.dispatch()
+ self.connection._waiter.notifyAll()
+
+ def _error(self, err, recoverable):
+ if self._socket is not None:
+ self._socket.close()
+ self.reset()
+ if recoverable and self.connection.reconnect:
+ self._timeout = time.time() + 3
+ log.warn("recoverable error: %s" % err)
+ log.warn("sleeping 3 seconds")
+ else:
+ self.connection.error = (err,)
+
+ def write_op(self, op):
+ log.debug("SENT: %r", op)
+ self._op_enc.write(op)
+ self._seg_enc.write(*self._op_enc.read())
+ self._frame_enc.write(*self._seg_enc.read())
+ self._buf += self._frame_enc.read()
+
+ def do_header(self, hdr):
+ cli_major = 0; cli_minor = 10
+ magic, _, _, major, minor = struct.unpack(HEADER, hdr)
+ if major != cli_major or minor != cli_minor:
+ raise VersionError("client: %s-%s, server: %s-%s" %
+ (cli_major, cli_minor, major, minor))
+
+ def do_connection_start(self, start):
+ # XXX: should we use some sort of callback for this?
+ r = "\0%s\0%s" % (self.connection.username, self.connection.password)
+ m = self.connection.mechanism
+ self.write_op(ConnectionStartOk(client_properties=CLIENT_PROPERTIES,
+ mechanism=m, response=r))
+
+ def do_connection_tune(self, tune):
+ # XXX: is heartbeat protocol specific?
+ if tune.channel_max is not None:
+ self.channel_max = tune.channel_max
+ self.write_op(ConnectionTuneOk(heartbeat=self.connection.heartbeat,
+ channel_max=self.channel_max))
+ self.write_op(ConnectionOpen())
+
+ def do_connection_open_ok(self, open_ok):
+ self._connected = True
+
+ def connection_heartbeat(self, hrt):
+ self.write_op(ConnectionHeartbeat())
+
+ def do_connection_close(self, close):
+ self.write_op(ConnectionCloseOk())
+ if close.reply_code != close_code.normal:
+ self.connection.error = (close.reply_code, close.reply_text)
+ # XXX: should we do a half shutdown on the socket here?
+ # XXX: we really need to test this, we may end up reporting a
+ # connection abort after this, if we were to do a shutdown on read
+ # and stop reading, then we wouldn't report the abort, that's
+ # probably the right thing to do
+
+ def do_connection_close_ok(self, close_ok):
+ self._socket.close()
+ self.reset()
+
+ def do_session_attached(self, atc):
+ pass
+
+ def do_session_command_point(self, cp):
+ sst = self.get_sst(cp)
+ sst.received = cp.command_id
+
+ def do_session_completed(self, sc):
+ sst = self.get_sst(sc)
+ for r in sc.commands:
+ sst.acknowledged.add(r.lower, r.upper)
+
+ if not sc.commands.empty():
+ while sst.min_completion in sc.commands:
+ if sst.completions.has_key(sst.min_completion):
+ sst.completions.pop(sst.min_completion)()
+ sst.min_completion += 1
+
+ def session_known_completed(self, kcmp):
+ sst = self.get_sst(kcmp)
+ executed = RangedSet()
+ for e in sst.executed.ranges:
+ for ke in kcmp.ranges:
+ if e.lower in ke and e.upper in ke:
+ break
+ else:
+ executed.add_range(e)
+ sst.executed = completed
+
+ def do_session_flush(self, sf):
+ sst = self.get_sst(sf)
+ if sf.expected:
+ if sst.received is None:
+ exp = None
+ else:
+ exp = RangedSet(sst.received)
+ sst.write_op(SessionExpected(exp))
+ if sf.confirmed:
+ sst.write_op(SessionConfirmed(sst.executed))
+ if sf.completed:
+ sst.write_op(SessionCompleted(sst.executed))
+
+ def do_execution_result(self, er):
+ sst = self.get_sst(er)
+ sst.results[er.command_id] = er.value
+
+ def do_execution_exception(self, ex):
+ sst = self.get_sst(ex)
+ sst.session.error = (ex,)
+
+ def dispatch(self):
+ try:
+ if self._socket is None and self.connection._connected and not self._opening:
self.connect()
- elif self._conn is not None and not self.connection._connected:
+ elif self._socket is not None and not self.connection._connected and not self._closing:
self.disconnect()
- if self._conn is not None:
+ if self._connected and not self._closing:
for ssn in self.connection.sessions.values():
self.attach(ssn)
self.process(ssn)
-
- exi = None
except:
- exi = sys.exc_info()
-
- if exi:
msg = compat.format_exc()
- recoverable = ["aborted", "Connection refused", "SessionDetached", "Connection reset by peer",
- "Bad file descriptor", "start timed out", "Broken pipe"]
- for r in recoverable:
- if self.connection.reconnect and r in msg:
- print "waiting to retry"
- self.reset()
- time.sleep(3)
- print "retrying..."
- return
- else:
- self.connection.error = (msg,)
-
- self._modcount = modcount
- self.connection._waiter.notifyAll()
+ self.connection.error = (msg,)
def connect(self):
- if self._conn is not None:
- return
try:
+ # XXX: should make this non blocking
self._socket = connect(self.connection.host, self.connection.port)
+ self._timeout = None
except socket.error, e:
- raise ConnectError(e)
- self._conn = connection.Connection(self._socket)
- try:
- self._conn.start(timeout=10)
- self._connected = True
- except connection.VersionError, e:
- raise ConnectError(e)
- except Timeout:
- print "start timed out"
- raise ConnectError("start timed out")
+ if self.connection.reconnect:
+ self._error(e, True)
+ return
+ else:
+ raise e
+ self._buf += struct.pack(HEADER, "AMQP", 1, 1, 0, 10)
+ self._opening = True
def disconnect(self):
- self._conn.close()
- self.reset()
-
- def reset(self):
- self._conn = None
- self._connected = False
- self._attachments.clear()
- for ssn in self.connection.sessions.values():
- for m in ssn.acked + ssn.unacked + ssn.incoming:
- m._transfer_id = None
- for rcv in ssn.receivers:
- rcv.impending = rcv.received
-
- def connected(self):
- return self._conn is not None
+ self.write_op(ConnectionClose(close_code.normal))
+ self._closing = True
def attach(self, ssn):
- _ssn = self._attachments.get(ssn)
- if _ssn is None:
- _ssn = self._conn.session(ssn.name, delegate=delegate(self, ssn))
- _ssn.auto_sync = False
- _ssn.invoke_lock = self._lock
- _ssn.lock = self._lock
- _ssn.condition = self.connection._condition
+ sst = self._attachments.get(ssn)
+ if sst is None and not ssn.closed:
+ for i in xrange(0, self.channel_max):
+ if not self._sessions.has_key(i):
+ ch = i
+ break
+ else:
+ raise RuntimeError("all channels used")
+ sst = SessionState(self, ssn, ssn.name, ch)
+ sst.write_op(SessionAttach(name=ssn.name))
+ sst.write_op(SessionCommandPoint(sst.sent, 0))
+ sst.outgoing_idx = 0
+ sst.acked = []
if ssn.transactional:
- # XXX: adding an attribute to qpid.session.Session
- _ssn.acked = []
- _ssn.tx_select()
- self._attachments[ssn] = _ssn
+ sst.write_cmd(TxSelect())
+ self._attachments[ssn] = sst
+ self._sessions[sst.channel] = sst
for snd in ssn.senders:
self.link_out(snd)
for rcv in ssn.receivers:
self.link_in(rcv)
- if ssn.closing:
- _ssn.close()
- del self._attachments[ssn]
- ssn.closed = True
+ if sst is not None and ssn.closing and not sst.detached:
+ sst.detached = True
+ sst.write_op(SessionDetach(name=ssn.name))
+
+ def get_sst(self, op):
+ return self._sessions[op.channel]
- def _exchange_query(self, ssn, address):
- # XXX: auto sync hack is to avoid deadlock on future
- result = ssn.exchange_query(name=address, sync=True)
- ssn.sync()
- return result.get()
+ def do_session_detached(self, dtc):
+ sst = self._sessions.pop(dtc.channel)
+ ssn = sst.session
+ del self._attachments[ssn]
+ ssn.closed = True
+
+ def do_session_detach(self, dtc):
+ sst = self.get_sst(dtc)
+ sst.write_op(SessionDetached(name=dtc.name))
+ self.do_session_detached(dtc)
def link_out(self, snd):
- _ssn = self._attachments[snd.session]
+ sst = self._attachments.get(snd.session)
_snd = self._attachments.get(snd)
- if _snd is None:
+ if _snd is None and not snd.closing and not snd.closed:
_snd = Attachment(snd)
- node, _snd._subject = parse_addr(snd.target)
- result = self._exchange_query(_ssn, node)
- if result.not_found:
- # XXX: should check 'create' option
- _ssn.queue_declare(queue=node, durable=DURABLE_DEFAULT, sync=True)
- _ssn.sync()
- _snd._exchange = ""
- _snd._routing_key = node
- else:
- _snd._exchange = node
- _snd._routing_key = _snd._subject
+
+ try:
+ _snd.name, _snd.subject, _snd.options = address.parse(snd.target)
+ except address.LexError, e:
+ snd.error = e
+ snd.closed = True
+ return
+ except address.ParseError, e:
+ snd.error = e
+ snd.closed = True
+ return
+
+ # XXX: subject
+ if _snd.options is None:
+ _snd.options = {}
+
+ def do_link():
+ snd.linked = True
+
+ def do_queue_q(result):
+ if sst.detached:
+ return
+
+ if result.queue:
+ _snd._exchange = ""
+ _snd._routing_key = _snd.name
+ do_link()
+ else:
+ snd.error = ("no such queue: %s" % _snd.name,)
+ del self._attachments[snd]
+ snd.closed = True
+
+ def do_exchange_q(result):
+ if sst.detached:
+ return
+
+ if result.not_found:
+ if _snd.options.get("create") in ("always", "receiver"):
+ sst.write_cmd(QueueDeclare(queue=_snd.name, durable=DURABLE_DEFAULT))
+ _snd._exchange = ""
+ _snd._routing_key = _snd.name
+ else:
+ sst.write_query(QueueQuery(queue=_snd.name), do_queue_q)
+ return
+ else:
+ _snd._exchange = _snd.name
+ _snd._routing_key = _snd.subject
+ do_link()
+
+ sst.write_query(ExchangeQuery(name=_snd.name), do_exchange_q)
self._attachments[snd] = _snd
- if snd.closed:
+ if snd.closing and not snd.closed:
del self._attachments[snd]
- return None
- else:
- return _snd
+ snd.closed = True
def link_in(self, rcv):
- _ssn = self._attachments[rcv.session]
+ sst = self._attachments.get(rcv.session)
_rcv = self._attachments.get(rcv)
- if _rcv is None:
+ if _rcv is None and not rcv.closing and not rcv.closed:
_rcv = Attachment(rcv)
- result = self._exchange_query(_ssn, rcv.source)
- if result.not_found:
- _rcv._queue = rcv.source
- # XXX: should check 'create' option
- _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT)
- else:
- _rcv._queue = "%s.%s" % (rcv.session.name, rcv.destination)
- _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True)
- if rcv.filter is None:
- f = FILTER_DEFAULTS[result.type]
+ _rcv.canceled = False
+ _rcv.draining = False
+
+ try:
+ _rcv.name, _rcv.subject, _rcv.options = address.parse(rcv.source)
+ except address.LexError, e:
+ rcv.error = e
+ rcv.closed = True
+ return
+ except address.ParseError, e:
+ rcv.error = e
+ rcv.closed = True
+ return
+
+ # XXX: subject
+ if _rcv.options is None:
+ _rcv.options = {}
+
+ def do_link():
+ sst.write_cmd(MessageSubscribe(queue=_rcv._queue, destination=rcv.destination))
+ sst.write_cmd(MessageSetFlowMode(rcv.destination, flow_mode.credit))
+ rcv.linked = True
+
+ def do_queue_q(result):
+ if sst.detached:
+ return
+ if result.queue:
+ _rcv._queue = _rcv.name
+ do_link()
+ else:
+ rcv.error = ("no such queue: %s" % _rcv.name,)
+ del self._attachments[rcv]
+ rcv.closed = True
+
+ def do_exchange_q(result):
+ if sst.detached:
+ return
+ if result.not_found:
+ if _rcv.options.get("create") in ("always", "receiver"):
+ _rcv._queue = _rcv.name
+ sst.write_cmd(QueueDeclare(queue=_rcv._queue, durable=DURABLE_DEFAULT))
+ else:
+ sst.write_query(QueueQuery(queue=_rcv.name), do_queue_q)
+ return
else:
- f = rcv.filter
- f._bind(_ssn, rcv.source, _rcv._queue)
- _ssn.message_subscribe(queue=_rcv._queue, destination=rcv.destination)
- _ssn.message_set_flow_mode(rcv.destination, _ssn.flow_mode.credit, sync=True)
+ _rcv._queue = "%s.%s" % (rcv.session.name, rcv.destination)
+ sst.write_cmd(QueueDeclare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True))
+ filter = _rcv.options.get("filter")
+ if _rcv.subject is None and filter is None:
+ f = FILTER_DEFAULTS[result.type]
+ elif _rcv.subject and filter:
+ # XXX
+ raise Exception("can't supply both subject and filter")
+ elif _rcv.subject:
+ # XXX
+ from messaging import Pattern
+ f = Pattern(_rcv.subject)
+ else:
+ f = filter
+ f._bind(sst, _rcv.name, _rcv._queue)
+ do_link()
+ sst.write_query(ExchangeQuery(name=_rcv.name), do_exchange_q)
self._attachments[rcv] = _rcv
- # XXX: need to kill syncs
- _ssn.sync()
-
- if rcv.closing:
- _ssn.message_cancel(rcv.destination, sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- del self._attachments[rcv]
- rcv.closed = True
- return None
- else:
- return _rcv
+
+ if rcv.closing and not rcv.closed:
+ if rcv.linked:
+ if not _rcv.canceled:
+ def close_rcv():
+ del self._attachments[rcv]
+ rcv.closed = True
+ sst.write_cmd(MessageCancel(rcv.destination, sync=True), close_rcv)
+ _rcv.canceled = True
+ else:
+ rcv.closed = True
def process(self, ssn):
if ssn.closing: return
- _ssn = self._attachments[ssn]
+ sst = self._attachments[ssn]
- while ssn.outgoing:
- msg = ssn.outgoing[0]
+ while sst.outgoing_idx < len(ssn.outgoing):
+ msg = ssn.outgoing[sst.outgoing_idx]
snd = msg._sender
- self.send(snd, msg)
- ssn.outgoing.pop(0)
+ # XXX: should check for sender error here
+ _snd = self._attachments.get(snd)
+ if _snd and snd.linked:
+ self.send(snd, msg)
+ sst.outgoing_idx += 1
+ else:
+ break
for rcv in ssn.receivers:
self.process_receiver(rcv)
if ssn.acked:
- messages = ssn.acked[:]
- ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
- for range in ids:
- _ssn.receiver._completed.add_range(range)
- ch = _ssn.channel
- if ch is None:
- raise SessionDetached()
- ch.session_completed(_ssn.receiver._completed)
- _ssn.message_accept(ids, sync=True)
- # XXX: really need to make this async so that we don't give up the lock
- _ssn.sync()
-
- # XXX: we're ignoring acks that get lost when disconnected
- for m in messages:
- ssn.acked.remove(m)
- if ssn.transactional:
- _ssn.acked.append(m)
-
- if ssn.committing:
- _ssn.tx_commit(sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- del _ssn.acked[:]
- ssn.committing = False
- ssn.committed = True
- ssn.aborting = False
- ssn.aborted = False
-
- if ssn.aborting:
- for rcv in ssn.receivers:
- _ssn.message_stop(rcv.destination)
- _ssn.sync()
-
- messages = _ssn.acked + ssn.unacked + ssn.incoming
- ids = RangedSet(*[m._transfer_id for m in messages])
- for range in ids:
- _ssn.receiver._completed.add_range(range)
- _ssn.channel.session_completed(_ssn.receiver._completed)
- _ssn.message_release(ids)
- _ssn.tx_rollback(sync=True)
- _ssn.sync()
-
- del ssn.incoming[:]
- del ssn.unacked[:]
- del _ssn.acked[:]
+ messages = [m for m in ssn.acked if m not in sst.acked]
+ if messages:
+ # XXX: we're ignoring acks that get lost when disconnected,
+ # could we deal this via some message-id based purge?
+ ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
+ for range in ids:
+ sst.executed.add_range(range)
+ sst.write_op(SessionCompleted(sst.executed))
+ def ack_ack():
+ for m in messages:
+ ssn.acked.remove(m)
+ if not ssn.transactional:
+ sst.acked.remove(m)
+ sst.write_cmd(MessageAccept(ids, sync=True), ack_ack)
+ sst.acked.extend(messages)
+
+ if ssn.committing and not sst.committing:
+ def commit_ok():
+ del sst.acked[:]
+ ssn.committing = False
+ ssn.committed = True
+ ssn.aborting = False
+ ssn.aborted = False
+ sst.write_cmd(TxCommit(sync=True), commit_ok)
+ sst.committing = True
+
+ if ssn.aborting and not sst.aborting:
+ sst.aborting = True
+ def do_rb():
+ messages = sst.acked + ssn.unacked + ssn.incoming
+ ids = RangedSet(*[m._transfer_id for m in messages])
+ for range in ids:
+ sst.executed.add_range(range)
+ sst.write_op(SessionCompleted(sst.executed))
+ sst.write_cmd(MessageRelease(ids))
+ sst.write_cmd(TxRollback(sync=True), do_rb_ok)
+
+ def do_rb_ok():
+ del ssn.incoming[:]
+ del ssn.unacked[:]
+ del sst.acked[:]
+
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+ rcv.returned = rcv.received
+ # XXX: do we need to update granted here as well?
+
+ for rcv in ssn.receivers:
+ self.process_receiver(rcv)
+
+ ssn.aborting = False
+ ssn.aborted = True
+ ssn.committing = False
+ ssn.committed = False
+ sst.aborting = False
for rcv in ssn.receivers:
- rcv.impending = rcv.received
- rcv.returned = rcv.received
- # XXX: do we need to update granted here as well?
-
- for rcv in ssn.receivers:
- self.process_receiver(rcv)
-
- ssn.aborting = False
- ssn.aborted = True
- ssn.committing = False
- ssn.committed = False
+ sst.write_cmd(MessageStop(rcv.destination))
+ sst.write_cmd(ExecutionSync(sync=True), do_rb)
def grant(self, rcv):
- _ssn = self._attachments[rcv.session]
- _rcv = self.link_in(rcv)
+ sst = self._attachments[rcv.session]
+ _rcv = self._attachments.get(rcv)
+ if _rcv is None or not rcv.linked or _rcv.canceled or _rcv.draining:
+ return
if rcv.granted is UNLIMITED:
if rcv.impending is UNLIMITED:
@@ -343,30 +671,37 @@ class Driver:
delta = max(rcv.granted, rcv.received) - rcv.impending
if delta is UNLIMITED:
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, UNLIMITED.value)
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.byte, UNLIMITED.value))
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.message, UNLIMITED.value))
rcv.impending = UNLIMITED
elif delta > 0:
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, delta)
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.byte, UNLIMITED.value))
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.message, delta))
rcv.impending += delta
- elif delta < 0:
- if rcv.drain:
- _ssn.message_flush(rcv.destination, sync=True)
- else:
- _ssn.message_stop(rcv.destination, sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- rcv.impending = rcv.received
- self.grant(rcv)
+ elif delta < 0 and not rcv.draining:
+ _rcv.draining = True
+ def do_stop():
+ rcv.impending = rcv.received
+ _rcv.draining = False
+ self.grant(rcv)
+ sst.write_cmd(MessageStop(rcv.destination, sync=True), do_stop)
+
+ if rcv.draining:
+ def do_flush():
+ rcv.impending = rcv.received
+ rcv.granted = rcv.impending
+ _rcv.draining = False
+ rcv.draining = False
+ sst.write_cmd(MessageFlush(rcv.destination, sync=True), do_flush)
+
def process_receiver(self, rcv):
if rcv.closed: return
self.grant(rcv)
def send(self, snd, msg):
- _ssn = self._attachments[snd.session]
- _snd = self.link_out(snd)
+ sst = self._attachments[snd.session]
+ _snd = self._attachments[snd]
# XXX: what if subject is specified for a normal queue?
if _snd._routing_key is None:
@@ -375,16 +710,16 @@ class Driver:
rk = _snd._routing_key
# XXX: do we need to query to figure out how to create the reply-to interoperably?
if msg.reply_to:
- rt = _ssn.reply_to(*parse_addr(msg.reply_to))
+ rt = addr2reply_to(msg.reply_to)
else:
rt = None
- dp = _ssn.delivery_properties(routing_key=rk)
- mp = _ssn.message_properties(message_id=msg.id,
- user_id=msg.user_id,
- reply_to=rt,
- correlation_id=msg.correlation_id,
- content_type=msg.content_type,
- application_headers=msg.properties)
+ dp = DeliveryProperties(routing_key=rk)
+ mp = MessageProperties(message_id=msg.id,
+ user_id=msg.user_id,
+ reply_to=rt,
+ correlation_id=msg.correlation_id,
+ content_type=msg.content_type,
+ application_headers=msg.properties)
if msg.subject is not None:
if mp.application_headers is None:
mp.application_headers = {}
@@ -397,37 +732,42 @@ class Driver:
dp.delivery_mode = delivery_mode.persistent
enc, dec = get_codec(msg.content_type)
body = enc(msg.content)
- _ssn.message_transfer(destination=_snd._exchange,
- message=Message010(dp, mp, body),
- sync=True)
- log.debug("SENT [%s] %s", snd.session, msg)
- # XXX: really need to make this async so that we don't give up the lock
- _ssn.sync()
- # XXX: should we log the ack somehow too?
- snd.acked += 1
-
- @synchronized
- def _message_transfer(self, ssn, cmd):
- m = Message010(cmd.payload)
- m.headers = cmd.headers
- m.id = cmd.id
- msg = self._decode(m)
- rcv = ssn.receivers[int(cmd.destination)]
+ def msg_acked():
+ # XXX: should we log the ack somehow too?
+ snd.acked += 1
+ m = snd.session.outgoing.pop(0)
+ sst.outgoing_idx -= 1
+ assert msg == m
+ sst.write_cmd(MessageTransfer(destination=_snd._exchange, headers=(dp, mp),
+ payload=body, sync=True), msg_acked)
+
+ def do_message_transfer(self, xfr):
+ sst = self.get_sst(xfr)
+ ssn = sst.session
+
+ msg = self._decode(xfr)
+ rcv = ssn.receivers[int(xfr.destination)]
msg._receiver = rcv
if rcv.impending is not UNLIMITED:
- assert rcv.received < rcv.impending
+ assert rcv.received < rcv.impending, "%s, %s" % (rcv.received, rcv.impending)
rcv.received += 1
log.debug("RECV [%s] %s", ssn, msg)
ssn.incoming.append(msg)
self.connection._waiter.notifyAll()
- return INCOMPLETE
- def _decode(self, message):
- dp = message.get("delivery_properties")
- mp = message.get("message_properties")
+ def _decode(self, xfr):
+ dp = EMPTY_DP
+ mp = EMPTY_MP
+
+ for h in xfr.headers:
+ if isinstance(h, DeliveryProperties):
+ dp = h
+ elif isinstance(h, MessageProperties):
+ mp = h
+
ap = mp.application_headers
enc, dec = get_codec(mp.content_type)
- content = dec(message.body)
+ content = dec(xfr.payload)
msg = Message(content)
msg.id = mp.message_id
if ap is not None:
@@ -440,5 +780,5 @@ class Driver:
msg.durable = dp.delivery_mode == delivery_mode.persistent
msg.properties = mp.application_headers
msg.content_type = mp.content_type
- msg._transfer_id = message.id
+ msg._transfer_id = xfr.id
return msg
diff --git a/qpid/python/qpid/messaging.py b/qpid/python/qpid/messaging.py
index d755aa5054..3e3c8f36cb 100644
--- a/qpid/python/qpid/messaging.py
+++ b/qpid/python/qpid/messaging.py
@@ -77,7 +77,8 @@ class Connection:
"""
@static
- def open(host, port=None):
+ def open(host, port=None, username="guest", password="guest",
+ mechanism="PLAIN", heartbeat=None, **options):
"""
Creates an AMQP connection and connects it to the given host and port.
@@ -88,11 +89,12 @@ class Connection:
@rtype: Connection
@return: a connected Connection
"""
- conn = Connection(host, port)
+ conn = Connection(host, port, username, password, mechanism, heartbeat, **options)
conn.connect()
return conn
- def __init__(self, host, port=None):
+ def __init__(self, host, port=None, username="guest", password="guest",
+ mechanism="PLAIN", heartbeat=None, **options):
"""
Creates a connection. A newly created connection must be connected
with the Connection.connect() method before it can be started.
@@ -106,11 +108,16 @@ class Connection:
"""
self.host = host
self.port = default(port, AMQP_PORT)
+ self.username = username
+ self.password = password
+ self.mechanism = mechanism
+ self.heartbeat = heartbeat
+
self.started = False
self.id = str(uuid4())
self.session_counter = 0
self.sessions = {}
- self.reconnect = False
+ self.reconnect = options.get("reconnect", False)
self._connected = False
self._lock = RLock()
self._condition = Condition(self._lock)
@@ -230,9 +237,10 @@ class Pattern:
self.value = value
# XXX: this should become part of the driver
- def _bind(self, ssn, exchange, queue):
- ssn.exchange_bind(exchange=exchange, queue=queue,
- binding_key=self.value.replace("*", "#"))
+ def _bind(self, sst, exchange, queue):
+ from qpid.ops import ExchangeBind
+ sst.write_cmd(ExchangeBind(exchange=exchange, queue=queue,
+ binding_key=self.value.replace("*", "#")))
class SessionError(Exception):
pass
@@ -282,6 +290,7 @@ class Session:
# XXX: I hate this name.
self.ack_capacity = UNLIMITED
+ self.error = None
self.closing = False
self.closed = False
@@ -302,12 +311,16 @@ class Session:
def _check_error(self, exc=SessionError):
self.connection._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
def _ewait(self, predicate, timeout=None, exc=SessionError):
- return self.connection._ewait(predicate, timeout, exc)
+ result = self.connection._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
@synchronized
- def sender(self, target):
+ def sender(self, target, **options):
"""
Creates a L{Sender} that may be used to send L{Messages<Message>}
to the specified target.
@@ -317,7 +330,7 @@ class Session:
@rtype: Sender
@return: a new Sender for the specified target
"""
- sender = Sender(self, len(self.senders), target)
+ sender = Sender(self, len(self.senders), target, options)
self.senders.append(sender)
self._wakeup()
# XXX: because of the lack of waiting here we can end up getting
@@ -327,7 +340,7 @@ class Session:
return sender
@synchronized
- def receiver(self, source, filter=None):
+ def receiver(self, source, **options):
"""
Creates a receiver that may be used to actively fetch or to listen
for the arrival of L{Messages<Message>} from the specified source.
@@ -337,7 +350,7 @@ class Session:
@rtype: Receiver
@return: a new Receiver for the specified source
"""
- receiver = Receiver(self, len(self.receivers), source, filter,
+ receiver = Receiver(self, len(self.receivers), source, options,
self.started)
self.receivers.append(receiver)
self._wakeup()
@@ -368,8 +381,8 @@ class Session:
@synchronized
def _get(self, predicate, timeout=None):
- if self._wait(lambda: ((self._peek(predicate) is not None) or self.closing),
- timeout):
+ if self._ewait(lambda: ((self._peek(predicate) is not None) or self.closing),
+ timeout):
msg = self._pop(predicate)
if msg is not None:
msg._receiver.returned += 1
@@ -505,13 +518,18 @@ class Sender:
Sends outgoing messages.
"""
- def __init__(self, session, index, target):
+ def __init__(self, session, index, target, options):
self.session = session
self.index = index
self.target = target
- self.capacity = UNLIMITED
+ self.options = options
+ self.capacity = options.get("capacity", UNLIMITED)
+ self.durable = options.get("durable")
self.queued = Serial(0)
self.acked = Serial(0)
+ self.error = None
+ self.linked = False
+ self.closing = False
self.closed = False
self._lock = self.session._lock
@@ -520,9 +538,13 @@ class Sender:
def _check_error(self, exc=SendError):
self.session._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
def _ewait(self, predicate, timeout=None, exc=SendError):
- return self.session._ewait(predicate, timeout, exc)
+ result = self.session._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
@synchronized
def pending(self):
@@ -558,11 +580,16 @@ class Sender:
if not self.session.connection._connected or self.session.closing:
raise Disconnected()
+ self._ewait(lambda: self.linked)
+
if isinstance(object, Message):
message = object
else:
message = Message(object)
+ if message.durable is None:
+ message.durable = self.durable
+
if self.capacity is not UNLIMITED:
if self.capacity <= 0:
raise InsufficientCapacity("capacity = %s" % self.capacity)
@@ -573,15 +600,19 @@ class Sender:
message._sender = self
self.session.outgoing.append(message)
self.queued += 1
- mno = self.queued
self._wakeup()
if sync:
- self._ewait(lambda: self.acked >= mno)
+ self.sync()
assert message not in self.session.outgoing
@synchronized
+ def sync(self):
+ mno = self.queued
+ self._ewait(lambda: self.acked >= mno)
+
+ @synchronized
def close(self):
"""
Close the Sender.
@@ -609,21 +640,23 @@ class Receiver:
L{listen}.
"""
- def __init__(self, session, index, source, filter, started):
+ def __init__(self, session, index, source, options, started):
self.session = session
self.index = index
self.destination = str(self.index)
self.source = source
- self.filter = filter
+ self.options = options
self.started = started
- self.capacity = UNLIMITED
+ self.capacity = options.get("capacity", UNLIMITED)
self.granted = Serial(0)
- self.drain = False
+ self.draining = False
self.impending = Serial(0)
self.received = Serial(0)
self.returned = Serial(0)
+ self.error = None
+ self.linked = False
self.closing = False
self.closed = False
self.listener = None
@@ -634,9 +667,13 @@ class Receiver:
def _check_error(self, exc=ReceiveError):
self.session._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
def _ewait(self, predicate, timeout=None, exc=ReceiveError):
- return self.session._ewait(predicate, timeout, exc)
+ result = self.session._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
@synchronized
def pending(self):
@@ -680,17 +717,18 @@ class Receiver:
@type timeout: float
@param timeout: the time to wait for a message to be available
"""
+
+ self._ewait(lambda: self.linked)
+
if self._capacity() == 0:
self.granted = self.returned + 1
self._wakeup()
self._ewait(lambda: self.impending >= self.granted)
msg = self.session._get(self._pred, timeout=timeout)
if msg is None:
- self.drain = True
- self.granted = self.received
+ self.draining = True
self._wakeup()
- self._ewait(lambda: self.impending == self.received)
- self.drain = False
+ self._ewait(lambda: not self.draining)
self._grant()
self._wakeup()
msg = self.session._get(self._pred, timeout=0)
@@ -738,7 +776,7 @@ class Receiver:
self.closing = True
self._wakeup()
try:
- self._ewait(lambda: self.closed)
+ self.session._ewait(lambda: self.closed)
finally:
self.session.receivers.remove(self)
@@ -778,6 +816,8 @@ def get_type(content):
def get_codec(content_type):
return TYPE_CODEC[content_type]
+UNSPECIFIED = object()
+
class Message:
"""
@@ -802,7 +842,9 @@ class Message:
@ivar content: the message content
"""
- def __init__(self, content=None):
+ def __init__(self, content=None, content_type=UNSPECIFIED, id=None,
+ subject=None, to=None, user_id=None, reply_to=None,
+ correlation_id=None, durable=None, properties=None):
"""
Construct a new message with the supplied content. The
content-type of the message will be automatically inferred from
@@ -810,20 +852,44 @@ class Message:
@type content: str, unicode, buffer, dict, list
@param content: the message content
- """
- self.id = None
- self.subject = None
- self.user_id = None
- self.to = None
- self.reply_to = None
- self.correlation_id = None
- self.durable = False
- self.properties = {}
- self.content_type = get_type(content)
+
+ @type content_type: str
+ @param content_type: the content-type of the message
+ """
+ self.id = id
+ self.subject = subject
+ self.to = to
+ self.user_id = user_id
+ self.reply_to = reply_to
+ self.correlation_id = correlation_id
+ self.durable = durable
+ if properties is None:
+ self.properties = {}
+ else:
+ self.properties = properties
+ if content_type is UNSPECIFIED:
+ self.content_type = get_type(content)
+ else:
+ self.content_type = content_type
self.content = content
def __repr__(self):
- return "Message(%r)" % self.content
+ args = []
+ for name in ["id", "subject", "to", "user_id", "reply_to",
+ "correlation_id"]:
+ value = self.__dict__[name]
+ if value is not None: args.append("%s=%r" % (name, value))
+ for name in ["durable", "properties"]:
+ value = self.__dict__[name]
+ if value: args.append("%s=%r" % (name, value))
+ if self.content_type != get_type(self.content):
+ args.append("content_type=%r" % self.content_type)
+ 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)
__all__ = ["Connection", "Session", "Sender", "Receiver", "Pattern", "Message",
"ConnectionError", "ConnectError", "SessionError", "Disconnected",
diff --git a/qpid/python/qpid/ops.py b/qpid/python/qpid/ops.py
index 11e7d11fe9..277d059203 100644
--- a/qpid/python/qpid/ops.py
+++ b/qpid/python/qpid/ops.py
@@ -80,7 +80,7 @@ class Compound(object):
return "%s(%s)" % (self.__class__.__name__,
", ".join(["%s=%r" % (f.name, getattr(self, f.name))
for f in self.ARGS
- if getattr(self, f.name) is not f.default]))
+ if getattr(self, f.name) != f.default]))
class Command(Compound):
UNENCODED=[Field("channel", "uint16", 0),
@@ -209,8 +209,8 @@ def make(nd):
from qpid_config import amqp_spec as file
pclfile = "%s.ops.pcl" % file
-if False and (os.path.exists(pclfile) and
- os.path.getmtime(pclfile) > os.path.getmtime(file)):
+if os.path.exists(pclfile) and \
+ os.path.getmtime(pclfile) > os.path.getmtime(file):
f = open(pclfile, "read")
types = pickle.load(f)
f.close()
diff --git a/qpid/python/qpid/selector.py b/qpid/python/qpid/selector.py
new file mode 100644
index 0000000000..46052e1108
--- /dev/null
+++ b/qpid/python/qpid/selector.py
@@ -0,0 +1,156 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import atexit, os, time
+from compat import select, set
+from threading import Thread, Lock
+
+class Acceptor:
+
+ def __init__(self, sock, handler):
+ self.sock = sock
+ self.handler = handler
+
+ def fileno(self):
+ return self.sock.fileno()
+
+ def reading(self):
+ return True
+
+ def writing(self):
+ return False
+
+ def readable(self):
+ sock, addr = self.sock.accept()
+ self.handler(sock)
+
+class Sink:
+
+ def __init__(self, fd):
+ self.fd = fd
+
+ def fileno(self):
+ return self.fd
+
+ def reading(self):
+ return True
+
+ def readable(self):
+ os.read(self.fd, 65536)
+
+ def __repr__(self):
+ return "Sink(%r)" % self.fd
+
+class Selector:
+
+ lock = Lock()
+ DEFAULT = None
+
+ @staticmethod
+ def default():
+ Selector.lock.acquire()
+ try:
+ if Selector.DEFAULT is None:
+ sel = Selector()
+ atexit.register(sel.stop)
+ sel.start()
+ Selector.DEFAULT = sel
+ return Selector.DEFAULT
+ finally:
+ Selector.lock.release()
+
+ def __init__(self):
+ self.selectables = set()
+ self.reading = set()
+ self.writing = set()
+ self.wait_fd, self.wakeup_fd = os.pipe()
+ self.reading.add(Sink(self.wait_fd))
+ self.stopped = False
+ self.thread = None
+
+ def wakeup(self):
+ os.write(self.wakeup_fd, "\0")
+
+ def register(self, selectable):
+ self.selectables.add(selectable)
+ self.modify(selectable)
+
+ def _update(self, selectable):
+ if selectable.reading():
+ self.reading.add(selectable)
+ else:
+ self.reading.discard(selectable)
+ if selectable.writing():
+ self.writing.add(selectable)
+ else:
+ self.writing.discard(selectable)
+ return selectable.timing()
+
+ def modify(self, selectable):
+ self._update(selectable)
+ self.wakeup()
+
+ def unregister(self, selectable):
+ self.reading.discard(selectable)
+ self.writing.discard(selectable)
+ self.selectables.discard(selectable)
+ self.wakeup()
+
+ def start(self):
+ self.stopped = False
+ self.thread = Thread(target=self.run)
+ self.thread.setDaemon(True)
+ self.thread.start();
+
+ def run(self):
+ while not self.stopped:
+ wakeup = None
+ for sel in self.selectables.copy():
+ t = self._update(sel)
+ if t is not None:
+ if wakeup is None:
+ wakeup = t
+ else:
+ wakeup = min(wakeup, t)
+
+ if wakeup is None:
+ timeout = None
+ else:
+ timeout = max(0, wakeup - time.time())
+
+ rd, wr, ex = select(self.reading, self.writing, (), timeout)
+
+ for sel in wr:
+ if sel.writing():
+ sel.writeable()
+
+ for sel in rd:
+ if sel.reading():
+ sel.readable()
+
+ now = time.time()
+ for sel in self.selectables.copy():
+ w = sel.timing()
+ if w is not None and now > w:
+ sel.timeout()
+
+ def stop(self, timeout=None):
+ self.stopped = True
+ self.wakeup()
+ self.thread.join(timeout)
+ self.thread = None
diff --git a/qpid/python/qpid/tests/messaging.py b/qpid/python/qpid/tests/messaging.py
index 7623c1f93b..2e4c0ca1ab 100644
--- a/qpid/python/qpid/tests/messaging.py
+++ b/qpid/python/qpid/tests/messaging.py
@@ -24,7 +24,7 @@ import time
from qpid.tests import Test
from qpid.harness import Skipped
from qpid.messaging import Connection, ConnectError, Disconnected, Empty, \
- InsufficientCapacity, Message, UNLIMITED, uuid4
+ InsufficientCapacity, Message, ReceiveError, SendError, UNLIMITED, uuid4
from Queue import Queue, Empty as QueueEmpty
class Base(Test):
@@ -50,6 +50,8 @@ class Base(Test):
raise Skipped(e)
self.ssn = self.setup_session()
self.snd = self.setup_sender()
+ if self.snd is not None:
+ self.snd.durable = self.durable()
self.rcv = self.setup_receiver()
def teardown(self):
@@ -63,11 +65,12 @@ class Base(Test):
return "%s[%s, %s]" % (base, count, self.test_id)
def ping(self, ssn):
+ PING_Q = 'ping-queue {create: always}'
# send a message
- sender = ssn.sender("ping-queue")
+ sender = ssn.sender(PING_Q, durable=self.durable())
content = self.content("ping")
sender.send(content)
- receiver = ssn.receiver("ping-queue")
+ receiver = ssn.receiver(PING_Q)
msg = receiver.fetch(0)
ssn.acknowledge()
assert msg.content == content, "expected %r, got %r" % (content, msg.content)
@@ -97,16 +100,27 @@ class Base(Test):
def delay(self):
return float(self.config.defines.get("delay", "2"))
+ def get_bool(self, name):
+ return self.config.defines.get(name, "false").lower() in ("true", "yes", "1")
+
+ def durable(self):
+ return self.get_bool("durable")
+
+ def reconnect(self):
+ return self.get_bool("reconnect")
+
class SetupTests(Base):
def testOpen(self):
# XXX: need to flesh out URL support/syntax
- self.conn = Connection.open(self.broker.host, self.broker.port)
+ self.conn = Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
self.ping(self.conn.session())
def testConnect(self):
# XXX: need to flesh out URL support/syntax
- self.conn = Connection(self.broker.host, self.broker.port)
+ self.conn = Connection(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
self.conn.connect()
self.ping(self.conn.session())
@@ -121,7 +135,8 @@ class SetupTests(Base):
class ConnectionTests(Base):
def setup_connection(self):
- return Connection.open(self.broker.host, self.broker.port)
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
def testSessionAnon(self):
ssn1 = self.conn.session()
@@ -174,17 +189,21 @@ class ConnectionTests(Base):
self.conn.close()
assert not self.conn.connected()
+ACK_Q = 'test-ack-queue {create: always}'
+
class SessionTests(Base):
def setup_connection(self):
- return Connection.open(self.broker.host, self.broker.port)
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
def setup_session(self):
return self.conn.session()
def testSender(self):
- snd = self.ssn.sender("test-snd-queue")
- snd2 = self.ssn.sender(snd.target)
+ snd = self.ssn.sender('test-snd-queue {create: always}',
+ durable=self.durable())
+ snd2 = self.ssn.sender(snd.target, durable=self.durable())
assert snd is not snd2
snd2.close()
@@ -196,47 +215,49 @@ class SessionTests(Base):
self.ssn.acknowledge(msg)
def testReceiver(self):
- rcv = self.ssn.receiver("test-rcv-queue")
+ rcv = self.ssn.receiver('test-rcv-queue {create: always}')
rcv2 = self.ssn.receiver(rcv.source)
assert rcv is not rcv2
rcv2.close()
content = self.content("testReceiver")
- snd = self.ssn.sender(rcv.source)
+ snd = self.ssn.sender(rcv.source, durable=self.durable())
snd.send(content)
msg = rcv.fetch(0)
assert msg.content == content
self.ssn.acknowledge(msg)
def testStart(self):
- rcv = self.ssn.receiver("test-start-queue")
+ START_Q = 'test-start-queue {create: always}'
+ rcv = self.ssn.receiver(START_Q)
assert not rcv.started
self.ssn.start()
assert rcv.started
- rcv = self.ssn.receiver("test-start-queue")
+ rcv = self.ssn.receiver(START_Q)
assert rcv.started
def testStop(self):
+ STOP_Q = 'test-stop-queue {create: always}'
self.ssn.start()
- rcv = self.ssn.receiver("test-stop-queue")
+ rcv = self.ssn.receiver(STOP_Q)
assert rcv.started
self.ssn.stop()
assert not rcv.started
- rcv = self.ssn.receiver("test-stop-queue")
+ rcv = self.ssn.receiver(STOP_Q)
assert not rcv.started
# XXX, we need a convenient way to assert that required queues are
# empty on setup, and possibly also to drain queues on teardown
def ackTest(self, acker, ack_capacity=None):
# send a bunch of messages
- snd = self.ssn.sender("test-ack-queue")
+ snd = self.ssn.sender(ACK_Q, durable=self.durable())
contents = [self.content("ackTest", i) for i in range(15)]
for c in contents:
snd.send(c)
# drain the queue, verify the messages are there and then close
# without acking
- rcv = self.ssn.receiver(snd.target)
+ rcv = self.ssn.receiver(ACK_Q)
self.drain(rcv, expected=contents)
self.ssn.close()
@@ -245,7 +266,7 @@ class SessionTests(Base):
self.ssn = self.conn.session()
if ack_capacity is not None:
self.ssn.ack_capacity = ack_capacity
- rcv = self.ssn.receiver("test-ack-queue")
+ rcv = self.ssn.receiver(ACK_Q)
self.drain(rcv, expected=contents)
acker(self.ssn)
self.ssn.close()
@@ -253,7 +274,7 @@ class SessionTests(Base):
# drain the queue a final time and verify that the messages were
# dequeued
self.ssn = self.conn.session()
- rcv = self.ssn.receiver("test-ack-queue")
+ rcv = self.ssn.receiver(ACK_Q)
self.assertEmpty(rcv)
def testAcknowledge(self):
@@ -271,7 +292,7 @@ class SessionTests(Base):
pass
finally:
self.ssn.ack_capacity = UNLIMITED
- self.drain(self.ssn.receiver("test-ack-queue"))
+ self.drain(self.ssn.receiver(ACK_Q))
self.ssn.acknowledge()
def testAcknowledgeAsyncAckCap1(self):
@@ -284,7 +305,7 @@ class SessionTests(Base):
self.ackTest(lambda ssn: ssn.acknowledge(sync=False), UNLIMITED)
def send(self, ssn, queue, base, count=1):
- snd = ssn.sender(queue)
+ snd = ssn.sender(queue, durable=self.durable())
contents = []
for i in range(count):
c = self.content(base, i)
@@ -294,10 +315,12 @@ class SessionTests(Base):
return contents
def txTest(self, commit):
+ TX_Q = 'test-tx-queue {create: always}'
+ TX_Q_COPY = 'test-tx-queue-copy {create: always}'
txssn = self.conn.session(transactional=True)
- contents = self.send(self.ssn, "test-tx-queue", "txTest", 3)
- txrcv = txssn.receiver("test-tx-queue")
- txsnd = txssn.sender("test-tx-queue-copy")
+ contents = self.send(self.ssn, TX_Q, "txTest", 3)
+ txrcv = txssn.receiver(TX_Q)
+ txsnd = txssn.sender(TX_Q_COPY, durable=self.durable())
rcv = self.ssn.receiver(txrcv.source)
copy_rcv = self.ssn.receiver(txsnd.target)
self.assertEmpty(copy_rcv)
@@ -323,9 +346,10 @@ class SessionTests(Base):
self.txTest(False)
def txTestSend(self, commit):
+ TX_SEND_Q = 'test-tx-send-queue {create: always}'
txssn = self.conn.session(transactional=True)
- contents = self.send(txssn, "test-tx-send-queue", "txTestSend", 3)
- rcv = self.ssn.receiver("test-tx-send-queue")
+ contents = self.send(txssn, TX_SEND_Q, "txTestSend", 3)
+ rcv = self.ssn.receiver(TX_SEND_Q)
self.assertEmpty(rcv)
if commit:
@@ -345,10 +369,11 @@ class SessionTests(Base):
self.txTestSend(False)
def txTestAck(self, commit):
+ TX_ACK_Q = 'test-tx-ack-queue {create: always}'
txssn = self.conn.session(transactional=True)
- txrcv = txssn.receiver("test-tx-ack-queue")
+ txrcv = txssn.receiver(TX_ACK_Q)
self.assertEmpty(txrcv)
- contents = self.send(self.ssn, "test-tx-ack-queue", "txTestAck", 3)
+ contents = self.send(self.ssn, TX_ACK_Q, "txTestAck", 3)
assert contents == self.drain(txrcv)
if commit:
@@ -366,11 +391,11 @@ class SessionTests(Base):
txssn.close()
txssn = self.conn.session(transactional=True)
- txrcv = txssn.receiver("test-tx-ack-queue")
+ txrcv = txssn.receiver(TX_ACK_Q)
assert contents == self.drain(txrcv)
txssn.acknowledge()
txssn.commit()
- rcv = self.ssn.receiver("test-tx-ack-queue")
+ rcv = self.ssn.receiver(TX_ACK_Q)
self.assertEmpty(rcv)
txssn.close()
self.assertEmpty(rcv)
@@ -389,19 +414,22 @@ class SessionTests(Base):
except Disconnected:
pass
+RECEIVER_Q = 'test-receiver-queue {create: always}'
+
class ReceiverTests(Base):
def setup_connection(self):
- return Connection.open(self.broker.host, self.broker.port)
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
def setup_session(self):
return self.conn.session()
def setup_sender(self):
- return self.ssn.sender("test-receiver-queue")
+ return self.ssn.sender(RECEIVER_Q)
def setup_receiver(self):
- return self.ssn.receiver("test-receiver-queue")
+ return self.ssn.receiver(RECEIVER_Q)
def send(self, base, count = None):
content = self.content(base, count)
@@ -516,7 +544,7 @@ class ReceiverTests(Base):
self.assertPending(self.rcv, 5)
drained = self.drain(self.rcv)
- assert len(drained) == 10
+ assert len(drained) == 10, "%s, %s" % (len(drained), drained)
self.assertPending(self.rcv, 0)
self.ssn.acknowledge()
@@ -538,19 +566,81 @@ class ReceiverTests(Base):
# XXX: need testClose
+NOSUCH_Q = "this-queue-should-not-exist"
+UNPARSEABLE_ADDR = "{bad address}"
+UNLEXABLE_ADDR = "\0x0\0x1\0x2\0x3"
+
+class AddressErrorTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def sendErrorTest(self, addr, exc, check=lambda e: True):
+ snd = self.ssn.sender(addr, durable=self.durable())
+ try:
+ snd.send("hello")
+ assert False, "send succeeded"
+ except exc, e:
+ assert check(e), "unexpected error: %s" % e
+ snd.close()
+
+ def fetchErrorTest(self, addr, exc, check=lambda e: True):
+ rcv = self.ssn.receiver(addr)
+ try:
+ rcv.fetch(timeout=0)
+ assert False, "fetch succeeded"
+ except exc, e:
+ assert check(e), "unexpected error: %s" % e
+ rcv.close()
+
+ def testNoTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(NOSUCH_Q, SendError, lambda e: NOSUCH_Q in str(e))
+
+ def testNoSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(NOSUCH_Q, ReceiveError, lambda e: NOSUCH_Q in str(e))
+
+ def testUnparseableTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(UNPARSEABLE_ADDR, SendError,
+ lambda e: "expecting ID" in str(e))
+
+ def testUnparseableSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(UNPARSEABLE_ADDR, ReceiveError,
+ lambda e: "expecting ID" in str(e))
+
+ def testUnlexableTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(UNLEXABLE_ADDR, SendError,
+ lambda e: "unrecognized character" in str(e))
+
+ def testUnlexableSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(UNLEXABLE_ADDR, ReceiveError,
+ lambda e: "unrecognized character" in str(e))
+
+SENDER_Q = 'test-sender-q {create: always}'
+
class SenderTests(Base):
def setup_connection(self):
- return Connection.open(self.broker.host, self.broker.port)
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
def setup_session(self):
return self.conn.session()
def setup_sender(self):
- return self.ssn.sender("test-sender-queue")
+ return self.ssn.sender(SENDER_Q)
def setup_receiver(self):
- return self.ssn.receiver("test-sender-queue")
+ return self.ssn.receiver(SENDER_Q)
def checkContent(self, content):
self.snd.send(content)
@@ -611,6 +701,7 @@ class SenderTests(Base):
except InsufficientCapacity:
caught = True
break
+ self.snd.sync()
self.drain(self.rcv, expected=msgs)
self.ssn.acknowledge()
assert caught, "did not exceed capacity"
@@ -643,19 +734,22 @@ class MessageTests(Base):
m.content = u"<html/>"
assert m.content_type == "text/html; charset=utf8"
+ECHO_Q = 'test-message-echo-queue {create: always}'
+
class MessageEchoTests(Base):
def setup_connection(self):
- return Connection.open(self.broker.host, self.broker.port)
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
def setup_session(self):
return self.conn.session()
def setup_sender(self):
- return self.ssn.sender("test-message-echo-queue")
+ return self.ssn.sender(ECHO_Q)
def setup_receiver(self):
- return self.ssn.receiver("test-message-echo-queue")
+ return self.ssn.receiver(ECHO_Q)
def check(self, msg):
self.snd.send(msg)
diff --git a/qpid/review/changeLogToWiki.py b/qpid/review/changeLogToWiki.py
new file mode 100755
index 0000000000..4054b135df
--- /dev/null
+++ b/qpid/review/changeLogToWiki.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sys, re
+from popen2 import popen2, popen3
+from optparse import OptionParser
+from xml.dom.minidom import parse, parseString
+
+prereqs = ["tr", "svn", "xsltproc", "sed", "grep", "wget"]
+
+apacheSVN="https://svn.apache.org/repos/asf/qpid/trunk/qpid/java"
+
+svncmd = "svn log %s --xml -r %s:HEAD | tr '\\n\\r|' ' -' | xsltproc svnlog2wiki.xsl - | grep r | sed -e 's/^ *//' | sed -e 's/\\(QPID-[0-9]*\\)/\\[\\1 | https:\\/\\/issues.apache.org\\/jira\\/browse\\/\\1 \]/g'"
+
+
+def get_commits(revision):
+ (stdout, stdin) = popen2(svncmd % (options.repo,revision))
+ return add_jira_status(stdout.read())
+
+def add_jira_status(commits):
+ commit_lines = commits.split("\n")
+ new_commits = []
+ for commit in commit_lines:
+ if re.match(".*https://issues.apache.org/.*", commit):
+ jira = re.findall("QPID-[0-9]*", commit)[0]
+ jira_xml_url = "http://issues.apache.org/jira/si/jira.issueviews:issue-xml/%s/%s.xml" % (jira, jira)
+ (stdout, stdin) = popen2("wget -q -O - %s" % jira_xml_url)
+
+ jira_dom = parse(stdout)
+ status = jira_dom.getElementsByTagName("status")[0]
+ new_commits.append("%s %s | " % (commit, status.lastChild.data))
+ else:
+ new_commits.append(commit)
+
+ return "\n".join(new_commits)
+
+
+def main():
+ global options
+ parser = OptionParser()
+ parser.add_option("-r", "--revision", dest="revision", action="store",
+ type="string",
+ help="The first revision to generate logs for")
+
+ parser.add_option("-s", "--svn-repo", dest="repo", action="store",
+ default=apacheSVN,
+ type="string",
+ help="Provide a svn repository to process")
+
+
+ (options, args) = parser.parse_args()
+
+ # Check that we have what's necessary
+
+ notfound = re.compile('^which')
+ for cmd in prereqs:
+ (stdout, stdin, stderr) = popen3('which %s' % cmd)
+ if (notfound.match(stderr.read())):
+ parser.error ("Could not find command %s, try [apt-get|yum] install %s" %
+ (cmd, cmd))
+
+ if (options.revision == None):
+ parser.error("svn revision must be specified")
+
+ print(get_commits(options.revision))
+
+if __name__ == "__main__":
+ main()
diff --git a/qpid/wcf/ReadMe.txt b/qpid/wcf/ReadMe.txt
index 0ef3e06ce5..6f118ceac3 100644
--- a/qpid/wcf/ReadMe.txt
+++ b/qpid/wcf/ReadMe.txt
@@ -49,9 +49,9 @@ NOTE: In the following instructions %QPID_ROOT% refers to the root of
qpid source code location e.g. C:\trunk\qpid
5. Build Qpid cpp
-Run CMake and choose "%QPID_ROOT%\cpp\build" as the location for "Where to
-build the binaries". Build at least the "qpidd", "qpidclient" and
-"qpidcommon" projects.
+Build at least the "qpidd", "qpidclient" and "qpidcommon" projects.
+Create an environment variable called QPID_BUILD_ROOT and store the
+path to the Qpid build directory in it.
4. Building the solution file
@@ -81,7 +81,7 @@ System Development Edition, or Team System Team Suite SKU)
%QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional\RunTests.bat has the correct
values for the nunit_exe, qpid_dll_location and configuration_name variables as per
your installation.
-2. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+2. Start the qpid broker from the qpid build folder e.g. %QPID_BUILD_ROOT%\src\Debug.
3. Execute RunTests.bat from its location e.g. %QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional.
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
index b952faf9e5..b0b71c87f3 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
@@ -64,6 +64,12 @@ namespace Apache.Qpid.Channel
set { transport.BrokerPort = value; }
}
+ public int PrefetchLimit
+ {
+ get { return transport.PrefetchLimit; }
+ set { transport.PrefetchLimit = value; }
+ }
+
public bool Shared
{
get { return transport.Shared; }
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
index 3ec62e809d..554824cea9 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
@@ -63,6 +63,13 @@ namespace Apache.Qpid.Channel
set { brokerPort = value; }
}
+ [ConfigurationProperty(AmqpConfigurationStrings.PrefetchLimit, DefaultValue = false)]
+ public int PrefetchLimit
+ {
+ get { return (int)base[AmqpConfigurationStrings.PrefetchLimit]; }
+ set { base[AmqpConfigurationStrings.PrefetchLimit] = value; }
+ }
+
[ConfigurationProperty(AmqpConfigurationStrings.Shared, DefaultValue = false)]
public bool Shared
{
@@ -95,6 +102,8 @@ namespace Apache.Qpid.Channel
get
{
ConfigurationPropertyCollection properties = base.Properties;
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.PrefetchLimit,
+ typeof(int), 0, null, null, ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.Shared,
typeof(bool), false, null, null, ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.TransferMode,
@@ -112,6 +121,7 @@ namespace Apache.Qpid.Channel
this.BrokerPort = amqpBinding.BrokerPort;
this.TransferMode = amqpBinding.TransferMode;
this.Shared = amqpBinding.Shared;
+ this.PrefetchLimit = amqpBinding.PrefetchLimit;
AmqpProperties props = amqpBinding.DefaultMessageProperties;
}
@@ -133,6 +143,7 @@ namespace Apache.Qpid.Channel
amqpBinding.BrokerPort = this.BrokerPort;
amqpBinding.TransferMode = this.TransferMode;
amqpBinding.Shared = this.Shared;
+ amqpBinding.PrefetchLimit = this.PrefetchLimit;
}
protected override void PostDeserialize()
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
index b8e2811527..542f1a00a8 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
@@ -32,6 +32,7 @@ namespace Apache.Qpid.Channel
AmqpChannelProperties channelProperties;
long maxBufferPoolSize;
bool shared;
+ int prefetchLimit;
internal AmqpChannelFactory(AmqpTransportBindingElement bindingElement, BindingContext context)
: base(context.Binding)
@@ -39,6 +40,7 @@ namespace Apache.Qpid.Channel
this.bindingElement = bindingElement;
this.channelProperties = bindingElement.ChannelProperties.Clone();
this.shared = bindingElement.Shared;
+ this.prefetchLimit = bindingElement.PrefetchLimit;
this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
Collection<MessageEncodingBindingElement> messageEncoderBindingElements
= context.BindingParameters.FindAll<MessageEncodingBindingElement>();
@@ -91,7 +93,7 @@ namespace Apache.Qpid.Channel
protected override TChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
{
- return (TChannel)(object) new AmqpTransportChannel(this, this.channelProperties, remoteAddress, this.messageEncoderFactory.Encoder, this.maxBufferPoolSize, this.shared);
+ return (TChannel)(object) new AmqpTransportChannel(this, this.channelProperties, remoteAddress, this.messageEncoderFactory.Encoder, this.maxBufferPoolSize, this.shared, this.prefetchLimit);
}
}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
index f1de30406a..0853b3d6f3 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
@@ -46,6 +46,7 @@ namespace Apache.Qpid.Channel
public const string TransferMode = "transferMode";
public const string Brokers = "brokers";
public const string Shared = "shared";
+ public const string PrefetchLimit = "prefetchLimit";
public const string MaxBufferPoolSize = "maxBufferPoolSize";
public const string MaxReceivedMessageSize = "maxReceivedMessageSize";
}
@@ -55,7 +56,6 @@ namespace Apache.Qpid.Channel
internal const string BrokerHost = "localhost";
internal const int BrokerPort = 5672;
internal const TransferMode TransferMode = System.ServiceModel.TransferMode.Buffered;
- internal const byte Priority = 4;
internal const long MaxBufferPoolSize = 64 * 1024;
internal const int MaxReceivedMessageSize = 5 * 1024 * 1024; //64 * 1024;
}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
index 44fecdaf62..8894b68584 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
@@ -32,6 +32,7 @@ namespace Apache.Qpid.Channel
AmqpTransportBindingElement bindingElement;
AmqpChannelProperties channelProperties;
bool shared;
+ int prefetchLimit;
long maxBufferPoolSize;
Uri uri;
AmqpTransportChannel amqpTransportChannel;
@@ -45,6 +46,7 @@ namespace Apache.Qpid.Channel
this.bindingElement = bindingElement;
this.channelProperties = bindingElement.ChannelProperties.Clone();
this.shared = bindingElement.Shared;
+ this.prefetchLimit = bindingElement.PrefetchLimit;
this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
@@ -132,7 +134,7 @@ namespace Apache.Qpid.Channel
{
amqpTransportChannel = new AmqpTransportChannel(this, this.channelProperties,
new EndpointAddress(uri), messageEncoderFactory.Encoder,
- maxBufferPoolSize, this.shared);
+ maxBufferPoolSize, this.shared, this.prefetchLimit);
return (IInputChannel)(object) amqpTransportChannel;
}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
index f23b8072e9..08c565af18 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
@@ -29,6 +29,7 @@ namespace Apache.Qpid.Channel
{
AmqpChannelProperties channelProperties;
bool shared;
+ int prefetchLimit;
public AmqpTransportBindingElement()
{
@@ -41,6 +42,7 @@ namespace Apache.Qpid.Channel
{
this.channelProperties = other.channelProperties.Clone();
this.shared = other.shared;
+ this.prefetchLimit = other.prefetchLimit;
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
@@ -98,6 +100,12 @@ namespace Apache.Qpid.Channel
set { this.channelProperties.BrokerPort = value; }
}
+ public int PrefetchLimit
+ {
+ get { return this.prefetchLimit; }
+ set { this.prefetchLimit = value; }
+ }
+
public bool Shared
{
get { return this.shared; }
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
index ca9c10be69..5924142046 100644
--- a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
@@ -50,6 +50,7 @@ namespace Apache.Qpid.Channel
private MessageEncoder encoder;
private AmqpChannelProperties factoryChannelProperties;
private bool shared;
+ private int prefetchLimit;
private string encoderContentType;
// input = 0-10 queue, output = 0-10 exchange
@@ -68,7 +69,7 @@ namespace Apache.Qpid.Channel
private AsyncTimeSpanCaller asyncOpenCaller;
private AsyncTimeSpanCaller asyncCloseCaller;
- internal AmqpTransportChannel(ChannelManagerBase factory, AmqpChannelProperties channelProperties, EndpointAddress remoteAddress, MessageEncoder msgEncoder, long maxBufferPoolSize, bool sharedConnection)
+ internal AmqpTransportChannel(ChannelManagerBase factory, AmqpChannelProperties channelProperties, EndpointAddress remoteAddress, MessageEncoder msgEncoder, long maxBufferPoolSize, bool sharedConnection, int prefetchLimit)
: base(factory)
{
this.isInputChannel = (factory is ChannelListenerBase) || (factory is AmqpChannelFactory<IInputChannel>);
@@ -80,6 +81,7 @@ namespace Apache.Qpid.Channel
this.factoryChannelProperties = channelProperties;
this.shared = sharedConnection;
+ this.prefetchLimit = prefetchLimit;
this.remoteAddress = remoteAddress;
// pull out host, port, queue, and connection arguments
@@ -128,6 +130,7 @@ namespace Apache.Qpid.Channel
if (this.isInputChannel)
{
this.inputLink = ConnectionManager.GetInputLink(this.factoryChannelProperties, shared, false, this.queueName);
+ this.inputLink.PrefetchLimit = this.prefetchLimit;
}
else
{
@@ -287,7 +290,7 @@ namespace Apache.Qpid.Channel
return false;
}
-
+
public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
return this.inputLink.BeginTryReceive(timeout, callback, state);
@@ -464,7 +467,7 @@ namespace Apache.Qpid.Channel
}
return amqpMessage;
}
-
+
private Message QpidToWcf(AmqpMessage amqpMessage)
{
@@ -531,7 +534,7 @@ namespace Apache.Qpid.Channel
{
this.bufferManager.ReturnBuffer(managedBuffer);
}
- }
+ }
return wcfMessage;
}
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
index bab73da74e..425a592509 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
@@ -63,11 +63,12 @@ AmqpSession::AmqpSession(AmqpConnection^ conn, qpid::client::Connection* qpidCon
sessionp = new qpid::client::AsyncSession;
*sessionp = qpidConnectionp->newSession();
subs_mgrp = new SubscriptionManager (*sessionp);
- success = true;
waiters = gcnew Collections::Generic::List<CompletionWaiter^>();
+ success = true;
} finally {
if (!success) {
Cleanup();
+ // TODO: include inner exception information
throw gcnew QpidException ("session creation failure");
}
}
@@ -76,12 +77,6 @@ AmqpSession::AmqpSession(AmqpConnection^ conn, qpid::client::Connection* qpidCon
void AmqpSession::Cleanup()
{
- if (subscriptionp != NULL) {
- subscriptionp->cancel();
- delete subscriptionp;
- subscriptionp=NULL;
- }
-
if (subs_mgrp != NULL) {
subs_mgrp->stop();
delete subs_mgrp;
@@ -112,6 +107,7 @@ void AmqpSession::Cleanup()
void AmqpSession::ConnectionClosed()
{
+ lock l(waiters);
Cleanup();
}
@@ -283,5 +279,27 @@ void AmqpSession::asyncHelper(Object ^unused)
}
}
+bool AmqpSession::MessageStop(Completion &comp, std::string &name)
+{
+ lock l(waiters);
+
+ if (sessionp == NULL)
+ return false;
+
+ comp = sessionp->messageStop(name, true);
+ return true;
+}
+
+void AmqpSession::AcceptAndComplete(SequenceSet& transfers)
+{
+ lock l(waiters);
+
+ if (sessionp == NULL)
+ throw gcnew ObjectDisposedException("Accept");
+
+ sessionp->markCompleted(transfers, false);
+ sessionp->messageAccept(transfers, false);
+}
+
}}} // namespace Apache::Qpid::Cli
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h
index b959a4123a..8306cdf720 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h
@@ -44,7 +44,6 @@ private:
AsyncSession* sessionp;
SessionImpl* sessionImplp;
SubscriptionManager* subs_mgrp;
- Subscription* subscriptionp;
LocalQueue* localQueuep;
Collections::Generic::List<CompletionWaiter^>^ waiters;
bool helperRunning;
@@ -69,6 +68,8 @@ internal:
void ConnectionClosed();
void internalWaitForCompletion(IntPtr Future);
void removeWaiter(CompletionWaiter^ waiter);
+ bool MessageStop(Completion &comp, std::string &name);
+ void AcceptAndComplete(SequenceSet& transfers);
property AmqpConnection^ Connection {
AmqpConnection^ get () { return connection; }
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
index 197ac632b0..88880c3721 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
+++ b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
@@ -32,7 +32,6 @@ private:
bool timedOut;
// has an owner thread
bool assigned;
- // can Run (i.e. earlier CompletionWaiters in the queue have completed)
System::Exception^ runException;
AsyncCallback^ asyncCallback;
Threading::Timer ^timer;
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp
index cee394b05d..e12151d943 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp
+++ b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp
@@ -59,6 +59,12 @@ using namespace Apache::Qpid::AmqpTypes;
// with proposed changes to the native library to reduce the number of servicing
// threads for large numbers of subscriptions.
+// synchronization is accomplished with locks, but also by ensuring that only one
+// MessageWaiter (the one at the front of the line) is ever active.
+// async threads to watch for: Close/finalizer, Timers, SyncCredit and the native Dispatch
+// thread (who deposits FrameSets into the local queue and is oblivious to the
+// managed space locks).
+
// The folowing def must match the "Frames" private typedef.
// TODO, make Qpid-cpp "Frames" definition visible.
@@ -94,6 +100,8 @@ InputLink::InputLink(AmqpSession^ session, System::String^ sourceQueue,
localQueuep = new LocalQueue;
SubscriptionSettings settings;
settings.flowControl = FlowControl::messageCredit(0);
+ settings.completionMode = CompletionMode::MANUAL_COMPLETION;
+
Subscription sub = qpidSubsMgrp->subscribe(*localQueuep, qname, settings);
subscriptionp = new Subscription (sub); // copy smart pointer for later IDisposable cleanup
@@ -197,6 +205,7 @@ bool InputLink::haveMessage()
IntPtr InputLink::nextLocalMessage()
{
lock l(waiters);
+
if (disposed)
return (IntPtr) NULL;
@@ -279,8 +288,7 @@ bool InputLink::internalWaitForMessage()
if (haveMessage())
return true;
- // TODO: prefetch window of messages, compatible with both 0-10 and 1.0.
- subscriptionp->grantMessageCredit(1);
+ AdjustCredit();
// get a scoped smart ptr ref to guard against async close or hangup
demuxQueuePtr = *queuePtrp;
@@ -350,7 +358,12 @@ void InputLink::removeWaiter(MessageWaiter^ waiter) {
}
return;
}
+
waiters->RemoveAt(idx);
+ if (waiter->TimedOut) {
+ // may have to give back message if it arrives momentarily
+ AdjustCredit();
+ }
// let the next waiter know it's his turn.
if (waiters->Count > 0) {
@@ -411,6 +424,129 @@ void InputLink::sync()
}
+void InputLink::PrefetchLimit::set(int value)
+{
+ lock l(waiters);
+ prefetchLimit = value;
+
+ int delta = 0;
+
+ // rough rule of thumb to keep the flow, but reduce chatter.
+ // for small messages, the credit request is almost as expensive as the transfer itself.
+ // experience may suggest a better heuristic or require a property for the low water mark
+ if (prefetchLimit >= 3) {
+ delta = prefetchLimit / 3;
+ }
+ minWorkingCredit = prefetchLimit - delta;
+ AdjustCredit();
+}
+
+
+// call with lock held
+void InputLink::AdjustCredit()
+{
+ if (creditSyncPending || disposed)
+ return;
+
+ // low watermark check
+ if ((prefetchLimit != 0) &&
+ (workingCredit >= minWorkingCredit) &&
+ (workingCredit >= waiters->Count))
+ return;
+
+ // should have enough for all waiters or to satisfy the prefetch window
+ int targetCredit = waiters->Count;
+ if (targetCredit < prefetchLimit)
+ targetCredit = prefetchLimit;
+
+ if (targetCredit > workingCredit) {
+ subscriptionp->grantMessageCredit(targetCredit - workingCredit);
+ workingCredit = targetCredit;
+ return;
+ }
+ if (targetCredit < workingCredit) {
+ if ((targetCredit == 0) && (prefetchLimit == 0)) {
+ creditSyncPending = true;
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &InputLink::SyncCredit));
+ }
+ // TODO: also shrink credit when prefetchLimit != 0
+ }
+}
+
+void InputLink::SyncCredit(Object ^unused)
+{
+ lock l(waiters);
+
+ try {
+ if (disposed)
+ return;
+
+ Completion comp;
+ if (!amqpSession->MessageStop(comp, subscriptionp->getName())) {
+ // connection closed
+ return;
+ }
+
+ // get a private scoped copy to use outside the lock
+ Subscription s(*subscriptionp);
+
+ l.release();
+ // use setFlowControl to re-enable credit flow on the broker.
+ // previously used comp.wait() here, but setFlowControl is a sync operation
+ s.setFlowControl(s.getSettings().flowControl);
+ l.acquire();
+
+ if (disposed)
+ return;
+
+ // let existing waiters use up any
+ // local queue size can only decrease until more credit is issued
+ while (true) {
+ if ((waiters->Count > 0) && ((*queuePtrp)->size() > 0)) {
+ l.release();
+ // a rare use case and not used in performance oriented code.
+ // optimization can wait until the qpid/messaging api is used
+ Thread::Sleep(10);
+ l.acquire();
+ if (disposed)
+ return;
+ }
+ else {
+ break;
+ }
+ }
+
+ // At this point, the lock is held and we are fully synced with the broker
+ // so we have a valid snapshot
+
+ if ((prefetchLimit == 0) && ((*queuePtrp)->size() > 0)) {
+ // can't be sure application will request a message again any time soon
+ QpidFrameSetPtr frameSetp;
+ while (!(*queuePtrp)->empty()) {
+ (*queuePtrp)->pop(frameSetp);
+ SequenceSet frameSetID(frameSetp->getId());
+ subscriptionp->release(frameSetID);
+ }
+
+ // don't touch dequeuedFrameSetpp. It is spoken for: explicitely from a
+ // MessageWaiter about to to get the nextLocalMessage(), or implicitely
+ // from a WaitForMessage().
+ }
+ // TODO: if prefetchLimit != 0, release messages from back of the queue that exceed targetCredit
+
+ workingCredit = (*queuePtrp)->size();
+ if (dequeuedFrameSetpp != NULL) {
+ workingCredit++;
+ }
+ }
+ finally {
+ creditSyncPending = false;
+ }
+
+ AdjustCredit();
+}
+
+
AmqpMessage^ InputLink::createAmqpMessage(IntPtr msgp)
{
QpidFrameSetPtr* fspp = (QpidFrameSetPtr*) msgp.ToPointer();
@@ -539,7 +675,15 @@ AmqpMessage^ InputLink::createAmqpMessage(IntPtr msgp)
// We have a message we can return to the caller.
// Tell the broker we got it.
- subscriptionp->accept(frameSetID);
+
+ // subscriptionp->accept(frameSetID) is a slow sync operation in the native API
+ // so do it within the AsyncSession directly
+ amqpSession->AcceptAndComplete(frameSetID);
+
+ workingCredit--;
+ // check if more messages need to be requested from broker
+ AdjustCredit();
+
return amqpMessage;
}
finally {
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h
index 366780c137..f59a03a8c3 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h
+++ b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h
@@ -47,6 +47,14 @@ private:
bool finalizing;
QpidFrameSetPtr* dequeuedFrameSetpp;
ManualResetEvent^ asyncHelperWaitHandle;
+ // number of messages to buffer locally for future consumption
+ int prefetchLimit;
+ // the number of messages requested and not yet processed
+ int workingCredit;
+ // stopping and restarting the message flow
+ bool creditSyncPending;
+ // working credit low water mark
+ int minWorkingCredit;
void Cleanup();
void ReleaseNative();
@@ -54,6 +62,8 @@ private:
void addWaiter(MessageWaiter^ waiter);
void asyncHelper();
AmqpMessage^ createAmqpMessage(IntPtr msgp);
+ void AdjustCredit();
+ void SyncCredit(Object ^);
internal:
InputLink(AmqpSession^ session, System::String^ sourceQueue, qpid::client::AsyncSession *qpidSessionp,
@@ -80,6 +90,11 @@ public:
IAsyncResult^ BeginWaitForMessage(TimeSpan timeout, AsyncCallback^ callback, Object^ state);
bool EndWaitForMessage(IAsyncResult^ result);
+ property int PrefetchLimit {
+ int get () { return prefetchLimit; }
+ void set (int value);
+ }
+
};
}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj b/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj
index 32f78c8344..484f6898fb 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj
+++ b/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj
@@ -65,7 +65,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/FU Debug\Apache.Qpid.AmqpTypes.netmodule"
Optimization="0"
- AdditionalIncludeDirectories="..\..\..\..\..\cpp\build\include;..\..\..\..\..\cpp\build\src;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ AdditionalIncludeDirectories="&quot;$(QPID_BUILD_ROOT)\include&quot;;&quot;$(QPID_BUILD_ROOT)\src&quot;;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CRT_NONSTDC_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;_SCL_SECURE_NO_WARNINGS;BOOST_ALL_DYN_LINK"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
@@ -83,7 +83,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalOptions="..\..\..\..\..\cpp\build\src\Debug\qpidcommon.lib ..\..\..\..\..\cpp\build\src\Debug\qpidclient.lib Debug\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalOptions="$(QPID_BUILD_ROOT)\src\Debug\qpidcommond.lib $(QPID_BUILD_ROOT)\src\Debug\qpidclientd.lib Debug\Apache.Qpid.AmqpTypes.netmodule"
AdditionalDependencies="$(NoInherit)"
OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
LinkIncremental="2"
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
index 3eb4919646..3737430844 100644
--- a/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
+++ b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
@@ -66,7 +66,6 @@ private:
void Activate();
void WaitForCompletion();
-// inline void SetCompletedSynchronously (bool v) { completedSynchronously = v; }
property IntPtr Message {
IntPtr get () {
@@ -78,7 +77,6 @@ private:
GC::SuppressFinalize(this);
return v;
}
- // void set (IntPtr v) { message = v; }
}
property bool Assigned {
@@ -89,11 +87,11 @@ private:
bool get () { return timedOut; }
}
-
property System::Exception^ RunException {
System::Exception^ get() { return runException; }
}
+
public:
virtual property bool IsCompleted {
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
index 4b83993257..a5eed8839b 100755
--- a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
@@ -19,15 +19,15 @@ REM under the License.
set nunit_exe=%programfiles%\NUnit 2.5.1\bin\net-2.0\nunit-console.exe
-set qpid_dll_location=..\..\..\..\..\..\..\cpp\build\src\Debug
+set qpid_dll_location=%QPID_BUILD_ROOT%\src\Debug
set configuration_name=bin\Debug
set qcreate_location=..\..\..\..\..\..\tools\QCreate\Debug
-copy %qpid_dll_location%\qpidclient.dll %configuration_name%
-copy %qpid_dll_location%\qpidcommon.dll %configuration_name%
+copy %qpid_dll_location%\qpidclientd.dll %configuration_name%
+copy %qpid_dll_location%\qpidcommond.dll %configuration_name%
-copy %qpid_dll_location%\qpidclient.dll %qcreate_location%
-copy %qpid_dll_location%\qpidcommon.dll %qcreate_location%
+copy %qpid_dll_location%\qpidclientd.dll %qcreate_location%
+copy %qpid_dll_location%\qpidcommond.dll %qcreate_location%
%qcreate_location%\QCreate.exe amq.direct routing_key message_queue
diff --git a/qpid/wcf/tools/QCreate/QCreate.vcproj b/qpid/wcf/tools/QCreate/QCreate.vcproj
index e58077d78c..ba77952966 100644
--- a/qpid/wcf/tools/QCreate/QCreate.vcproj
+++ b/qpid/wcf/tools/QCreate/QCreate.vcproj
@@ -61,7 +61,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="&quot;$(BOOST_ROOT)\include\$(BOOST_VERSION)&quot;;&quot;$(BOOST_ROOT)\.&quot;;..\..\..\cpp\include;..\..\..\cpp\build\include"
+ AdditionalIncludeDirectories="&quot;$(BOOST_ROOT)\include\$(BOOST_VERSION)&quot;;&quot;$(BOOST_ROOT)\.&quot;;..\..\..\cpp\include;&quot;$(QPID_BUILD_ROOT)\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -81,9 +81,9 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
LinkIncremental="2"
- AdditionalLibraryDirectories=".;&quot;$(BOOST_ROOT)\lib&quot;;..\..\..\cpp\build\src\Debug"
+ AdditionalLibraryDirectories=".;&quot;$(BOOST_ROOT)\lib&quot;;&quot;$(QPID_BUILD_ROOT)\src\Debug&quot;"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"