summaryrefslogtreecommitdiff
path: root/qpid
diff options
context:
space:
mode:
Diffstat (limited to 'qpid')
-rw-r--r--qpid/QPID_VERSION.txt2
-rwxr-xr-xqpid/bin/release.sh34
-rw-r--r--qpid/cpp/bindings/qpid/Makefile.am2
-rw-r--r--qpid/cpp/bindings/qpid/perl/Makefile.am2
-rw-r--r--qpid/cpp/bindings/qpid/python/Makefile.am2
-rw-r--r--qpid/cpp/bindings/qpid/ruby/Makefile.am2
-rw-r--r--qpid/cpp/bld-winsdk.ps13
-rw-r--r--qpid/cpp/configure.ac17
-rw-r--r--qpid/cpp/examples/CMakeLists.txt13
-rw-r--r--qpid/cpp/examples/Makefile.am16
-rw-r--r--qpid/cpp/examples/examples.sln24
-rw-r--r--qpid/cpp/examples/messaging/server.cpp4
-rw-r--r--qpid/cpp/examples/old_api/CMakeLists.txt25
-rw-r--r--qpid/cpp/examples/old_api/Makefile.am48
-rw-r--r--qpid/cpp/examples/old_api/README.verify (renamed from qpid/cpp/examples/README.verify)0
-rw-r--r--qpid/cpp/examples/old_api/direct/CMakeLists.txt (renamed from qpid/cpp/examples/direct/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/direct/Makefile.am (renamed from qpid/cpp/examples/direct/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/direct/declare_queues.cpp (renamed from qpid/cpp/examples/direct/declare_queues.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/direct/direct_declare_queues.vcproj (renamed from qpid/cpp/examples/direct/direct_declare_queues.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/direct/direct_direct_producer.vcproj (renamed from qpid/cpp/examples/direct/direct_direct_producer.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/direct/direct_listener.vcproj (renamed from qpid/cpp/examples/direct/direct_listener.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/direct/direct_producer.cpp (renamed from qpid/cpp/examples/direct/direct_producer.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/direct/listener.cpp (renamed from qpid/cpp/examples/direct/listener.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/direct/verify (renamed from qpid/cpp/examples/direct/verify)0
-rw-r--r--qpid/cpp/examples/old_api/direct/verify.in (renamed from qpid/cpp/examples/direct/verify.in)0
-rw-r--r--qpid/cpp/examples/old_api/failover/CMakeLists.txt (renamed from qpid/cpp/examples/failover/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/failover/Makefile.am (renamed from qpid/cpp/examples/failover/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/failover/declare_queues.cpp (renamed from qpid/cpp/examples/failover/declare_queues.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/failover/failover_declare_queues.vcproj (renamed from qpid/cpp/examples/failover/failover_declare_queues.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/failover/failover_replaying_sender.vcproj (renamed from qpid/cpp/examples/failover/failover_replaying_sender.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/failover/failover_resuming_receiver.vcproj (renamed from qpid/cpp/examples/failover/failover_resuming_receiver.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/failover/replaying_sender.cpp (renamed from qpid/cpp/examples/failover/replaying_sender.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/failover/resuming_receiver.cpp (renamed from qpid/cpp/examples/failover/resuming_receiver.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/CMakeLists.txt (renamed from qpid/cpp/examples/fanout/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/Makefile.am (renamed from qpid/cpp/examples/fanout/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj (renamed from qpid/cpp/examples/fanout/fanout_fanout_producer.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/fanout_listener.vcproj (renamed from qpid/cpp/examples/fanout/fanout_listener.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/fanout_producer.cpp (renamed from qpid/cpp/examples/fanout/fanout_producer.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/listener.cpp (renamed from qpid/cpp/examples/fanout/listener.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/verify (renamed from qpid/cpp/examples/fanout/verify)0
-rw-r--r--qpid/cpp/examples/old_api/fanout/verify.in (renamed from qpid/cpp/examples/fanout/verify.in)0
-rw-r--r--qpid/cpp/examples/old_api/old-examples.sln (renamed from qpid/cpp/examples/old-examples.sln)24
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/CMakeLists.txt (renamed from qpid/cpp/examples/pub-sub/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/Makefile.am (renamed from qpid/cpp/examples/pub-sub/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj (renamed from qpid/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj (renamed from qpid/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/topic_listener.cpp (renamed from qpid/cpp/examples/pub-sub/topic_listener.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/topic_publisher.cpp (renamed from qpid/cpp/examples/pub-sub/topic_publisher.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/verify (renamed from qpid/cpp/examples/pub-sub/verify)0
-rw-r--r--qpid/cpp/examples/old_api/pub-sub/verify.in (renamed from qpid/cpp/examples/pub-sub/verify.in)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/CMakeLists.txt (renamed from qpid/cpp/examples/request-response/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/Makefile.am (renamed from qpid/cpp/examples/request-response/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/request-response/client.cpp (renamed from qpid/cpp/examples/request-response/client.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/request-response_client.vcproj (renamed from qpid/cpp/examples/request-response/request-response_client.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/request-response_server.vcproj (renamed from qpid/cpp/examples/request-response/request-response_server.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/server.cpp (renamed from qpid/cpp/examples/request-response/server.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/verify (renamed from qpid/cpp/examples/request-response/verify)0
-rw-r--r--qpid/cpp/examples/old_api/request-response/verify.in (renamed from qpid/cpp/examples/request-response/verify.in)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/CMakeLists.txt (renamed from qpid/cpp/examples/tradedemo/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/Makefile.am (renamed from qpid/cpp/examples/tradedemo/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/declare_queues.cpp (renamed from qpid/cpp/examples/tradedemo/declare_queues.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/topic_listener.cpp (renamed from qpid/cpp/examples/tradedemo/topic_listener.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/topic_publisher.cpp (renamed from qpid/cpp/examples/tradedemo/topic_publisher.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj (renamed from qpid/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj (renamed from qpid/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj)0
-rw-r--r--qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj (renamed from qpid/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj)0
-rwxr-xr-xqpid/cpp/examples/old_api/verify (renamed from qpid/cpp/examples/verify)0
-rwxr-xr-xqpid/cpp/examples/old_api/verify_all (renamed from qpid/cpp/examples/verify_all)2
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/CMakeLists.txt (renamed from qpid/cpp/examples/xml-exchange/CMakeLists.txt)0
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/Makefile.am (renamed from qpid/cpp/examples/xml-exchange/Makefile.am)2
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/README.txt (renamed from qpid/cpp/examples/xml-exchange/README.txt)0
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/declare_queues.cpp (renamed from qpid/cpp/examples/xml-exchange/declare_queues.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/listener.cpp (renamed from qpid/cpp/examples/xml-exchange/listener.cpp)0
-rw-r--r--qpid/cpp/examples/old_api/xml-exchange/xml_producer.cpp (renamed from qpid/cpp/examples/xml-exchange/xml_producer.cpp)0
-rw-r--r--qpid/cpp/include/qmf/AgentSession.h40
-rw-r--r--qpid/cpp/include/qmf/ConsoleSession.h48
-rw-r--r--qpid/cpp/include/qpid/types/Variant.h2
-rw-r--r--qpid/cpp/src/CMakeWinVersions.cmake12
-rw-r--r--qpid/cpp/src/qmf/AgentSession.cpp11
-rw-r--r--qpid/cpp/src/qmf/ConsoleSession.cpp28
-rw-r--r--qpid/cpp/src/qmf/ConsoleSessionImpl.h1
-rw-r--r--qpid/cpp/src/qpid/broker/AsyncCompletion.h63
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp23
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.h3
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp37
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.h7
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionState.h1
-rw-r--r--qpid/cpp/src/qpid/broker/DeliveryRecord.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.cpp9
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.h2
-rw-r--r--qpid/cpp/src/qpid/broker/Fairshare.cpp76
-rw-r--r--qpid/cpp/src/qpid/broker/Fairshare.h6
-rw-r--r--qpid/cpp/src/qpid/broker/Message.cpp5
-rw-r--r--qpid/cpp/src/qpid/broker/Message.h4
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.h11
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.cpp29
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.h24
-rw-r--r--qpid/cpp/src/qpid/broker/QueueFlowLimit.cpp15
-rw-r--r--qpid/cpp/src/qpid/broker/QueuePolicy.cpp5
-rw-r--r--qpid/cpp/src/qpid/broker/QueueRegistry.cpp20
-rw-r--r--qpid/cpp/src/qpid/broker/QueueRegistry.h7
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.cpp66
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.h2
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp14
-rw-r--r--qpid/cpp/src/qpid/broker/SessionState.cpp146
-rw-r--r--qpid/cpp/src/qpid/broker/SessionState.h112
-rw-r--r--qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp67
-rw-r--r--qpid/cpp/src/qpid/broker/ThresholdAlerts.h4
-rw-r--r--qpid/cpp/src/qpid/broker/TopicExchange.cpp19
-rw-r--r--qpid/cpp/src/qpid/broker/TopicExchange.h14
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.cpp48
-rw-r--r--qpid/cpp/src/qpid/client/TCPConnector.cpp2
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp124
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp4
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp3
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.cpp4
-rw-r--r--qpid/cpp/src/qpid/cluster/Connection.cpp36
-rw-r--r--qpid/cpp/src/qpid/cluster/Connection.h23
-rw-r--r--qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp17
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateDataExchange.cpp10
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateDataExchange.h2
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp16
-rw-r--r--qpid/cpp/src/qpid/sys/ClusterSafe.cpp10
-rw-r--r--qpid/cpp/src/qpid/sys/ClusterSafe.h18
-rw-r--r--qpid/cpp/src/qpid/sys/SslPlugin.cpp2
-rw-r--r--qpid/cpp/src/qpid/types/Variant.cpp3
-rw-r--r--qpid/cpp/src/tests/Makefile.am12
-rw-r--r--qpid/cpp/src/tests/MessageUtils.h14
-rw-r--r--qpid/cpp/src/tests/QueueTest.cpp10
-rwxr-xr-xqpid/cpp/src/tests/acl.py155
-rw-r--r--qpid/cpp/src/tests/brokertest.py231
-rwxr-xr-xqpid/cpp/src/tests/cli_tests.py24
-rwxr-xr-xqpid/cpp/src/tests/cluster_test_logs.py13
-rwxr-xr-xqpid/cpp/src/tests/cluster_tests.py104
-rwxr-xr-xqpid/cpp/src/tests/python_tests2
-rw-r--r--qpid/cpp/src/tests/qpid-perftest.cpp7
-rw-r--r--qpid/cpp/src/tests/qpid-receive.cpp5
-rw-r--r--qpid/cpp/src/tests/qrsh.cpp169
-rw-r--r--qpid/cpp/src/tests/qrsh_run.cpp321
-rw-r--r--qpid/cpp/src/tests/qrsh_server.cpp1068
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/2_forever26
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/4_wait_for_it26
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/5_exited64
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/6_get29
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/7_get_output44
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/8_any43
-rwxr-xr-xqpid/cpp/src/tests/qrsh_utils/9_alias38
-rw-r--r--qpid/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp52
-rw-r--r--qpid/cpp/src/tests/qrsh_utils/qrsh_forever.cpp50
-rw-r--r--qpid/cpp/src/tests/qrsh_utils/qsh_doc.txt309
-rw-r--r--qpid/cpp/src/tests/queue_flow_limit_tests.py3
-rwxr-xr-xqpid/cpp/src/tests/replication_test2
-rwxr-xr-xqpid/cpp/src/tests/run_acl_tests2
-rwxr-xr-xqpid/cpp/src/tests/run_cli_tests5
-rwxr-xr-xqpid/cpp/src/tests/run_federation_tests2
-rwxr-xr-xqpid/cpp/src/tests/run_header_test2
-rwxr-xr-xqpid/cpp/src/tests/run_test2
-rw-r--r--qpid/cpp/src/tests/sasl.mk15
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex284
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_dynamic27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_dynamic_cluster27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_link27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_link_cluster27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_queue27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_queue_cluster27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_route27
-rwxr-xr-xqpid/cpp/src/tests/sasl_fed_ex_route_cluster27
-rwxr-xr-xqpid/cpp/src/tests/ssl_test2
-rw-r--r--qpid/cpp/xml/cluster.xml1
-rw-r--r--qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml1
-rw-r--r--qpid/doc/book/src/AMQP-Messaging-Broker-CPP.xml3
-rw-r--r--qpid/doc/book/src/Cheat-Sheet-for-configuring-Queue-Options.xml10
-rw-r--r--qpid/doc/book/src/Programming-In-Apache-Qpid.xml41
-rw-r--r--qpid/doc/book/src/producer-flow-control.xml347
-rw-r--r--[-rwxr-xr-x]qpid/dotnet/Consumer/Program.cs (renamed from qpid/cpp/src/tests/qrsh_utils/3_kill_it)21
-rw-r--r--qpid/dotnet/Consumer/default.build47
-rw-r--r--[-rwxr-xr-x]qpid/dotnet/Producer/Program.cs (renamed from qpid/cpp/src/tests/qrsh_utils/10_all)24
-rw-r--r--qpid/dotnet/Producer/default.build47
-rw-r--r--[-rwxr-xr-x]qpid/dotnet/Program.cs (renamed from qpid/cpp/src/tests/qrsh_utils/1_remote_run)20
-rw-r--r--qpid/dotnet/Qpid.Client.Tests/interop/Consumer.cs56
-rw-r--r--qpid/dotnet/Qpid.Client.Tests/interop/Producer.cs55
-rw-r--r--qpid/dotnet/Qpid.Client.Tests/interop/TopicListener.cs18
-rw-r--r--qpid/dotnet/README.txt22
-rwxr-xr-xqpid/dotnet/build-mono2
-rwxr-xr-xqpid/dotnet/build-nant-release21
-rw-r--r--qpid/dotnet/default.build5
-rwxr-xr-xqpid/extras/qmf/setup.py4
-rw-r--r--qpid/extras/qmf/src/py/qmf/console.py17
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/__init__.py (renamed from qpid/extras/qmf/src/py/qmf2/__init__.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/agent.py (renamed from qpid/extras/qmf/src/py/qmf2/agent.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/common.py (renamed from qpid/extras/qmf/src/py/qmf2/common.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/console.py (renamed from qpid/extras/qmf/src/py/qmf2/console.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/__init__.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/__init__.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_discovery.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/agent_discovery.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_test.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/agent_test.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/async_method.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/async_method.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/async_query.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/async_query.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_method.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/basic_method.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_query.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/basic_query.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/console_test.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/console_test.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/events.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/events.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/multi_response.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/multi_response.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/obj_gets.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/obj_gets.py)0
-rw-r--r--qpid/extras/qmf/src/py/qmf2-prototype/tests/subscriptions.py (renamed from qpid/extras/qmf/src/py/qmf2/tests/subscriptions.py)0
-rwxr-xr-xqpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java70
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java57
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java30
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java20
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java15
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java81
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java37
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java117
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java113
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java156
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java163
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java118
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java120
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java103
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java26
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java5
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java59
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java7
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java32
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java115
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/stats/StatisticsCounterTest.java144
-rw-r--r--qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java2
-rw-r--r--qpid/java/build.xml4
-rw-r--r--qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java2
-rw-r--r--qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java2
-rwxr-xr-xqpid/java/client/src/main/java/client.bnd2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java15
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java6
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java38
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java64
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java55
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java3
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java17
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java25
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java87
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java16
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java3
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java22
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java15
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java52
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java52
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java31
-rw-r--r--qpid/java/common.xml2
-rwxr-xr-xqpid/java/common/src/main/java/common.bnd2
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java5
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java12
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java1
-rw-r--r--qpid/java/management/common/src/main/java/management-common.bnd2
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java118
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java121
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java121
-rw-r--r--qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF2
-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/jmx/JMXManagedObject.java29
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java25
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java2
-rw-r--r--qpid/java/module.xml9
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java26
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java102
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java177
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java110
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java90
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java233
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java128
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java193
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java22
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java104
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutConfigurationTest.java82
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java72
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java335
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java253
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java77
-rwxr-xr-xqpid/java/test-profiles/CPPExcludes5
-rwxr-xr-xqpid/java/test-profiles/Java010Excludes7
-rw-r--r--qpid/python/qpid/codec010.py17
-rw-r--r--qpid/python/qpid/messaging/endpoints.py2
-rw-r--r--qpid/python/qpid/tests/messaging/endpoints.py3
-rwxr-xr-xqpid/python/setup.py2
-rw-r--r--qpid/specs/management-schema.xml1
-rwxr-xr-xqpid/tests/setup.py2
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py125
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py4
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/extensions.py51
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/management.py67
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/message.py16
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/priority.py20
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/threshold.py15
-rwxr-xr-xqpid/tools/setup.py5
-rwxr-xr-xqpid/tools/src/py/qpid-config40
-rwxr-xr-xqpid/tools/src/py/qpid-printevents28
-rwxr-xr-xqpid/tools/src/py/qpid-route53
-rwxr-xr-xqpid/tools/src/py/qpid-tool19
316 files changed, 7116 insertions, 3723 deletions
diff --git a/qpid/QPID_VERSION.txt b/qpid/QPID_VERSION.txt
index b63ba696b7..51176c7c89 100644
--- a/qpid/QPID_VERSION.txt
+++ b/qpid/QPID_VERSION.txt
@@ -1 +1 @@
-0.9
+0.11
diff --git a/qpid/bin/release.sh b/qpid/bin/release.sh
index 31c12e630c..e323b40e51 100755
--- a/qpid/bin/release.sh
+++ b/qpid/bin/release.sh
@@ -41,6 +41,8 @@ usage()
echo "--ruby |-r : Generate the ruby artefacts"
echo "--python|-p : Generate the python artefacts"
echo "--wcf |-w : Generate the WCF artefacts"
+ echo "--tools |-t : Generate the tools artefacts"
+ echo "--qmf |-q : Generate the QMF artefacts"
echo "--source|-e : Generate the source artefact"
echo "--sign |-s : Sign generated artefacts"
echo "--upload|-u : Upload the artifacts directory to people.apache.org as qpid-\$VER"
@@ -79,6 +81,8 @@ for arg in $* ; do
RUBY="RUBY"
PYTHON="PYTHON"
WCF="WCF"
+ TOOLS="TOOLS"
+ QMF="QMF"
SOURCE="SOURCE"
;;
--cpp|-c)
@@ -99,6 +103,12 @@ for arg in $* ; do
--wcf|-w)
WCF="WCF"
;;
+ --tools|-t)
+ TOOLS="TOOLS"
+ ;;
+ --qmf|-q)
+ QMF="QMF"
+ ;;
--source|-e)
SOURCE="SOURCE"
;;
@@ -218,8 +228,8 @@ if [ "JAVA" == "$JAVA" ] ; then
cp qpid-${VER}/java/management/eclipse-plugin/release/*.tar.gz qpid-${VER}/java/management/eclipse-plugin/release/*.zip artifacts/
# copy the Maven artifacts
- cp qpid-${VER}/java/client/release/maven artifacts/
- cp qpid-${VER}/java/common/release/maven artifacts/
+ cp -a qpid-${VER}/java/client/release/maven artifacts/
+ cp -a qpid-${VER}/java/common/release/maven artifacts/
fi
if [ "DOTNET" == "$DOTNET" ] ; then
@@ -239,6 +249,26 @@ if [ "DOTNET" == "$DOTNET" ] ; then
cp qpid-${VER}/dotnet/client-010/bin/mono-2.0/debug/*.zip artifacts/qpid-dotnet-0-10-${VER}.zip
fi
+if [ "TOOLS" = "$TOOLS" ] ; then
+ pushd qpid-${VER}/tools
+
+ python setup.py sdist
+
+ popd
+
+ cp qpid-${VER}/tools/dist/*.tar.gz artifacts/qpid-tools-${VER}.tar.gz
+fi
+
+if [ "QMF" = "$QMF" ]; then
+ pushd qpid-${VER}/extras/qmf
+
+ python setup.py sdist
+
+ popd
+
+ cp qpid-${VER}/extras/qmf/dist/*.tar.gz artifacts/qpid-qmf-${VER}.tar.gz
+fi
+
if [ "SIGN" == "$SIGN" ] ; then
pushd artifacts
sha1sum *.zip *.gz *.svnversion > SHA1SUM
diff --git a/qpid/cpp/bindings/qpid/Makefile.am b/qpid/cpp/bindings/qpid/Makefile.am
index ca9eda0c73..31bce5d1d5 100644
--- a/qpid/cpp/bindings/qpid/Makefile.am
+++ b/qpid/cpp/bindings/qpid/Makefile.am
@@ -21,7 +21,7 @@ SUBDIRS = dotnet
if HAVE_SWIG
-EXTRA_DIST = qpid.i
+EXTRA_DIST = CMakeLists.txt qpid.i
if HAVE_RUBY_DEVEL
SUBDIRS += ruby
diff --git a/qpid/cpp/bindings/qpid/perl/Makefile.am b/qpid/cpp/bindings/qpid/perl/Makefile.am
index 13ab66f032..9e47786b8a 100644
--- a/qpid/cpp/bindings/qpid/perl/Makefile.am
+++ b/qpid/cpp/bindings/qpid/perl/Makefile.am
@@ -21,7 +21,7 @@ if HAVE_PERL_DEVEL
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC)
-EXTRA_DIST = perl.i
+EXTRA_DIST = CMakeLists.txt perl.i
BUILT_SOURCES = cqpid_perl.cpp
SWIG_FLAGS = -w362,401
diff --git a/qpid/cpp/bindings/qpid/python/Makefile.am b/qpid/cpp/bindings/qpid/python/Makefile.am
index 7fa4106be0..9aef179db7 100644
--- a/qpid/cpp/bindings/qpid/python/Makefile.am
+++ b/qpid/cpp/bindings/qpid/python/Makefile.am
@@ -25,7 +25,7 @@ generated_file_list = \
cqpid.cpp \
cqpid.py
-EXTRA_DIST = python.i
+EXTRA_DIST = CMakeLists.txt python.i
BUILT_SOURCES = $(generated_file_list)
SWIG_FLAGS = -w362,401
diff --git a/qpid/cpp/bindings/qpid/ruby/Makefile.am b/qpid/cpp/bindings/qpid/ruby/Makefile.am
index 67a3615362..34f9990574 100644
--- a/qpid/cpp/bindings/qpid/ruby/Makefile.am
+++ b/qpid/cpp/bindings/qpid/ruby/Makefile.am
@@ -21,7 +21,7 @@ if HAVE_RUBY_DEVEL
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src
-EXTRA_DIST = ruby.i
+EXTRA_DIST = CMakeLists.txt ruby.i
BUILT_SOURCES = cqpid.cpp
SWIG_FLAGS = -w362,401
diff --git a/qpid/cpp/bld-winsdk.ps1 b/qpid/cpp/bld-winsdk.ps1
index 8f0a5886dc..bea46da28f 100644
--- a/qpid/cpp/bld-winsdk.ps1
+++ b/qpid/cpp/bld-winsdk.ps1
@@ -186,9 +186,6 @@ function BuildAPlatform
'examples/qmf-console',
'examples/request-response',
'examples/tradedemo',
- 'examples/old-examples.sln',
- 'examples/README.*',
- 'examples/verify*',
'include',
'plugins')
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
index ea1a1b49ea..43a32d3ad7 100644
--- a/qpid/cpp/configure.ac
+++ b/qpid/cpp/configure.ac
@@ -521,18 +521,19 @@ AM_PATH_PYTHON()
builddir_lib_suffix="/.libs"
AC_SUBST([builddir_lib_suffix])
-# Files to generate
+# Files to generate
AC_CONFIG_FILES([
Makefile
examples/Makefile
- examples/direct/Makefile
- examples/fanout/Makefile
- examples/pub-sub/Makefile
- examples/request-response/Makefile
- examples/failover/Makefile
- examples/xml-exchange/Makefile
+ examples/old_api/Makefile
+ examples/old_api/direct/Makefile
+ examples/old_api/fanout/Makefile
+ examples/old_api/pub-sub/Makefile
+ examples/old_api/request-response/Makefile
+ examples/old_api/failover/Makefile
+ examples/old_api/xml-exchange/Makefile
examples/qmf-console/Makefile
- examples/tradedemo/Makefile
+ examples/old_api/tradedemo/Makefile
examples/messaging/Makefile
bindings/qpid/Makefile
bindings/qpid/ruby/Makefile
diff --git a/qpid/cpp/examples/CMakeLists.txt b/qpid/cpp/examples/CMakeLists.txt
index da8e39e944..1b28cfd031 100644
--- a/qpid/cpp/examples/CMakeLists.txt
+++ b/qpid/cpp/examples/CMakeLists.txt
@@ -77,25 +77,14 @@ macro(add_example subdir example)
endmacro(add_example)
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.txt
- ${CMAKE_CURRENT_SOURCE_DIR}/README.verify
- ${CMAKE_CURRENT_SOURCE_DIR}/verify
- ${CMAKE_CURRENT_SOURCE_DIR}/verify_all
DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
COMPONENT ${QPID_COMPONENT_EXAMPLES})
if (MSVC)
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/examples.sln
- ${CMAKE_CURRENT_SOURCE_DIR}/old-examples.sln
DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
COMPONENT ${QPID_COMPONENT_EXAMPLES})
endif (MSVC)
-add_subdirectory(direct)
-add_subdirectory(failover)
-add_subdirectory(fanout)
-add_subdirectory(pub-sub)
-#add_subdirectory(qmf-agent)
add_subdirectory(qmf-console)
-add_subdirectory(request-response)
-add_subdirectory(tradedemo)
-add_subdirectory(xml-exchange)
add_subdirectory(messaging)
+add_subdirectory(old_api)
diff --git a/qpid/cpp/examples/Makefile.am b/qpid/cpp/examples/Makefile.am
index c6cc308d98..6b2bb73587 100644
--- a/qpid/cpp/examples/Makefile.am
+++ b/qpid/cpp/examples/Makefile.am
@@ -16,15 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-SUBDIRS = direct fanout pub-sub request-response failover qmf-console tradedemo messaging
-if HAVE_XML
- SUBDIRS += xml-exchange
- broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so"
-endif
-if !HAVE_XML
- exclude_examples_regexp="xml" # Exclude XML examples.
- broker_args = "--no-module-dir --data-dir \"\" --auth no"
-endif
+SUBDIRS = qmf-console messaging old_api
MAKEDIST=.libs/Makefile
@@ -37,13 +29,9 @@ $(MAKEDIST): Makefile
examplesdir=$(pkgdatadir)/examples
dist_examples_DATA = README.txt $(MAKEDIST)
-EXTRA_DIST = README.verify verify verify_all examples.sln CMakeLists.txt
+EXTRA_DIST = examples.sln CMakeLists.txt
# For older versions of automake
abs_top_srcdir = @abs_top_srcdir@
abs_top_builddir = @abs_top_builddir@
-# Verify the examples in the buid tree.
-check-local:
- $(srcdir)/verify_all $(abs_top_srcdir)/.. $(abs_top_builddir) $(broker_args) $(exclude_examples_regexp)
-
diff --git a/qpid/cpp/examples/examples.sln b/qpid/cpp/examples/examples.sln
index 8511fe3cce..6f96105d97 100644
--- a/qpid/cpp/examples/examples.sln
+++ b/qpid/cpp/examples/examples.sln
@@ -32,6 +32,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_drain", "messagin
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_spout", "messaging\messaging_spout.vcproj", "{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_console", "qmf-console\qmf-console_console.vcproj", "{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_ping", "qmf-console\qmf-console_ping.vcproj", "{C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_printevents", "qmf-console\qmf-console_printevents.vcproj", "{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_queuestats", "qmf-console\qmf-console_queuestats.vcproj", "{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -88,6 +96,22 @@ Global
{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|Win32.Build.0 = Release|Win32
{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|x64.ActiveCfg = Release|x64
{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|x64.Build.0 = Release|x64
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.Build.0 = Debug|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.ActiveCfg = Release|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.Build.0 = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp
index ab72694c61..aa271d91f9 100644
--- a/qpid/cpp/examples/messaging/server.cpp
+++ b/qpid/cpp/examples/messaging/server.cpp
@@ -39,8 +39,8 @@ using std::string;
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
- std::string connectionOptions = argc > 3 ? argv[3] : "";
-
+ std::string connectionOptions = argc > 2 ? argv[2] : "";
+
Connection connection(url, connectionOptions);
try {
connection.open();
diff --git a/qpid/cpp/examples/old_api/CMakeLists.txt b/qpid/cpp/examples/old_api/CMakeLists.txt
new file mode 100644
index 0000000000..701f9be860
--- /dev/null
+++ b/qpid/cpp/examples/old_api/CMakeLists.txt
@@ -0,0 +1,25 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+add_subdirectory(direct)
+add_subdirectory(failover)
+add_subdirectory(fanout)
+add_subdirectory(pub-sub)
+add_subdirectory(request-response)
+add_subdirectory(tradedemo)
+add_subdirectory(xml-exchange)
diff --git a/qpid/cpp/examples/old_api/Makefile.am b/qpid/cpp/examples/old_api/Makefile.am
new file mode 100644
index 0000000000..466eee22e1
--- /dev/null
+++ b/qpid/cpp/examples/old_api/Makefile.am
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+SUBDIRS = direct pub-sub fanout request-response failover tradedemo
+if HAVE_XML
+ SUBDIRS += xml-exchange
+ broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so"
+endif
+if !HAVE_XML
+ exclude_examples_regexp="xml" # Exclude XML examples.
+ broker_args = "--no-module-dir --data-dir \"\" --auth no"
+endif
+
+MAKEDIST=.libs/Makefile
+
+$(MAKEDIST): Makefile
+ mkdir -p .libs
+ @(echo 'all clean:' ; \
+ echo ' for d in $(SUBDIRS) ; do $$(MAKE) -C $$$$d $$@ ; done' ; \
+ ) > $(MAKEDIST)
+
+examplesdir=$(pkgdatadir)/examples/old_api
+dist_examples_DATA = $(MAKEDIST)
+EXTRA_DIST = README.verify verify verify_all
+
+# For older versions of automake
+abs_top_srcdir = @abs_top_srcdir@
+abs_top_builddir = @abs_top_builddir@
+
+# Verify the examples in the buid tree.
+check-local:
+ $(srcdir)/verify_all $(abs_top_srcdir)/.. $(abs_top_builddir) $(broker_args) $(exclude_examples_regexp)
+
diff --git a/qpid/cpp/examples/README.verify b/qpid/cpp/examples/old_api/README.verify
index e1370764c9..e1370764c9 100644
--- a/qpid/cpp/examples/README.verify
+++ b/qpid/cpp/examples/old_api/README.verify
diff --git a/qpid/cpp/examples/direct/CMakeLists.txt b/qpid/cpp/examples/old_api/direct/CMakeLists.txt
index 2ec1b2b813..2ec1b2b813 100644
--- a/qpid/cpp/examples/direct/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/direct/CMakeLists.txt
diff --git a/qpid/cpp/examples/direct/Makefile.am b/qpid/cpp/examples/old_api/direct/Makefile.am
index b07db2cfd6..24f783fcc7 100644
--- a/qpid/cpp/examples/direct/Makefile.am
+++ b/qpid/cpp/examples/old_api/direct/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/direct
+examplesdir=$(pkgdatadir)/examples/old_api/direct
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/direct/declare_queues.cpp b/qpid/cpp/examples/old_api/direct/declare_queues.cpp
index 9a51d1982b..9a51d1982b 100644
--- a/qpid/cpp/examples/direct/declare_queues.cpp
+++ b/qpid/cpp/examples/old_api/direct/declare_queues.cpp
diff --git a/qpid/cpp/examples/direct/direct_declare_queues.vcproj b/qpid/cpp/examples/old_api/direct/direct_declare_queues.vcproj
index 083474b9ef..083474b9ef 100644
--- a/qpid/cpp/examples/direct/direct_declare_queues.vcproj
+++ b/qpid/cpp/examples/old_api/direct/direct_declare_queues.vcproj
diff --git a/qpid/cpp/examples/direct/direct_direct_producer.vcproj b/qpid/cpp/examples/old_api/direct/direct_direct_producer.vcproj
index f091fbf291..f091fbf291 100644
--- a/qpid/cpp/examples/direct/direct_direct_producer.vcproj
+++ b/qpid/cpp/examples/old_api/direct/direct_direct_producer.vcproj
diff --git a/qpid/cpp/examples/direct/direct_listener.vcproj b/qpid/cpp/examples/old_api/direct/direct_listener.vcproj
index dce1d3ec28..dce1d3ec28 100644
--- a/qpid/cpp/examples/direct/direct_listener.vcproj
+++ b/qpid/cpp/examples/old_api/direct/direct_listener.vcproj
diff --git a/qpid/cpp/examples/direct/direct_producer.cpp b/qpid/cpp/examples/old_api/direct/direct_producer.cpp
index ecc9675189..ecc9675189 100644
--- a/qpid/cpp/examples/direct/direct_producer.cpp
+++ b/qpid/cpp/examples/old_api/direct/direct_producer.cpp
diff --git a/qpid/cpp/examples/direct/listener.cpp b/qpid/cpp/examples/old_api/direct/listener.cpp
index 38bf24ec41..38bf24ec41 100644
--- a/qpid/cpp/examples/direct/listener.cpp
+++ b/qpid/cpp/examples/old_api/direct/listener.cpp
diff --git a/qpid/cpp/examples/direct/verify b/qpid/cpp/examples/old_api/direct/verify
index f598bacc1f..f598bacc1f 100644
--- a/qpid/cpp/examples/direct/verify
+++ b/qpid/cpp/examples/old_api/direct/verify
diff --git a/qpid/cpp/examples/direct/verify.in b/qpid/cpp/examples/old_api/direct/verify.in
index d1e95f1151..d1e95f1151 100644
--- a/qpid/cpp/examples/direct/verify.in
+++ b/qpid/cpp/examples/old_api/direct/verify.in
diff --git a/qpid/cpp/examples/failover/CMakeLists.txt b/qpid/cpp/examples/old_api/failover/CMakeLists.txt
index 05db8fad51..05db8fad51 100644
--- a/qpid/cpp/examples/failover/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/failover/CMakeLists.txt
diff --git a/qpid/cpp/examples/failover/Makefile.am b/qpid/cpp/examples/old_api/failover/Makefile.am
index 48846fdf79..8b1da80f2c 100644
--- a/qpid/cpp/examples/failover/Makefile.am
+++ b/qpid/cpp/examples/old_api/failover/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/failover
+examplesdir=$(pkgdatadir)/examples/old_api/failover
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/failover/declare_queues.cpp b/qpid/cpp/examples/old_api/failover/declare_queues.cpp
index a677870c53..a677870c53 100644
--- a/qpid/cpp/examples/failover/declare_queues.cpp
+++ b/qpid/cpp/examples/old_api/failover/declare_queues.cpp
diff --git a/qpid/cpp/examples/failover/failover_declare_queues.vcproj b/qpid/cpp/examples/old_api/failover/failover_declare_queues.vcproj
index c87c72affd..c87c72affd 100644
--- a/qpid/cpp/examples/failover/failover_declare_queues.vcproj
+++ b/qpid/cpp/examples/old_api/failover/failover_declare_queues.vcproj
diff --git a/qpid/cpp/examples/failover/failover_replaying_sender.vcproj b/qpid/cpp/examples/old_api/failover/failover_replaying_sender.vcproj
index 6d22fa6770..6d22fa6770 100644
--- a/qpid/cpp/examples/failover/failover_replaying_sender.vcproj
+++ b/qpid/cpp/examples/old_api/failover/failover_replaying_sender.vcproj
diff --git a/qpid/cpp/examples/failover/failover_resuming_receiver.vcproj b/qpid/cpp/examples/old_api/failover/failover_resuming_receiver.vcproj
index ba5061e248..ba5061e248 100644
--- a/qpid/cpp/examples/failover/failover_resuming_receiver.vcproj
+++ b/qpid/cpp/examples/old_api/failover/failover_resuming_receiver.vcproj
diff --git a/qpid/cpp/examples/failover/replaying_sender.cpp b/qpid/cpp/examples/old_api/failover/replaying_sender.cpp
index 22a7e1ebd3..22a7e1ebd3 100644
--- a/qpid/cpp/examples/failover/replaying_sender.cpp
+++ b/qpid/cpp/examples/old_api/failover/replaying_sender.cpp
diff --git a/qpid/cpp/examples/failover/resuming_receiver.cpp b/qpid/cpp/examples/old_api/failover/resuming_receiver.cpp
index d1886ce861..d1886ce861 100644
--- a/qpid/cpp/examples/failover/resuming_receiver.cpp
+++ b/qpid/cpp/examples/old_api/failover/resuming_receiver.cpp
diff --git a/qpid/cpp/examples/fanout/CMakeLists.txt b/qpid/cpp/examples/old_api/fanout/CMakeLists.txt
index 3f89d67650..3f89d67650 100644
--- a/qpid/cpp/examples/fanout/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/fanout/CMakeLists.txt
diff --git a/qpid/cpp/examples/fanout/Makefile.am b/qpid/cpp/examples/old_api/fanout/Makefile.am
index 6e2e821eae..3ab43b0279 100644
--- a/qpid/cpp/examples/fanout/Makefile.am
+++ b/qpid/cpp/examples/old_api/fanout/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/fanout
+examplesdir=$(pkgdatadir)/examples/old_api/fanout
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/fanout/fanout_fanout_producer.vcproj b/qpid/cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj
index daff5f3cf0..daff5f3cf0 100644
--- a/qpid/cpp/examples/fanout/fanout_fanout_producer.vcproj
+++ b/qpid/cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj
diff --git a/qpid/cpp/examples/fanout/fanout_listener.vcproj b/qpid/cpp/examples/old_api/fanout/fanout_listener.vcproj
index f0e91b7dc6..f0e91b7dc6 100644
--- a/qpid/cpp/examples/fanout/fanout_listener.vcproj
+++ b/qpid/cpp/examples/old_api/fanout/fanout_listener.vcproj
diff --git a/qpid/cpp/examples/fanout/fanout_producer.cpp b/qpid/cpp/examples/old_api/fanout/fanout_producer.cpp
index decd4d314d..decd4d314d 100644
--- a/qpid/cpp/examples/fanout/fanout_producer.cpp
+++ b/qpid/cpp/examples/old_api/fanout/fanout_producer.cpp
diff --git a/qpid/cpp/examples/fanout/listener.cpp b/qpid/cpp/examples/old_api/fanout/listener.cpp
index cd3071c29a..cd3071c29a 100644
--- a/qpid/cpp/examples/fanout/listener.cpp
+++ b/qpid/cpp/examples/old_api/fanout/listener.cpp
diff --git a/qpid/cpp/examples/fanout/verify b/qpid/cpp/examples/old_api/fanout/verify
index 2eaadff56b..2eaadff56b 100644
--- a/qpid/cpp/examples/fanout/verify
+++ b/qpid/cpp/examples/old_api/fanout/verify
diff --git a/qpid/cpp/examples/fanout/verify.in b/qpid/cpp/examples/old_api/fanout/verify.in
index 8f8612ce67..8f8612ce67 100644
--- a/qpid/cpp/examples/fanout/verify.in
+++ b/qpid/cpp/examples/old_api/fanout/verify.in
diff --git a/qpid/cpp/examples/old-examples.sln b/qpid/cpp/examples/old_api/old-examples.sln
index 7f2fa3e8b0..e6ec9a0d66 100644
--- a/qpid/cpp/examples/old-examples.sln
+++ b/qpid/cpp/examples/old_api/old-examples.sln
@@ -40,14 +40,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_listener", "p
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_publisher", "pub-sub\pub-sub_topic_publisher.vcproj", "{05158653-FECA-1BAD-A430-FD5330E23A2D}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_console", "qmf-console\qmf-console_console.vcproj", "{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_ping", "qmf-console\qmf-console_ping.vcproj", "{C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_printevents", "qmf-console\qmf-console_printevents.vcproj", "{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_queuestats", "qmf-console\qmf-console_queuestats.vcproj", "{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request_response_client", "request-response\request-response_client.vcproj", "{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request_response_server", "request-response\request-response_server.vcproj", "{46817425-FECA-1BAD-BD3A-8A467D0C5CCC}"
@@ -104,22 +96,6 @@ Global
{05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.Build.0 = Debug|Win32
{05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.ActiveCfg = Release|Win32
{05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.Build.0 = Release|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.ActiveCfg = Debug|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.Build.0 = Debug|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.ActiveCfg = Release|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.Build.0 = Release|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.ActiveCfg = Debug|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.Build.0 = Debug|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/qpid/cpp/examples/pub-sub/CMakeLists.txt b/qpid/cpp/examples/old_api/pub-sub/CMakeLists.txt
index 961de06d5a..961de06d5a 100644
--- a/qpid/cpp/examples/pub-sub/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/pub-sub/CMakeLists.txt
diff --git a/qpid/cpp/examples/pub-sub/Makefile.am b/qpid/cpp/examples/old_api/pub-sub/Makefile.am
index 62658ebe94..8f42ee0211 100644
--- a/qpid/cpp/examples/pub-sub/Makefile.am
+++ b/qpid/cpp/examples/old_api/pub-sub/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/pub-sub
+examplesdir=$(pkgdatadir)/examples/old_api/pub-sub
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj b/qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj
index aa0b3bcaa3..aa0b3bcaa3 100644
--- a/qpid/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj
+++ b/qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj
diff --git a/qpid/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj b/qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj
index 76e51df4df..76e51df4df 100644
--- a/qpid/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj
+++ b/qpid/cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj
diff --git a/qpid/cpp/examples/pub-sub/topic_listener.cpp b/qpid/cpp/examples/old_api/pub-sub/topic_listener.cpp
index d38a806303..d38a806303 100644
--- a/qpid/cpp/examples/pub-sub/topic_listener.cpp
+++ b/qpid/cpp/examples/old_api/pub-sub/topic_listener.cpp
diff --git a/qpid/cpp/examples/pub-sub/topic_publisher.cpp b/qpid/cpp/examples/old_api/pub-sub/topic_publisher.cpp
index aed5f8f033..aed5f8f033 100644
--- a/qpid/cpp/examples/pub-sub/topic_publisher.cpp
+++ b/qpid/cpp/examples/old_api/pub-sub/topic_publisher.cpp
diff --git a/qpid/cpp/examples/pub-sub/verify b/qpid/cpp/examples/old_api/pub-sub/verify
index 528d2f401e..528d2f401e 100644
--- a/qpid/cpp/examples/pub-sub/verify
+++ b/qpid/cpp/examples/old_api/pub-sub/verify
diff --git a/qpid/cpp/examples/pub-sub/verify.in b/qpid/cpp/examples/old_api/pub-sub/verify.in
index 6413c5c788..6413c5c788 100644
--- a/qpid/cpp/examples/pub-sub/verify.in
+++ b/qpid/cpp/examples/old_api/pub-sub/verify.in
diff --git a/qpid/cpp/examples/request-response/CMakeLists.txt b/qpid/cpp/examples/old_api/request-response/CMakeLists.txt
index 873a0cfa86..873a0cfa86 100644
--- a/qpid/cpp/examples/request-response/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/request-response/CMakeLists.txt
diff --git a/qpid/cpp/examples/request-response/Makefile.am b/qpid/cpp/examples/old_api/request-response/Makefile.am
index 48b3d989f0..f48762da51 100644
--- a/qpid/cpp/examples/request-response/Makefile.am
+++ b/qpid/cpp/examples/old_api/request-response/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/request-response
+examplesdir=$(pkgdatadir)/examples/old_api/request-response
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/request-response/client.cpp b/qpid/cpp/examples/old_api/request-response/client.cpp
index 679d1c5fc2..679d1c5fc2 100644
--- a/qpid/cpp/examples/request-response/client.cpp
+++ b/qpid/cpp/examples/old_api/request-response/client.cpp
diff --git a/qpid/cpp/examples/request-response/request-response_client.vcproj b/qpid/cpp/examples/old_api/request-response/request-response_client.vcproj
index 5f9eadde36..5f9eadde36 100644
--- a/qpid/cpp/examples/request-response/request-response_client.vcproj
+++ b/qpid/cpp/examples/old_api/request-response/request-response_client.vcproj
diff --git a/qpid/cpp/examples/request-response/request-response_server.vcproj b/qpid/cpp/examples/old_api/request-response/request-response_server.vcproj
index 54352b9f46..54352b9f46 100644
--- a/qpid/cpp/examples/request-response/request-response_server.vcproj
+++ b/qpid/cpp/examples/old_api/request-response/request-response_server.vcproj
diff --git a/qpid/cpp/examples/request-response/server.cpp b/qpid/cpp/examples/old_api/request-response/server.cpp
index 65a4717b35..65a4717b35 100644
--- a/qpid/cpp/examples/request-response/server.cpp
+++ b/qpid/cpp/examples/old_api/request-response/server.cpp
diff --git a/qpid/cpp/examples/request-response/verify b/qpid/cpp/examples/old_api/request-response/verify
index dee82413e7..dee82413e7 100644
--- a/qpid/cpp/examples/request-response/verify
+++ b/qpid/cpp/examples/old_api/request-response/verify
diff --git a/qpid/cpp/examples/request-response/verify.in b/qpid/cpp/examples/old_api/request-response/verify.in
index 7925dc5671..7925dc5671 100644
--- a/qpid/cpp/examples/request-response/verify.in
+++ b/qpid/cpp/examples/old_api/request-response/verify.in
diff --git a/qpid/cpp/examples/tradedemo/CMakeLists.txt b/qpid/cpp/examples/old_api/tradedemo/CMakeLists.txt
index e61fc1467d..e61fc1467d 100644
--- a/qpid/cpp/examples/tradedemo/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/tradedemo/CMakeLists.txt
diff --git a/qpid/cpp/examples/tradedemo/Makefile.am b/qpid/cpp/examples/old_api/tradedemo/Makefile.am
index f4d8686d05..445b15b367 100644
--- a/qpid/cpp/examples/tradedemo/Makefile.am
+++ b/qpid/cpp/examples/old_api/tradedemo/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/tradedemo
+examplesdir=$(pkgdatadir)/examples/old_api/tradedemo
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/tradedemo/declare_queues.cpp b/qpid/cpp/examples/old_api/tradedemo/declare_queues.cpp
index b1f2cc3510..b1f2cc3510 100644
--- a/qpid/cpp/examples/tradedemo/declare_queues.cpp
+++ b/qpid/cpp/examples/old_api/tradedemo/declare_queues.cpp
diff --git a/qpid/cpp/examples/tradedemo/topic_listener.cpp b/qpid/cpp/examples/old_api/tradedemo/topic_listener.cpp
index c488e7fb69..c488e7fb69 100644
--- a/qpid/cpp/examples/tradedemo/topic_listener.cpp
+++ b/qpid/cpp/examples/old_api/tradedemo/topic_listener.cpp
diff --git a/qpid/cpp/examples/tradedemo/topic_publisher.cpp b/qpid/cpp/examples/old_api/tradedemo/topic_publisher.cpp
index e22c185bc7..e22c185bc7 100644
--- a/qpid/cpp/examples/tradedemo/topic_publisher.cpp
+++ b/qpid/cpp/examples/old_api/tradedemo/topic_publisher.cpp
diff --git a/qpid/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj b/qpid/cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj
index 34b5cb3b2b..34b5cb3b2b 100644
--- a/qpid/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj
+++ b/qpid/cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj
diff --git a/qpid/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj b/qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj
index 965be2e88b..965be2e88b 100644
--- a/qpid/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj
+++ b/qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj
diff --git a/qpid/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj b/qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj
index 77fd511e15..77fd511e15 100644
--- a/qpid/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj
+++ b/qpid/cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj
diff --git a/qpid/cpp/examples/verify b/qpid/cpp/examples/old_api/verify
index 9a1ed078d6..9a1ed078d6 100755
--- a/qpid/cpp/examples/verify
+++ b/qpid/cpp/examples/old_api/verify
diff --git a/qpid/cpp/examples/verify_all b/qpid/cpp/examples/old_api/verify_all
index cb4c5283fa..fbe51377b6 100755
--- a/qpid/cpp/examples/verify_all
+++ b/qpid/cpp/examples/old_api/verify_all
@@ -32,7 +32,7 @@ trap "$qpidd -q" exit
QPID_PORT=`$qpidd -dp0 $broker_args` || { echo "Can't run qpidd" ; exit 1; }
export QPID_PORT
-find="find $topsrcdir/cpp/examples"
+find="find $topsrcdir/cpp/examples/old_api"
find="$find -mindepth 2 -name verify"
all_examples=`$find`
diff --git a/qpid/cpp/examples/xml-exchange/CMakeLists.txt b/qpid/cpp/examples/old_api/xml-exchange/CMakeLists.txt
index 3fea47a208..3fea47a208 100644
--- a/qpid/cpp/examples/xml-exchange/CMakeLists.txt
+++ b/qpid/cpp/examples/old_api/xml-exchange/CMakeLists.txt
diff --git a/qpid/cpp/examples/xml-exchange/Makefile.am b/qpid/cpp/examples/old_api/xml-exchange/Makefile.am
index 9001e3fa61..3e1082cdb2 100644
--- a/qpid/cpp/examples/xml-exchange/Makefile.am
+++ b/qpid/cpp/examples/old_api/xml-exchange/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-examplesdir=$(pkgdatadir)/examples/xml-exchange
+examplesdir=$(pkgdatadir)/examples/old_api/xml-exchange
MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
diff --git a/qpid/cpp/examples/xml-exchange/README.txt b/qpid/cpp/examples/old_api/xml-exchange/README.txt
index 85caebe352..85caebe352 100644
--- a/qpid/cpp/examples/xml-exchange/README.txt
+++ b/qpid/cpp/examples/old_api/xml-exchange/README.txt
diff --git a/qpid/cpp/examples/xml-exchange/declare_queues.cpp b/qpid/cpp/examples/old_api/xml-exchange/declare_queues.cpp
index ad08642019..ad08642019 100644
--- a/qpid/cpp/examples/xml-exchange/declare_queues.cpp
+++ b/qpid/cpp/examples/old_api/xml-exchange/declare_queues.cpp
diff --git a/qpid/cpp/examples/xml-exchange/listener.cpp b/qpid/cpp/examples/old_api/xml-exchange/listener.cpp
index 11bcb9f669..11bcb9f669 100644
--- a/qpid/cpp/examples/xml-exchange/listener.cpp
+++ b/qpid/cpp/examples/old_api/xml-exchange/listener.cpp
diff --git a/qpid/cpp/examples/xml-exchange/xml_producer.cpp b/qpid/cpp/examples/old_api/xml-exchange/xml_producer.cpp
index af1a7e60c7..af1a7e60c7 100644
--- a/qpid/cpp/examples/xml-exchange/xml_producer.cpp
+++ b/qpid/cpp/examples/old_api/xml-exchange/xml_producer.cpp
diff --git a/qpid/cpp/include/qmf/AgentSession.h b/qpid/cpp/include/qmf/AgentSession.h
index 9e29d6b54b..39d921a8ec 100644
--- a/qpid/cpp/include/qmf/AgentSession.h
+++ b/qpid/cpp/include/qmf/AgentSession.h
@@ -72,14 +72,14 @@ namespace qmf {
* strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
* - If False: Operate more flexibly with regard to use of messaging facilities [default]
*/
- QMF_EXTERN AgentSession(qpid::messaging::Connection&, const std::string& options="");
+ QMF_EXTERN AgentSession(qpid::messaging::Connection& conn, const std::string& options="");
/**
* setDomain - Change the QMF domain that this agent will operate in. If this is not called,
* the domain will be "default". Agents in a domain can be seen only by consoles in the same domain.
* This must be called prior to opening the agent session.
*/
- QMF_EXTERN void setDomain(const std::string&);
+ QMF_EXTERN void setDomain(const std::string& domain);
/**
* Set identifying attributes of this agent.
@@ -88,16 +88,16 @@ namespace qmf {
* setInstance - Set the unique instance name (if not set, a UUID will be assigned)
* These must be called prior to opening the agent session.
*/
- QMF_EXTERN void setVendor(const std::string&);
- QMF_EXTERN void setProduct(const std::string&);
- QMF_EXTERN void setInstance(const std::string&);
+ QMF_EXTERN void setVendor(const std::string& vendor);
+ QMF_EXTERN void setProduct(const std::string& product);
+ QMF_EXTERN void setInstance(const std::string& instance);
/**
* setAttribute - Set an arbitrary attribute for this agent. The attributes are not used
* to uniquely identify the agent but can be used as a search criteria when looking for agents.
* This must be called prior to opening the agent session.
*/
- QMF_EXTERN void setAttribute(const std::string&, const qpid::types::Variant&);
+ QMF_EXTERN void setAttribute(const std::string& key, const qpid::types::Variant& value);
/**
* Get the identifying name of the agent.
@@ -119,13 +119,19 @@ namespace qmf {
* Get the next event from the agent session. Events represent actions that must be acted upon by the
* agent application. This method blocks for up to the timeout if there are no events to be handled.
* This method will typically be the focus of the agent application's main execution loop.
+ * If the timeout is set to Duration::IMMEDIATE, the call will not block.
*/
- QMF_EXTERN bool nextEvent(AgentEvent&, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER);
+ QMF_EXTERN bool nextEvent(AgentEvent& outEvent, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER);
+
+ /**
+ * Return the number of events pending for nextEvent. This method will never block.
+ */
+ QMF_EXTERN int pendingEvents() const;
/**
* Register a schema to be exposed by this agent.
*/
- QMF_EXTERN void registerSchema(Schema&);
+ QMF_EXTERN void registerSchema(Schema& schema);
/**
* Add data to be managed internally by the agent. If the option external:True is selected, this call
@@ -138,12 +144,12 @@ namespace qmf {
* across different sessions. If persistent, it is the agent application's
* responsibility to ensure the name is the same each time it is added.
*/
- QMF_EXTERN DataAddr addData(Data&, const std::string& name="", bool persistent=false);
+ QMF_EXTERN DataAddr addData(Data& data, const std::string& name="", bool persistent=false);
/**
* Delete data from internal agent management.
*/
- QMF_EXTERN void delData(const DataAddr&);
+ QMF_EXTERN void delData(const DataAddr& dataAddr);
/**
* The following methods are used to respond to events received in nextEvent.
@@ -155,13 +161,13 @@ namespace qmf {
* complete - Indicate that the response to a query is complete (external:True only)
* methodSuccess - Indicate the successful completion of a method call.
*/
- QMF_EXTERN void authAccept(AgentEvent&);
- QMF_EXTERN void authReject(AgentEvent&, const std::string& diag="");
- QMF_EXTERN void raiseException(AgentEvent&, const std::string&);
- QMF_EXTERN void raiseException(AgentEvent&, const Data&);
- QMF_EXTERN void response(AgentEvent&, const Data&);
- QMF_EXTERN void complete(AgentEvent&);
- QMF_EXTERN void methodSuccess(AgentEvent&);
+ QMF_EXTERN void authAccept(AgentEvent& event);
+ QMF_EXTERN void authReject(AgentEvent& event, const std::string& diag="");
+ QMF_EXTERN void raiseException(AgentEvent& event, const std::string& errorText);
+ QMF_EXTERN void raiseException(AgentEvent& event, const Data& errorData);
+ QMF_EXTERN void response(AgentEvent& event, const Data& responseData);
+ QMF_EXTERN void complete(AgentEvent& event);
+ QMF_EXTERN void methodSuccess(AgentEvent& event);
/**
* Raise an event to be sent into the QMF network.
diff --git a/qpid/cpp/include/qmf/ConsoleSession.h b/qpid/cpp/include/qmf/ConsoleSession.h
index 0c73e7a6db..896f8ffda7 100644
--- a/qpid/cpp/include/qmf/ConsoleSession.h
+++ b/qpid/cpp/include/qmf/ConsoleSession.h
@@ -62,14 +62,48 @@ namespace qmf {
* strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
* - If False: Operate more flexibly with regard to use of messaging facilities [default]
*/
- QMF_EXTERN ConsoleSession(qpid::messaging::Connection&, const std::string& options="");
- QMF_EXTERN void setDomain(const std::string&);
- QMF_EXTERN void setAgentFilter(const std::string&);
+ QMF_EXTERN ConsoleSession(qpid::messaging::Connection& conn, const std::string& options="");
+
+ /**
+ * setDomain - Change the QMF domain that this console will operate in. If this is not called,
+ * the domain will be "default". Agents in a domain can be seen only by consoles in the same domain.
+ * This must be called prior to opening the console session.
+ */
+ QMF_EXTERN void setDomain(const std::string& domain);
+ QMF_EXTERN void setAgentFilter(const std::string& filter);
+
+ /**
+ * Open the console session. After opening the session, the domain cannot be changed.
+ */
QMF_EXTERN void open();
+
+ /**
+ * Close the session. Once closed, the session no longer communicates on the messaging network.
+ */
QMF_EXTERN void close();
- QMF_EXTERN bool nextEvent(ConsoleEvent&, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER);
+
+ /**
+ * Get the next event from the console session. Events represent actions that must be acted upon by the
+ * console application. This method blocks for up to the timeout if there are no events to be handled.
+ * This method will typically be the focus of the console application's main execution loop.
+ * If the timeout is set to Duration::IMMEDIATE, the call will not block.
+ */
+ QMF_EXTERN bool nextEvent(ConsoleEvent& outEvent, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER);
+
+ /**
+ * Return the number of events pending for nextEvent. This method will never block.
+ */
+ QMF_EXTERN int pendingEvents() const;
+
+ /**
+ * getAgentCount, getAgent - Retrieve the set of agents that match the console session's agent filter.
+ */
QMF_EXTERN uint32_t getAgentCount() const;
- QMF_EXTERN Agent getAgent(uint32_t) const;
+ QMF_EXTERN Agent getAgent(uint32_t agentIndex) const;
+
+ /**
+ * Get the agent for the connected broker (i.e. the agent embedded in the broker to which we have a connection).
+ */
QMF_EXTERN Agent getConnectedBrokerAgent() const;
/**
@@ -79,8 +113,8 @@ namespace qmf {
* will involve all known agents. If agentFilter is non-empty, it will be applied only to the set of known
* agents. A subscription cannot be created that involves an agent not known by the session.
*/
- QMF_EXTERN Subscription subscribe(const Query&, const std::string& agentFilter = "", const std::string& options = "");
- QMF_EXTERN Subscription subscribe(const std::string&, const std::string& agentFilter = "", const std::string& options = "");
+ QMF_EXTERN Subscription subscribe(const Query& query, const std::string& agentFilter = "", const std::string& options = "");
+ QMF_EXTERN Subscription subscribe(const std::string& query, const std::string& agentFilter = "", const std::string& options = "");
#ifndef SWIG
private:
diff --git a/qpid/cpp/include/qpid/types/Variant.h b/qpid/cpp/include/qpid/types/Variant.h
index 9ae672b7c2..d9260133a7 100644
--- a/qpid/cpp/include/qpid/types/Variant.h
+++ b/qpid/cpp/include/qpid/types/Variant.h
@@ -60,6 +60,8 @@ enum VariantType {
VAR_UUID
};
+std::string getTypeName(VariantType type);
+
class VariantImpl;
/**
diff --git a/qpid/cpp/src/CMakeWinVersions.cmake b/qpid/cpp/src/CMakeWinVersions.cmake
index 9bffd2ba0e..0bac7cab47 100644
--- a/qpid/cpp/src/CMakeWinVersions.cmake
+++ b/qpid/cpp/src/CMakeWinVersions.cmake
@@ -34,11 +34,11 @@
# set ("winver_PACKAGE_NAME" "qpid-cpp")
# set ("winver_DESCRIPTION_SUMMARY" "Apache Qpid C++")
# set ("winver_FILE_VERSION_N1" "0")
-# set ("winver_FILE_VERSION_N2" "9")
+# set ("winver_FILE_VERSION_N2" "11")
# set ("winver_FILE_VERSION_N3" "0")
# set ("winver_FILE_VERSION_N4" "0")
# set ("winver_PRODUCT_VERSION_N1" "0")
-# set ("winver_PRODUCT_VERSION_N2" "9")
+# set ("winver_PRODUCT_VERSION_N2" "11")
# set ("winver_PRODUCT_VERSION_N3" "0")
# set ("winver_PRODUCT_VERSION_N4" "0")
# set ("winver_LEGAL_COPYRIGHT" "")
@@ -46,10 +46,10 @@
#
# Specification of per-project settings:
#
-# set ("winver_${projectName}_FileVersionBinary" "0,9,0,0")
-# set ("winver_${projectName}_ProductVersionBinary" "0,9,0,0")
-# set ("winver_${projectName}_FileVersionString" "0, 9, 0, 0")
-# set ("winver_${projectName}_ProductVersionString" "0, 9, 0, 0")
+# set ("winver_${projectName}_FileVersionBinary" "0,11,0,0")
+# set ("winver_${projectName}_ProductVersionBinary" "0,11,0,0")
+# set ("winver_${projectName}_FileVersionString" "0, 11, 0, 0")
+# set ("winver_${projectName}_ProductVersionString" "0, 11, 0, 0")
# set ("winver_${projectName}_FileDescription" "qpid-cpp-qpidcommon Library")
# set ("winver_${projectName}_LegalCopyright" "")
# set ("winver_${projectName}_InternalName" "qpidcommon")
diff --git a/qpid/cpp/src/qmf/AgentSession.cpp b/qpid/cpp/src/qmf/AgentSession.cpp
index 4c5a72a467..71d369325f 100644
--- a/qpid/cpp/src/qmf/AgentSession.cpp
+++ b/qpid/cpp/src/qmf/AgentSession.cpp
@@ -72,6 +72,7 @@ namespace qmf {
void open();
void close();
bool nextEvent(AgentEvent& e, Duration t);
+ int pendingEvents() const;
void registerSchema(Schema& s);
DataAddr addData(Data& d, const string& n, bool persist);
@@ -161,6 +162,7 @@ const string& AgentSession::getName() const { return impl->getName(); }
void AgentSession::open() { impl->open(); }
void AgentSession::close() { impl->close(); }
bool AgentSession::nextEvent(AgentEvent& e, Duration t) { return impl->nextEvent(e, t); }
+int AgentSession::pendingEvents() const { return impl->pendingEvents(); }
void AgentSession::registerSchema(Schema& s) { impl->registerSchema(s); }
DataAddr AgentSession::addData(Data& d, const string& n, bool p) { return impl->addData(d, n, p); }
void AgentSession::delData(const DataAddr& a) { impl->delData(a); }
@@ -318,7 +320,7 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout)
uint64_t milliseconds = timeout.getMilliseconds();
qpid::sys::Mutex::ScopedLock l(lock);
- if (eventQueue.empty())
+ if (eventQueue.empty() && milliseconds > 0)
cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(),
qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
@@ -332,6 +334,13 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout)
}
+int AgentSessionImpl::pendingEvents() const
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ return eventQueue.size();
+}
+
+
void AgentSessionImpl::registerSchema(Schema& schema)
{
if (!schema.isFinalized())
diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
index e12c1152f6..7b839930e1 100644
--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
+++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
@@ -54,6 +54,7 @@ void ConsoleSession::setAgentFilter(const string& f) { impl->setAgentFilter(f);
void ConsoleSession::open() { impl->open(); }
void ConsoleSession::close() { impl->close(); }
bool ConsoleSession::nextEvent(ConsoleEvent& e, Duration t) { return impl->nextEvent(e, t); }
+int ConsoleSession::pendingEvents() const { return impl->pendingEvents(); }
uint32_t ConsoleSession::getAgentCount() const { return impl->getAgentCount(); }
Agent ConsoleSession::getAgent(uint32_t i) const { return impl->getAgent(i); }
Agent ConsoleSession::getConnectedBrokerAgent() const { return impl->getConnectedBrokerAgent(); }
@@ -213,7 +214,7 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout)
uint64_t milliseconds = timeout.getMilliseconds();
qpid::sys::Mutex::ScopedLock l(lock);
- if (eventQueue.empty())
+ if (eventQueue.empty() && milliseconds > 0)
cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(),
qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
@@ -227,6 +228,13 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout)
}
+int ConsoleSessionImpl::pendingEvents() const
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ return eventQueue.size();
+}
+
+
uint32_t ConsoleSessionImpl::getAgentCount() const
{
qpid::sys::Mutex::ScopedLock l(lock);
@@ -421,7 +429,23 @@ void ConsoleSessionImpl::handleAgentUpdate(const string& agentName, const Varian
iter = content.find("_values");
if (iter == content.end())
return;
- Variant::Map attrs(iter->second.asMap());
+ const Variant::Map& in_attrs(iter->second.asMap());
+ Variant::Map attrs;
+
+ //
+ // Copy the map from the message to "attrs". Translate any old-style
+ // keys to their new key values in the process.
+ //
+ for (iter = in_attrs.begin(); iter != in_attrs.end(); iter++) {
+ if (iter->first == "epoch")
+ attrs[protocol::AGENT_ATTR_EPOCH] = iter->second;
+ else if (iter->first == "timestamp")
+ attrs[protocol::AGENT_ATTR_TIMESTAMP] = iter->second;
+ else if (iter->first == "heartbeat_interval")
+ attrs[protocol::AGENT_ATTR_HEARTBEAT_INTERVAL] = iter->second;
+ else
+ attrs[iter->first] = iter->second;
+ }
iter = attrs.find(protocol::AGENT_ATTR_EPOCH);
if (iter != attrs.end())
diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
index 675c8bcfb5..411b3f016a 100644
--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
@@ -58,6 +58,7 @@ namespace qmf {
void open();
void close();
bool nextEvent(ConsoleEvent& e, qpid::messaging::Duration t);
+ int pendingEvents() const;
uint32_t getAgentCount() const;
Agent getAgent(uint32_t i) const;
Agent getConnectedBrokerAgent() const { return connectedBrokerAgent; }
diff --git a/qpid/cpp/src/qpid/broker/AsyncCompletion.h b/qpid/cpp/src/qpid/broker/AsyncCompletion.h
index 1f3d11e0ee..fef994438f 100644
--- a/qpid/cpp/src/qpid/broker/AsyncCompletion.h
+++ b/qpid/cpp/src/qpid/broker/AsyncCompletion.h
@@ -22,6 +22,8 @@
*
*/
+#include <boost/intrusive_ptr.hpp>
+
#include "qpid/broker/BrokerImportExport.h"
#include "qpid/sys/AtomicValue.h"
#include "qpid/sys/Mutex.h"
@@ -77,6 +79,22 @@ namespace broker {
class AsyncCompletion
{
+ public:
+
+ /** Supplied by the Initiator to the end() method, allows for a callback
+ * when all outstanding completers are done. If the callback cannot be
+ * made during the end() call, the clone() method must supply a copy of
+ * this callback object that persists after end() returns. The cloned
+ * callback object will be used by the last completer thread, and
+ * released when the callback returns.
+ */
+ class Callback : public RefCounted
+ {
+ public:
+ virtual void completed(bool) = 0;
+ virtual boost::intrusive_ptr<Callback> clone() = 0;
+ };
+
private:
mutable qpid::sys::AtomicValue<uint32_t> completionsNeeded;
mutable qpid::sys::Monitor callbackLock;
@@ -85,14 +103,17 @@ class AsyncCompletion
void invokeCallback(bool sync) {
qpid::sys::Mutex::ScopedLock l(callbackLock);
if (active) {
- inCallback = true;
- {
- qpid::sys::Mutex::ScopedUnlock ul(callbackLock);
- completed(sync);
+ if (callback.get()) {
+ inCallback = true;
+ {
+ qpid::sys::Mutex::ScopedUnlock ul(callbackLock);
+ callback->completed(sync);
+ }
+ inCallback = false;
+ callback = boost::intrusive_ptr<Callback>();
+ callbackLock.notifyAll();
}
- inCallback = false;
active = false;
- callbackLock.notifyAll();
}
}
@@ -100,17 +121,17 @@ class AsyncCompletion
/** Invoked when all completers have signalled that they have completed
* (via calls to finishCompleter()). bool == true if called via end()
*/
- virtual void completed(bool) = 0;
+ boost::intrusive_ptr<Callback> callback;
public:
AsyncCompletion() : completionsNeeded(0), inCallback(false), active(true) {};
virtual ~AsyncCompletion() { cancel(); }
+
/** True when all outstanding operations have compeleted
*/
bool isDone()
{
- qpid::sys::Mutex::ScopedLock l(callbackLock);
return !active;
}
@@ -135,17 +156,32 @@ class AsyncCompletion
*/
void begin()
{
- qpid::sys::Mutex::ScopedLock l(callbackLock);
++completionsNeeded;
}
/** called by initiator after all potential completers have called
* startCompleter().
*/
- void end()
+ void end(Callback& cb)
{
assert(completionsNeeded.get() > 0); // ensure begin() has been called!
+ // the following only "decrements" the count if it is 1. This means
+ // there are no more outstanding completers and we are done.
+ if (completionsNeeded.boolCompareAndSwap(1, 0)) {
+ // done! Complete immediately
+ cb.completed(true);
+ return;
+ }
+
+ // the compare-and-swap did not succeed. This means there are
+ // outstanding completers pending (count > 1). Get a persistent
+ // Callback object to use when the last completer is done.
+ // Decrement after setting up the callback ensures that pending
+ // completers cannot touch the callback until it is ready.
+ callback = cb.clone();
if (--completionsNeeded == 0) {
+ // note that a completer may have completed during the
+ // callback setup or decrement:
invokeCallback(true);
}
}
@@ -156,14 +192,9 @@ class AsyncCompletion
virtual void cancel() {
qpid::sys::Mutex::ScopedLock l(callbackLock);
while (inCallback) callbackLock.wait();
+ callback = boost::intrusive_ptr<Callback>();
active = false;
}
-
- /** may be called by Initiator after all completers have been added but
- * prior to calling end(). Allows initiator to determine if it _really_
- * needs to wait for pending Completers (e.g. count > 1).
- */
- //uint32_t getPendingCompleters() { return completionsNeeded.get(); }
};
}} // qpid::broker::
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index 93e176fc0d..1b64fb2a52 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -122,7 +122,8 @@ Broker::Options::Options(const std::string& name) :
qmf2Support(true),
qmf1Support(true),
queueFlowStopRatio(80),
- queueFlowResumeRatio(70)
+ queueFlowResumeRatio(70),
+ queueThresholdEventRatio(80)
{
int c = sys::SystemInfo::concurrency();
workerThreads=c+1;
@@ -153,11 +154,12 @@ 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)")
- ("sasl-config", optValue(saslConfigPath, "FILE"), "gets sasl config from nonstandard location")
+ ("sasl-config", optValue(saslConfigPath, "DIR"), "gets sasl config info from nonstandard location")
("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")
("default-flow-stop-threshold", optValue(queueFlowStopRatio, "%MESSAGES"), "Queue capacity level at which flow control is activated.")
- ("default-flow-resume-threshold", optValue(queueFlowResumeRatio, "%MESSAGES"), "Queue capacity level at which flow control is de-activated.");
+ ("default-flow-resume-threshold", optValue(queueFlowResumeRatio, "%MESSAGES"), "Queue capacity level at which flow control is de-activated.")
+ ("default-event-threshold-ratio", optValue(queueThresholdEventRatio, "%age of limit"), "The ratio of any specified queue limit at which an event will be raised");
}
const std::string empty;
@@ -595,7 +597,7 @@ void Broker::createObject(const std::string& type, const std::string& name,
}
} else if (type == TYPE_EXCHANGE || type == TYPE_TOPIC) {
bool durable(false);
- std::string exchangeType;
+ std::string exchangeType("topic");
std::string alternateExchange;
Variant::Map extensions;
for (Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) {
@@ -788,18 +790,11 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
Exchange::shared_ptr alternate;
if (!alternateExchange.empty()) {
alternate = exchanges.get(alternateExchange);
- if (!alternate) framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange));
+ if (!alternate) throw framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange));
}
- std::pair<Queue::shared_ptr, bool> result = queues.declare(name, durable, autodelete, owner);
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, durable, autodelete, owner, alternate, arguments);
if (result.second) {
- if (alternate) {
- result.first->setAlternateExchange(alternate);
- alternate->incAlternateUsers();
- }
-
- //apply settings & create persistent record if required
- result.first->create(arguments);
//add default binding:
result.first->bind(exchanges.getDefault(), name);
@@ -861,7 +856,7 @@ std::pair<Exchange::shared_ptr, bool> Broker::createExchange(
Exchange::shared_ptr alternate;
if (!alternateExchange.empty()) {
alternate = exchanges.get(alternateExchange);
- if (!alternate) framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange));
+ if (!alternate) throw framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange));
}
std::pair<Exchange::shared_ptr, bool> result;
diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h
index 5fd230d9bd..d165c7ea70 100644
--- a/qpid/cpp/src/qpid/broker/Broker.h
+++ b/qpid/cpp/src/qpid/broker/Broker.h
@@ -121,6 +121,7 @@ public:
bool qmf1Support;
uint queueFlowStopRatio; // producer flow control: on
uint queueFlowResumeRatio; // producer flow control: off
+ uint16_t queueThresholdEventRatio;
private:
std::string getHome();
@@ -154,7 +155,7 @@ public:
void setLogLevel(const std::string& level);
std::string getLogLevel();
void createObject(const std::string& type, const std::string& name,
- const qpid::types::Variant::Map& properties, bool lenient, const ConnectionState* context);
+ const qpid::types::Variant::Map& properties, bool strict, const ConnectionState* context);
void deleteObject(const std::string& type, const std::string& name,
const qpid::types::Variant::Map& options, const ConnectionState* context);
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
index 67713a6eb7..c07e63e68c 100644
--- a/qpid/cpp/src/qpid/broker/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -331,31 +331,30 @@ void Connection::closed(){ // Physically closed, suspend open sessions.
try {
while (!channels.empty())
ptr_map_ptr(channels.begin())->handleDetach();
- while (!exclusiveQueues.empty()) {
- boost::shared_ptr<Queue> q(exclusiveQueues.front());
- q->releaseExclusiveOwnership();
- if (q->canAutoDelete()) {
- Queue::tryAutoDelete(broker, q);
- }
- exclusiveQueues.erase(exclusiveQueues.begin());
- }
} catch(std::exception& e) {
QPID_LOG(error, QPID_MSG("While closing connection: " << e.what()));
assert(0);
}
}
+void Connection::doIoCallbacks() {
+ {
+ ScopedLock<Mutex> l(ioCallbackLock);
+ // Although IO callbacks execute in the connection thread context, they are
+ // not cluster safe because they are queued for execution in non-IO threads.
+ ClusterUnsafeScope cus;
+ while (!ioCallbacks.empty()) {
+ boost::function0<void> cb = ioCallbacks.front();
+ ioCallbacks.pop();
+ ScopedUnlock<Mutex> ul(ioCallbackLock);
+ cb(); // Lend the IO thread for management processing
+ }
+ }
+}
+
bool Connection::doOutput() {
try {
- {
- ScopedLock<Mutex> l(ioCallbackLock);
- while (!ioCallbacks.empty()) {
- boost::function0<void> cb = ioCallbacks.front();
- ioCallbacks.pop();
- ScopedUnlock<Mutex> ul(ioCallbackLock);
- cb(); // Lend the IO thread for management processing
- }
- }
+ doIoCallbacks();
if (mgmtClosing) {
closed();
close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request");
@@ -475,8 +474,8 @@ void Connection::OutboundFrameTracker::abort() { next->abort(); }
void Connection::OutboundFrameTracker::activateOutput() { next->activateOutput(); }
void Connection::OutboundFrameTracker::giveReadCredit(int32_t credit) { next->giveReadCredit(credit); }
void Connection::OutboundFrameTracker::send(framing::AMQFrame& f)
-{
- next->send(f);
+{
+ next->send(f);
con.sent(f);
}
void Connection::OutboundFrameTracker::wrap(sys::ConnectionOutputHandlerPtr& p)
diff --git a/qpid/cpp/src/qpid/broker/Connection.h b/qpid/cpp/src/qpid/broker/Connection.h
index b751848d73..8f1aa701ef 100644
--- a/qpid/cpp/src/qpid/broker/Connection.h
+++ b/qpid/cpp/src/qpid/broker/Connection.h
@@ -153,13 +153,16 @@ class Connection : public sys::ConnectionInputHandler,
void addManagementObject();
const qpid::sys::SecuritySettings& getExternalSecuritySettings() const
- {
+ {
return securitySettings;
}
/** @return true if the initial connection negotiation is complete. */
bool isOpen();
+ // Used by cluster during catch-up, see cluster::OutputInterceptor
+ void doIoCallbacks();
+
private:
typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap;
typedef std::vector<boost::shared_ptr<Queue> >::iterator queue_iterator;
@@ -201,7 +204,7 @@ class Connection : public sys::ConnectionInputHandler,
sys::ConnectionOutputHandler* next;
};
OutboundFrameTracker outboundTracker;
-
+
void sent(const framing::AMQFrame& f);
public:
diff --git a/qpid/cpp/src/qpid/broker/ConnectionState.h b/qpid/cpp/src/qpid/broker/ConnectionState.h
index 774c37408d..9c31a931d8 100644
--- a/qpid/cpp/src/qpid/broker/ConnectionState.h
+++ b/qpid/cpp/src/qpid/broker/ConnectionState.h
@@ -79,7 +79,6 @@ class ConnectionState : public ConnectionToken, public management::Manageable
Broker& getBroker() { return broker; }
Broker& broker;
- std::vector<boost::shared_ptr<Queue> > exclusiveQueues;
//contained output tasks
sys::AggregateOutput outputTasks;
diff --git a/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
index 64760bea36..58dcc6d7c7 100644
--- a/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
+++ b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp
@@ -135,7 +135,7 @@ void DeliveryRecord::reject()
Exchange::shared_ptr alternate = queue->getAlternateExchange();
if (alternate) {
DeliverableMessage delivery(msg.payload);
- alternate->route(delivery, msg.payload->getRoutingKey(), msg.payload->getApplicationHeaders());
+ alternate->routeWithAlternate(delivery);
QPID_LOG(info, "Routed rejected message from " << queue->getName() << " to "
<< alternate->getName());
} else {
diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp
index b499171418..8ebe865867 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.cpp
+++ b/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -356,3 +356,12 @@ bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b)
void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) {
msg->getProperties<DeliveryProperties>()->setExchange(getName());
}
+
+bool Exchange::routeWithAlternate(Deliverable& msg)
+{
+ route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders());
+ if (!msg.delivered && alternate) {
+ alternate->route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders());
+ }
+ return msg.delivered;
+}
diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h
index 3c8b5ca2cd..9c4e6be192 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.h
+++ b/qpid/cpp/src/qpid/broker/Exchange.h
@@ -222,6 +222,8 @@ public:
*/
void recoveryComplete(ExchangeRegistry& exchanges);
+ bool routeWithAlternate(Deliverable& message);
+
protected:
qpid::sys::Mutex bridgeLock;
std::vector<DynamicBridge*> bridgeVector;
diff --git a/qpid/cpp/src/qpid/broker/Fairshare.cpp b/qpid/cpp/src/qpid/broker/Fairshare.cpp
index e6bbf86691..17270ffd8d 100644
--- a/qpid/cpp/src/qpid/broker/Fairshare.cpp
+++ b/qpid/cpp/src/qpid/broker/Fairshare.cpp
@@ -24,6 +24,7 @@
#include "qpid/log/Statement.h"
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/assign/list_of.hpp>
namespace qpid {
namespace broker {
@@ -104,51 +105,80 @@ bool Fairshare::setState(Messages& m, uint priority, uint count)
return fairshare && fairshare->setState(priority, count);
}
-int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::string& key)
+int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys)
{
- qpid::framing::FieldTable::ValuePtr v = settings.get(key);
+ qpid::framing::FieldTable::ValuePtr v;
+ std::vector<std::string>::const_iterator i = keys.begin();
+ while (!v && i != keys.end()) {
+ v = settings.get(*i++);
+ }
+
if (!v) {
return 0;
} else if (v->convertsTo<int>()) {
return v->get<int>();
} else if (v->convertsTo<std::string>()){
std::string s = v->get<std::string>();
- try {
- return boost::lexical_cast<int>(s);
+ try {
+ return boost::lexical_cast<int>(s);
} catch(const boost::bad_lexical_cast&) {
- QPID_LOG(warning, "Ignoring invalid integer value for " << key << ": " << s);
+ QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << s);
return 0;
}
} else {
- QPID_LOG(warning, "Ignoring invalid integer value for " << key << ": " << *v);
+ QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << *v);
return 0;
}
}
-int getSetting(const qpid::framing::FieldTable& settings, const std::string& key, int minvalue, int maxvalue)
+int getIntegerSettingForKey(const qpid::framing::FieldTable& settings, const std::string& key)
+{
+ return getIntegerSetting(settings, boost::assign::list_of<std::string>(key));
+}
+
+int getSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys, int minvalue, int maxvalue)
+{
+ return std::max(minvalue,std::min(getIntegerSetting(settings, keys), maxvalue));
+}
+
+std::auto_ptr<Fairshare> getFairshareForKey(const qpid::framing::FieldTable& settings, uint levels, const std::string& key)
+{
+ uint defaultLimit = getIntegerSettingForKey(settings, key);
+ std::auto_ptr<Fairshare> fairshare(new Fairshare(levels, defaultLimit));
+ for (uint i = 0; i < levels; i++) {
+ std::string levelKey = (boost::format("%1%-%2%") % key % i).str();
+ if(settings.isSet(levelKey)) {
+ fairshare->setLimit(i, getIntegerSettingForKey(settings, levelKey));
+ }
+ }
+ if (!fairshare->isNull()) {
+ return fairshare;
+ } else {
+ return std::auto_ptr<Fairshare>();
+ }
+}
+
+std::auto_ptr<Fairshare> getFairshare(const qpid::framing::FieldTable& settings,
+ uint levels,
+ const std::vector<std::string>& keys)
{
- return std::max(minvalue,std::min(getIntegerSetting(settings, key), maxvalue));
+ std::auto_ptr<Fairshare> fairshare;
+ for (std::vector<std::string>::const_iterator i = keys.begin(); i != keys.end() && !fairshare.get(); ++i) {
+ fairshare = getFairshareForKey(settings, levels, *i);
+ }
+ return fairshare;
}
std::auto_ptr<Messages> Fairshare::create(const qpid::framing::FieldTable& settings)
{
+ using boost::assign::list_of;
std::auto_ptr<Messages> result;
- size_t levels = getSetting(settings, "x-qpid-priorities", 1, 100);
+ size_t levels = getSetting(settings, list_of<std::string>("qpid.priorities")("x-qpid-priorities"), 1, 100);
if (levels) {
- uint defaultLimit = getIntegerSetting(settings, "x-qpid-fairshare");
- std::auto_ptr<Fairshare> fairshare(new Fairshare(levels, defaultLimit));
- for (uint i = 0; i < levels; i++) {
- std::string key = (boost::format("x-qpid-fairshare-%1%") % i).str();
- if(settings.isSet(key)) {
- fairshare->setLimit(i, getIntegerSetting(settings, key));
- }
- }
-
- if (fairshare->isNull()) {
- result = std::auto_ptr<Messages>(new PriorityQueue(levels));
- } else {
- result = fairshare;
- }
+ std::auto_ptr<Fairshare> fairshare =
+ getFairshare(settings, levels, list_of<std::string>("qpid.fairshare")("x-qpid-fairshare"));
+ if (fairshare.get()) result = fairshare;
+ else result = std::auto_ptr<Messages>(new PriorityQueue(levels));
}
return result;
}
diff --git a/qpid/cpp/src/qpid/broker/Fairshare.h b/qpid/cpp/src/qpid/broker/Fairshare.h
index 6c4b87f857..1b25721e0c 100644
--- a/qpid/cpp/src/qpid/broker/Fairshare.h
+++ b/qpid/cpp/src/qpid/broker/Fairshare.h
@@ -41,18 +41,18 @@ class Fairshare : public PriorityQueue
bool getState(uint& priority, uint& count) const;
bool setState(uint priority, uint count);
void setLimit(size_t level, uint limit);
+ bool isNull();
static std::auto_ptr<Messages> create(const qpid::framing::FieldTable& settings);
static bool getState(const Messages&, uint& priority, uint& count);
static bool setState(Messages&, uint priority, uint count);
private:
std::vector<uint> limits;
-
+
uint priority;
uint count;
-
+
uint currentLevel();
uint nextLevel();
- bool isNull();
bool limitReached();
bool findFrontLevel(uint& p, PriorityLevels&);
};
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index 122c5b9c1a..812d856416 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -51,7 +51,7 @@ 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), dequeueCallback(0),
- inCallback(false), requiredCredit(0)
+ inCallback(false), requiredCredit(0), isManagementMessage(false)
{}
Message::Message(const Message& original) :
@@ -443,4 +443,7 @@ framing::FieldTable& Message::getOrInsertHeaders()
return getProperties<MessageProperties>()->getApplicationHeaders();
}
+bool Message::getIsManagementMessage() const { return isManagementMessage; }
+void Message::setIsManagementMessage(bool b) { isManagementMessage = b; }
+
}} // namespace qpid::broker
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index 2d0de27823..0e9ae7ba12 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -159,7 +159,8 @@ public:
void resetDequeueCompleteCallback();
uint8_t getPriority() const;
-
+ bool getIsManagementMessage() const;
+ void setIsManagementMessage(bool b);
private:
MessageAdapter& getAdapter() const;
void allDequeuesComplete();
@@ -186,6 +187,7 @@ public:
bool inCallback;
uint32_t requiredCredit;
+ bool isManagementMessage;
};
}}
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h
index a84aa45d76..e50b52c09a 100644
--- a/qpid/cpp/src/qpid/broker/PersistableMessage.h
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h
@@ -56,7 +56,7 @@ class PersistableMessage : public Persistable
* operations have completed, the transfer of this message from the client
* may be considered complete.
*/
- boost::shared_ptr<AsyncCompletion> ingressCompletion;
+ AsyncCompletion ingressCompletion;
/**
* Tracks the number of outstanding asynchronous dequeue
@@ -115,12 +115,11 @@ class PersistableMessage : public Persistable
virtual QPID_BROKER_EXTERN bool isPersistent() const = 0;
/** track the progress of a message received by the broker - see ingressCompletion above */
- QPID_BROKER_EXTERN bool isIngressComplete() { return !ingressCompletion || ingressCompletion->isDone(); }
- QPID_BROKER_EXTERN boost::shared_ptr<AsyncCompletion>& getIngressCompletion() { return ingressCompletion; }
- QPID_BROKER_EXTERN void setIngressCompletion(boost::shared_ptr<AsyncCompletion>& ic) { ingressCompletion = ic; }
+ QPID_BROKER_EXTERN bool isIngressComplete() { return ingressCompletion.isDone(); }
+ QPID_BROKER_EXTERN AsyncCompletion& getIngressCompletion() { return ingressCompletion; }
- QPID_BROKER_EXTERN void enqueueStart() { if (ingressCompletion) ingressCompletion->startCompleter(); }
- QPID_BROKER_EXTERN void enqueueComplete() { if (ingressCompletion) ingressCompletion->finishCompleter(); }
+ QPID_BROKER_EXTERN void enqueueStart() { ingressCompletion.startCompleter(); }
+ QPID_BROKER_EXTERN void enqueueComplete() { ingressCompletion.finishCompleter(); }
QPID_BROKER_EXTERN void enqueueAsync(PersistableQueue::shared_ptr queue,
MessageStore* _store);
diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp
index f2322767f6..bd061ac214 100644
--- a/qpid/cpp/src/qpid/broker/Queue.cpp
+++ b/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -517,8 +517,7 @@ uint32_t Queue::purge(const uint32_t purge_request, boost::shared_ptr<Exchange>
while (!rerouteQueue.empty()) {
DeliverableMessage msg(rerouteQueue.front());
rerouteQueue.pop_front();
- dest->route(msg, msg.getMessage().getRoutingKey(),
- msg.getMessage().getApplicationHeaders());
+ dest->routeWithAlternate(msg);
}
return count;
@@ -758,7 +757,7 @@ void Queue::create(const FieldTable& _settings)
if (store) {
store->create(*this, _settings);
}
- configure(_settings);
+ configureImpl(_settings);
if (broker) broker->getCluster().create(*this);
}
@@ -784,9 +783,14 @@ int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::stri
}
}
-void Queue::configure(const FieldTable& _settings, bool recovering)
+void Queue::configure(const FieldTable& _settings)
{
+ settings = _settings;
+ configureImpl(settings);
+}
+void Queue::configureImpl(const FieldTable& _settings)
+{
eventMode = _settings.getAsInt(qpidQueueEventGeneration);
if (eventMode && broker) {
broker->getQueueEvents().observe(*this, eventMode == ENQUEUE_ONLY);
@@ -805,7 +809,7 @@ void Queue::configure(const FieldTable& _settings, bool recovering)
setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings));
}
if (broker && broker->getManagementAgent()) {
- ThresholdAlerts::observe(*this, *(broker->getManagementAgent()), _settings);
+ ThresholdAlerts::observe(*this, *(broker->getManagementAgent()), _settings, broker->getOptions().queueThresholdEventRatio);
}
//set this regardless of owner to allow use of no-local with exclusive consumers also
@@ -852,9 +856,6 @@ void Queue::configure(const FieldTable& _settings, bool recovering)
mgmtObject->set_arguments(ManagementAgent::toMap(_settings));
}
- if ( isDurable() && ! getPersistenceId() && ! recovering )
- store->create(*this, _settings);
-
QueueFlowLimit::observe(*this, _settings);
}
@@ -865,8 +866,7 @@ void Queue::destroyed()
Mutex::ScopedLock locker(messageLock);
while(!messages->empty()){
DeliverableMessage msg(messages->front().payload);
- alternateExchange->route(msg, msg.getMessage().getRoutingKey(),
- msg.getMessage().getApplicationHeaders());
+ alternateExchange->routeWithAlternate(msg);
popAndDequeue();
}
alternateExchange->decAlternateUsers();
@@ -949,13 +949,14 @@ uint32_t Queue::encodedSize() const
+ (policy.get() ? (*policy).encodedSize() : 0);
}
-Queue::shared_ptr Queue::decode ( QueueRegistry& queues, Buffer& buffer, bool recovering )
+Queue::shared_ptr Queue::restore( QueueRegistry& queues, Buffer& buffer )
{
string name;
buffer.getShortString(name);
- std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true);
- buffer.get(result.first->settings);
- result.first->configure(result.first->settings, recovering );
+ FieldTable settings;
+ buffer.get(settings);
+ boost::shared_ptr<Exchange> alternate;
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true, false, 0, alternate, settings, true);
if (result.first->policy.get() && buffer.available() >= result.first->policy->encodedSize()) {
buffer.get ( *(result.first->policy) );
}
diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h
index 331c9eaa4e..73d52ec9ca 100644
--- a/qpid/cpp/src/qpid/broker/Queue.h
+++ b/qpid/cpp/src/qpid/broker/Queue.h
@@ -149,6 +149,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QueuedMessage getFront();
void forcePersistent(QueuedMessage& msg);
int getEventMode();
+ void configureImpl(const qpid::framing::FieldTable& settings);
inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg)
{
@@ -192,11 +193,17 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QPID_BROKER_EXTERN bool dispatch(Consumer::shared_ptr);
- void create(const qpid::framing::FieldTable& settings);
+ /**
+ * Used to configure a new queue and create a persistent record
+ * for it in store if required.
+ */
+ QPID_BROKER_EXTERN void create(const qpid::framing::FieldTable& settings);
- // "recovering" means we are doing a MessageStore recovery.
- QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings,
- bool recovering = false);
+ /**
+ * Used to reconfigure a recovered queue (does not create
+ * persistent record in store).
+ */
+ QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings);
void destroyed();
QPID_BROKER_EXTERN void bound(const std::string& exchange,
const std::string& key,
@@ -314,8 +321,13 @@ class Queue : public boost::enable_shared_from_this<Queue>,
void encode(framing::Buffer& buffer) const;
uint32_t encodedSize() const;
- // "recovering" means we are doing a MessageStore recovery.
- static Queue::shared_ptr decode(QueueRegistry& queues, framing::Buffer& buffer, bool recovering = false );
+ /**
+ * Restores a queue from encoded data (used in recovery)
+ *
+ * Note: restored queue will be neither auto-deleted or have an
+ * exclusive owner
+ */
+ static Queue::shared_ptr restore(QueueRegistry& queues, framing::Buffer& buffer);
static void tryAutoDelete(Broker& broker, Queue::shared_ptr);
virtual void setExternalQueueStore(ExternalQueueStore* inst);
diff --git a/qpid/cpp/src/qpid/broker/QueueFlowLimit.cpp b/qpid/cpp/src/qpid/broker/QueueFlowLimit.cpp
index a99c9de7df..3494288f7b 100644
--- a/qpid/cpp/src/qpid/broker/QueueFlowLimit.cpp
+++ b/qpid/cpp/src/qpid/broker/QueueFlowLimit.cpp
@@ -138,13 +138,10 @@ void QueueFlowLimit::enqueued(const QueuedMessage& msg)
flowStopped = true;
QPID_LOG(info, "Queue \"" << queueName << "\": has reached " << flowStopSize << " enqueued bytes. Producer flow control activated." );
}
- if (flowStopped && queueMgmtObj)
+ if (flowStopped && queueMgmtObj) {
queueMgmtObj->set_flowStopped(true);
- }
-
- /** @todo KAG: - REMOVE ONCE STABLE */
- if (index.find(msg.payload) != index.end()) {
- QPID_LOG(error, "Queue \"" << queueName << "\": has enqueued a msg twice: " << msg.position);
+ queueMgmtObj->inc_flowStoppedCount();
+ }
}
if (flowStopped || !index.empty()) {
@@ -154,7 +151,7 @@ void QueueFlowLimit::enqueued(const QueuedMessage& msg)
return;
}
QPID_LOG(trace, "Queue \"" << queueName << "\": setting flow control for msg pos=" << msg.position);
- msg.payload->getIngressCompletion()->startCompleter(); // don't complete until flow resumes
+ msg.payload->getIngressCompletion().startCompleter(); // don't complete until flow resumes
index.insert(msg.payload);
}
}
@@ -194,14 +191,14 @@ void QueueFlowLimit::dequeued(const QueuedMessage& msg)
// flow enabled - release all pending msgs
while (!index.empty()) {
std::set< boost::intrusive_ptr<Message> >::iterator itr = index.begin();
- (*itr)->getIngressCompletion()->finishCompleter();
+ (*itr)->getIngressCompletion().finishCompleter();
index.erase(itr);
}
} else {
// even if flow controlled, we must release this msg as it is being dequeued
std::set< boost::intrusive_ptr<Message> >::iterator itr = index.find(msg.payload);
if (itr != index.end()) { // this msg is flow controlled, release it:
- (*itr)->getIngressCompletion()->finishCompleter();
+ (*itr)->getIngressCompletion().finishCompleter();
index.erase(itr);
}
}
diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
index 4168221ad0..b39ea3614b 100644
--- a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
+++ b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp
@@ -136,11 +136,10 @@ uint32_t QueuePolicy::getCapacity(const FieldTable& settings, const std::string&
string s(v->get<string>());
QPID_LOG(debug, "Got string value for " << key << ": " << s);
std::istringstream convert(s);
- if (convert >> result && result >= 0) return result;
+ if (convert >> result && result >= 0 && convert.eof()) return result;
}
- QPID_LOG(warning, "Cannot convert " << key << " to unsigned integer, using default (" << defaultValue << ")");
- return defaultValue;
+ throw IllegalArgumentException(QPID_MSG("Cannot convert " << key << " to unsigned integer: " << *v));
}
std::string QueuePolicy::getType(const FieldTable& settings)
diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
index ea2531dae7..135a3543d9 100644
--- a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
+++ b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/Queue.h"
#include "qpid/broker/QueueRegistry.h"
#include "qpid/broker/QueueEvents.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/log/Statement.h"
#include <sstream>
#include <assert.h>
@@ -36,7 +37,13 @@ QueueRegistry::~QueueRegistry(){}
std::pair<Queue::shared_ptr, bool>
QueueRegistry::declare(const string& declareName, bool durable,
- bool autoDelete, const OwnershipToken* owner)
+ bool autoDelete, const OwnershipToken* owner,
+ boost::shared_ptr<Exchange> alternate,
+ const qpid::framing::FieldTable& arguments,
+ bool recovering/*true if this declare is a
+ result of recovering queue
+ definition from persistente
+ record*/)
{
RWlock::ScopedWlock locker(lock);
string name = declareName.empty() ? generateName() : declareName;
@@ -45,6 +52,17 @@ QueueRegistry::declare(const string& declareName, bool durable,
if (i == queues.end()) {
Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent, broker));
+ if (alternate) {
+ queue->setAlternateExchange(alternate);//need to do this *before* create
+ alternate->incAlternateUsers();
+ }
+ if (!recovering) {
+ //apply settings & create persistent record if required
+ queue->create(arguments);
+ } else {
+ //i.e. recovering a queue for which we already have a persistent record
+ queue->configure(arguments);
+ }
queues[name] = queue;
if (lastNode) queue->setLastNodeFailure();
diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.h b/qpid/cpp/src/qpid/broker/QueueRegistry.h
index 57859fe639..8a32a64f05 100644
--- a/qpid/cpp/src/qpid/broker/QueueRegistry.h
+++ b/qpid/cpp/src/qpid/broker/QueueRegistry.h
@@ -24,6 +24,7 @@
#include "qpid/broker/BrokerImportExport.h"
#include "qpid/sys/Mutex.h"
#include "qpid/management/Manageable.h"
+#include "qpid/framing/FieldTable.h"
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <algorithm>
@@ -34,6 +35,7 @@ namespace broker {
class Queue;
class QueueEvents;
+class Exchange;
class OwnershipToken;
class Broker;
class MessageStore;
@@ -60,7 +62,10 @@ class QueueRegistry {
const std::string& name,
bool durable = false,
bool autodelete = false,
- const OwnershipToken* owner = 0);
+ const OwnershipToken* owner = 0,
+ boost::shared_ptr<Exchange> alternateExchange = boost::shared_ptr<Exchange>(),
+ const qpid::framing::FieldTable& args = framing::FieldTable(),
+ bool recovering = false);
/**
* Destroy the named queue.
diff --git a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
index 2a1f58eb91..9aae39ccc3 100644
--- a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
+++ b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
@@ -114,7 +114,7 @@ RecoverableExchange::shared_ptr RecoveryManagerImpl::recoverExchange(framing::Bu
RecoverableQueue::shared_ptr RecoveryManagerImpl::recoverQueue(framing::Buffer& buffer)
{
- Queue::shared_ptr queue = Queue::decode(queues, buffer, true);
+ Queue::shared_ptr queue = Queue::restore(queues, buffer);
try {
Exchange::shared_ptr exchange = exchanges.getDefault();
if (exchange) {
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp
index cfc379f47c..ba1f989f7c 100644
--- a/qpid/cpp/src/qpid/broker/SemanticState.cpp
+++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp
@@ -88,7 +88,7 @@ void SemanticState::closed() {
//prevent requeued messages being redelivered to consumers
for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
disable(i->second);
- }
+ }
if (dtxBuffer.get()) {
dtxBuffer->fail();
}
@@ -107,7 +107,7 @@ bool SemanticState::exists(const string& consumerTag){
return consumers.find(consumerTag) != consumers.end();
}
-void SemanticState::consume(const string& tag,
+void SemanticState::consume(const string& tag,
Queue::shared_ptr queue, bool ackRequired, bool acquire,
bool exclusive, const string& resumeId, uint64_t resumeTtl, const FieldTable& arguments)
{
@@ -116,7 +116,8 @@ void SemanticState::consume(const string& tag,
consumers[tag] = c;
}
-void SemanticState::cancel(const string& tag){
+bool SemanticState::cancel(const string& tag)
+{
ConsumerImplMap::iterator i = consumers.find(tag);
if (i != consumers.end()) {
cancel(i->second);
@@ -124,7 +125,9 @@ void SemanticState::cancel(const string& tag){
//should cancel all unacked messages for this consumer so that
//they are not redelivered on recovery
for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::cancel, _1, tag));
-
+ return true;
+ } else {
+ return false;
}
}
@@ -194,7 +197,7 @@ void SemanticState::endDtx(const std::string& xid, bool fail)
dtxBuffer->fail();
} else {
dtxBuffer->markEnded();
- }
+ }
dtxBuffer.reset();
}
@@ -254,9 +257,9 @@ void SemanticState::record(const DeliveryRecord& delivery)
const std::string QPID_SYNC_FREQUENCY("qpid.sync_frequency");
-SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
- const string& _name,
- Queue::shared_ptr _queue,
+SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
+ const string& _name,
+ Queue::shared_ptr _queue,
bool ack,
bool _acquire,
bool _exclusive,
@@ -265,20 +268,20 @@ SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
const framing::FieldTable& _arguments
-) :
+) :
Consumer(_acquire),
- parent(_parent),
- name(_name),
- queue(_queue),
- ackExpected(ack),
+ parent(_parent),
+ name(_name),
+ queue(_queue),
+ ackExpected(ack),
acquire(_acquire),
- blocked(true),
+ blocked(true),
windowing(true),
exclusive(_exclusive),
resumeId(_resumeId),
resumeTtl(_resumeTtl),
arguments(_arguments),
- msgCredit(0),
+ msgCredit(0),
byteCredit(0),
notifyEnabled(true),
syncFrequency(_arguments.getAsInt(QPID_SYNC_FREQUENCY)),
@@ -289,7 +292,7 @@ SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
{
ManagementAgent* agent = parent->session.getBroker().getManagementAgent();
qpid::management::Manageable* ms = dynamic_cast<qpid::management::Manageable*> (&(parent->session));
-
+
if (agent != 0)
{
mgmtObject = new _qmf::Subscription(agent, this, ms , queue->GetManagementObject()->getObjectId() ,name,
@@ -331,7 +334,7 @@ bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg)
if (!ackExpected && acquire) record.setEnded();//allows message to be released now its been delivered
if (windowing || ackExpected || !acquire) {
parent->record(record);
- }
+ }
if (acquire && !ackExpected) {
queue->dequeue(0, msg);
}
@@ -351,7 +354,7 @@ bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
// checkCredit fails because the message is to big, we should
// remain on queue's listener list for possible smaller messages
// in future.
- //
+ //
blocked = !(filter(msg) && checkCredit(msg));
return !blocked;
}
@@ -372,7 +375,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
{
assertClusterSafe();
uint32_t originalMsgCredit = msgCredit;
- uint32_t originalByteCredit = byteCredit;
+ uint32_t originalByteCredit = byteCredit;
if (msgCredit != 0xFFFFFFFF) {
msgCredit--;
}
@@ -382,7 +385,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this)
<< ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit
<< " now bytes: " << byteCredit << " msgs: " << msgCredit);
-
+
}
bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
@@ -396,7 +399,7 @@ bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
return enoughCredit;
}
-SemanticState::ConsumerImpl::~ConsumerImpl()
+SemanticState::ConsumerImpl::~ConsumerImpl()
{
if (mgmtObject != 0)
mgmtObject->resourceDestroy ();
@@ -414,7 +417,7 @@ void SemanticState::unsubscribe(ConsumerImpl::shared_ptr c)
Queue::shared_ptr queue = c->getQueue();
if(queue) {
queue->cancel(c);
- if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) {
+ if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) {
Queue::tryAutoDelete(session.getBroker(), queue);
}
}
@@ -457,7 +460,7 @@ const std::string nullstring;
void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
msg->setTimestamp(getSession().getBroker().getExpiryPolicy());
-
+
std::string exchangeName = msg->getExchangeName();
if (!cacheExchange || cacheExchange->getName() != exchangeName)
cacheExchange = session.getBroker().getExchanges().get(exchangeName);
@@ -466,7 +469,7 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
/* verify the userid if specified: */
std::string id =
msg->hasProperties<MessageProperties>() ? msg->getProperties<MessageProperties>()->getUserId() : nullstring;
-
+
if (authMsg && !id.empty() && !(id == userID || (isDefaultRealm && id == userName)))
{
QPID_LOG(debug, "authorised user id : " << userID << " but user id in message declared as " << id);
@@ -484,7 +487,7 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
if (!strategy.delivered) {
//TODO:if discard-unroutable, just drop it
- //TODO:else if accept-mode is explicit, reject it
+ //TODO:else if accept-mode is explicit, reject it
//else route it to alternate exchange
if (cacheExchange->getAlternate()) {
cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
@@ -513,7 +516,7 @@ void SemanticState::ConsumerImpl::requestDispatch()
}
bool SemanticState::complete(DeliveryRecord& delivery)
-{
+{
ConsumerImplMap::iterator i = consumers.find(delivery.getTag());
if (i != consumers.end()) {
i->second->complete(delivery);
@@ -541,7 +544,7 @@ void SemanticState::recover(bool requeue)
unacked.clear();
for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
}else{
- for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this));
+ for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this));
//unconfirmed messages re redelivered and therefore have their
//id adjusted, confirmed messages are not and so the ordering
//w.r.t id is lost
@@ -673,7 +676,7 @@ Queue::shared_ptr SemanticState::getQueue(const string& name) const {
}
AckRange SemanticState::findRange(DeliveryId first, DeliveryId last)
-{
+{
return DeliveryRecord::findRange(unacked, first, last);
}
@@ -764,13 +767,13 @@ void SemanticState::accepted(const SequenceSet& commands) {
//in transactional mode, don't dequeue or remove, just
//maintain set of acknowledged messages:
accumulatedAck.add(commands);
-
+
if (dtxBuffer.get()) {
//if enlisted in a dtx, copy the relevant slice from
//unacked and record it against that transaction
TxOp::shared_ptr txAck(new DtxAck(accumulatedAck, unacked));
accumulatedAck.clear();
- dtxBuffer->enlist(txAck);
+ dtxBuffer->enlist(txAck);
//mark the relevant messages as 'ended' in unacked
//if the messages are already completed, they can be
@@ -792,7 +795,6 @@ void SemanticState::accepted(const SequenceSet& commands) {
}
void SemanticState::completed(const SequenceSet& commands) {
- assertClusterSafe();
DeliveryRecords::iterator removed =
remove_if(unacked.begin(), unacked.end(),
isInSequenceSetAnd(commands,
@@ -803,7 +805,6 @@ void SemanticState::completed(const SequenceSet& commands) {
void SemanticState::attached()
{
- assertClusterSafe();
for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
i->second->enableNotify();
session.getConnection().outputTasks.addOutputTask(i->second.get());
@@ -813,7 +814,6 @@ void SemanticState::attached()
void SemanticState::detached()
{
- assertClusterSafe();
for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
i->second->disableNotify();
session.getConnection().outputTasks.removeOutputTask(i->second.get());
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.h b/qpid/cpp/src/qpid/broker/SemanticState.h
index b2e648410a..8c69d6b89b 100644
--- a/qpid/cpp/src/qpid/broker/SemanticState.h
+++ b/qpid/cpp/src/qpid/broker/SemanticState.h
@@ -205,7 +205,7 @@ class SemanticState : private boost::noncopyable {
const std::string& resumeId=std::string(), uint64_t resumeTtl=0,
const framing::FieldTable& = framing::FieldTable());
- void cancel(const std::string& tag);
+ bool cancel(const std::string& tag);
void setWindowMode(const std::string& destination);
void setCreditMode(const std::string& destination);
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
index 9e4516679e..63c4b660b2 100644
--- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -114,7 +114,7 @@ void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const
"existing"));
}
}catch(UnknownExchangeTypeException& /*e*/){
- throw CommandInvalidException(QPID_MSG("Exchange type not implemented: " << type));
+ throw NotFoundException(QPID_MSG("Exchange type not implemented: " << type));
}
}
}
@@ -353,12 +353,12 @@ void SessionAdapter::QueueHandlerImpl::checkDelete(Queue::shared_ptr queue, bool
} else if(ifUnused && queue->getConsumerCount() > 0) {
throw PreconditionFailedException(QPID_MSG("Cannot delete queue "
<< queue->getName() << "; queue in use"));
- } else if (queue->isExclusiveOwner(&getConnection())) {
+ } else if (queue->isExclusiveOwner(&session)) {
//remove the queue from the list of exclusive queues if necessary
- QueueVector::iterator i = std::find(getConnection().exclusiveQueues.begin(),
- getConnection().exclusiveQueues.end(),
+ QueueVector::iterator i = std::find(exclusiveQueues.begin(),
+ exclusiveQueues.end(),
queue);
- if (i < getConnection().exclusiveQueues.end()) getConnection().exclusiveQueues.erase(i);
+ if (i < exclusiveQueues.end()) exclusiveQueues.erase(i);
}
}
@@ -431,7 +431,9 @@ SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName,
void
SessionAdapter::MessageHandlerImpl::cancel(const string& destination )
{
- state.cancel(destination);
+ if (!state.cancel(destination)) {
+ throw NotFoundException(QPID_MSG("No such subscription: " << destination));
+ }
ManagementAgent* agent = getBroker().getManagementAgent();
if (agent)
diff --git a/qpid/cpp/src/qpid/broker/SessionState.cpp b/qpid/cpp/src/qpid/broker/SessionState.cpp
index 11f3e84b70..18dbf63487 100644
--- a/qpid/cpp/src/qpid/broker/SessionState.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionState.cpp
@@ -62,7 +62,7 @@ SessionState::SessionState(
msgBuilder(&broker.getStore()),
mgmtObject(0),
rateFlowcontrol(0),
- scheduledCompleterContext(new ScheduledCompleterContext(this))
+ asyncCommandCompleter(new AsyncCommandCompleter(this))
{
uint32_t maxRate = broker.getOptions().maxSessionRate;
if (maxRate) {
@@ -102,25 +102,7 @@ SessionState::~SessionState() {
if (flowControlTimer)
flowControlTimer->cancel();
- // clean up any outstanding incomplete commands
- {
- qpid::sys::ScopedLock<Mutex> l(incompleteCmdsLock);
- std::map<SequenceNumber, boost::shared_ptr<IncompleteCommandContext> > copy(incompleteCmds);
- incompleteCmds.clear();
- while (!copy.empty()) {
- boost::shared_ptr<IncompleteCommandContext> ref(copy.begin()->second);
- copy.erase(copy.begin());
- {
- // note: need to drop lock, as callback may attempt to take it.
- qpid::sys::ScopedUnlock<Mutex> ul(incompleteCmdsLock);
- ref->cancel();
- }
- }
- }
-
- // At this point, we are guaranteed no further completion callbacks will be
- // made. Cancel any outstanding scheduledCompleter calls...
- scheduledCompleterContext->cancel();
+ asyncCommandCompleter->cancel();
}
AMQP_ClientProxy& SessionState::getProxy() {
@@ -276,13 +258,11 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
msg->getFrames().append(header);
}
msg->setPublisher(&getConnection());
-
- boost::shared_ptr<AsyncCompletion> ac(boost::dynamic_pointer_cast<AsyncCompletion>(createIngressMsgXferContext(msg)));
- msg->setIngressCompletion( ac );
- ac->begin();
+ msg->getIngressCompletion().begin();
semanticState.handle(msg);
msgBuilder.end();
- ac->end(); // allows msg to complete xfer
+ IncompleteIngressMsgXfer xfer(this, msg);
+ msg->getIngressCompletion().end(xfer); // allows msg to complete xfer
}
// Handle producer session flow control
@@ -451,110 +431,94 @@ void SessionState::addPendingExecutionSync()
}
-/** factory for creating IncompleteIngressMsgXfer objects which
- * can be references from Messages as ingress AsyncCompletion objects.
+/** factory for creating a reference-counted IncompleteIngressMsgXfer object
+ * which will be attached to a message that will be completed asynchronously.
*/
-boost::shared_ptr<SessionState::IncompleteIngressMsgXfer>
-SessionState::createIngressMsgXferContext(boost::intrusive_ptr<Message> msg)
+boost::intrusive_ptr<AsyncCompletion::Callback>
+SessionState::IncompleteIngressMsgXfer::clone()
{
- SequenceNumber id = msg->getCommandId();
- boost::shared_ptr<SessionState::IncompleteIngressMsgXfer> cmd(new SessionState::IncompleteIngressMsgXfer(this, id, msg));
- qpid::sys::ScopedLock<Mutex> l(incompleteCmdsLock);
- incompleteCmds[id] = cmd;
- return cmd;
+ boost::intrusive_ptr<SessionState::IncompleteIngressMsgXfer> cb(new SessionState::IncompleteIngressMsgXfer(session, msg));
+ return cb;
}
-/** Invoked by the asynchronous completer associated with
- * a received msg that is pending Completion. May be invoked
- * by the SessionState directly (sync == true), or some external
- * entity (!sync).
+/** Invoked by the asynchronous completer associated with a received
+ * msg that is pending Completion. May be invoked by the IO thread
+ * (sync == true), or some external thread (!sync).
*/
void SessionState::IncompleteIngressMsgXfer::completed(bool sync)
{
if (!sync) {
/** note well: this path may execute in any thread. It is safe to access
- * the session, as the SessionState destructor will cancel all outstanding
- * callbacks before getting destroyed (so we'll never get here).
+ * the scheduledCompleterContext, since *this has a shared pointer to it.
+ * but not session or msg!
*/
+ session = 0; msg = 0;
QPID_LOG(debug, ": async completion callback scheduled for msg seq=" << id);
- if (session->scheduledCompleterContext->scheduleCompletion(id))
- session->getConnection().requestIOProcessing(boost::bind(&scheduledCompleter,
- session->scheduledCompleterContext));
- } else { // command is being completed in IO thread.
- // this path runs only on the IO thread.
- qpid::sys::ScopedLock<Mutex> l(session->incompleteCmdsLock);
- std::map<SequenceNumber, boost::shared_ptr<IncompleteCommandContext> >::iterator cmd;
- cmd = session->incompleteCmds.find(id);
- if (cmd != session->incompleteCmds.end()) {
- boost::shared_ptr<IncompleteCommandContext> tmp(cmd->second);
- session->incompleteCmds.erase(cmd);
-
- if (session->isAttached()) {
- QPID_LOG(debug, ": receive completed for msg seq=" << id);
- qpid::sys::ScopedUnlock<Mutex> ul(session->incompleteCmdsLock);
- session->completeRcvMsg(id, requiresAccept, requiresSync);
- return;
- }
+ completerContext->scheduleMsgCompletion(id, requiresAccept, requiresSync);
+ } else {
+ // this path runs directly from the ac->end() call in handleContent() above,
+ // so *session and *msg are definately valid.
+ if (session->isAttached()) {
+ QPID_LOG(debug, ": receive completed for msg seq=" << id);
+ session->completeRcvMsg(id, requiresAccept, requiresSync);
}
}
+ completerContext = boost::intrusive_ptr<AsyncCommandCompleter>();
}
-/** Scheduled from incomplete command's completed callback, safely completes all
- * completed commands in the IO Thread. Guaranteed not to be running at the same
- * time as the message receive code.
+/** Scheduled from an asynchronous command's completed callback to run on
+ * the IO thread.
*/
-void SessionState::scheduledCompleter(boost::shared_ptr<SessionState::ScheduledCompleterContext> ctxt)
+void SessionState::AsyncCommandCompleter::schedule(boost::intrusive_ptr<AsyncCommandCompleter> ctxt)
{
ctxt->completeCommands();
}
-/** mark a command (sequence) as completed, return True if caller should
- * schedule a call to completeCommands()
+/** mark an ingress Message.Transfer command as completed.
+ * This method must be thread safe - it may run on any thread.
*/
-bool SessionState::ScheduledCompleterContext::scheduleCompletion(SequenceNumber cmd)
+void SessionState::AsyncCommandCompleter::scheduleMsgCompletion(SequenceNumber cmd,
+ bool requiresAccept,
+ bool requiresSync)
{
- qpid::sys::ScopedLock<qpid::sys::Mutex> l(completedCmdsLock);
-
- completedCmds.push_back(cmd);
- return (completedCmds.size() == 1);
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock);
+
+ if (session) {
+ MessageInfo msg(cmd, requiresAccept, requiresSync);
+ completedMsgs.push_back(msg);
+ if (completedMsgs.size() == 1) {
+ session->getConnection().requestIOProcessing(boost::bind(&schedule,
+ session->asyncCommandCompleter));
+ }
+ }
}
-/** Cause the session to complete all completed commands */
-void SessionState::ScheduledCompleterContext::completeCommands()
+/** Cause the session to complete all completed commands.
+ * Executes on the IO thread.
+ */
+void SessionState::AsyncCommandCompleter::completeCommands()
{
- qpid::sys::ScopedLock<qpid::sys::Mutex> l(completedCmdsLock);
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock);
// when session is destroyed, it clears the session pointer via cancel().
- if (!session) return;
-
- while (!completedCmds.empty()) {
- SequenceNumber id = completedCmds.front();
- completedCmds.pop_front();
- std::map<SequenceNumber, boost::shared_ptr<IncompleteCommandContext> >::iterator cmd;
- {
- qpid::sys::ScopedLock<qpid::sys::Mutex> l(session->incompleteCmdsLock);
-
- cmd = session->incompleteCmds.find(id);
- if (cmd !=session->incompleteCmds.end()) {
- boost::shared_ptr<IncompleteCommandContext> tmp(cmd->second);
- {
- qpid::sys::ScopedUnlock<qpid::sys::Mutex> ul(session->incompleteCmdsLock);
- tmp->do_completion(); // retakes incompleteCmdslock
- }
- }
+ if (session && session->isAttached()) {
+ for (std::vector<MessageInfo>::iterator msg = completedMsgs.begin();
+ msg != completedMsgs.end(); ++msg) {
+ session->completeRcvMsg(msg->cmd, msg->requiresAccept, msg->requiresSync);
}
}
+ completedMsgs.clear();
}
/** cancel any pending calls to scheduleComplete */
-void SessionState::ScheduledCompleterContext::cancel()
+void SessionState::AsyncCommandCompleter::cancel()
{
- qpid::sys::ScopedLock<qpid::sys::Mutex> l(completedCmdsLock);
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock);
session = 0;
}
diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h
index 5e162e6475..2250940102 100644
--- a/qpid/cpp/src/qpid/broker/SessionState.h
+++ b/qpid/cpp/src/qpid/broker/SessionState.h
@@ -38,6 +38,7 @@
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
#include <set>
#include <vector>
@@ -176,79 +177,84 @@ class SessionState : public qpid::SessionState,
std::queue<SequenceNumber> pendingExecutionSyncs;
bool currentCommandComplete;
- /** Abstract class that represents a command that is pending
- * completion.
+ /** This class provides a context for completing asynchronous commands in a thread
+ * safe manner. Asynchronous commands save their completion state in this class.
+ * This class then schedules the completeCommands() method in the IO thread.
+ * While running in the IO thread, completeCommands() may safely complete all
+ * saved commands without the risk of colliding with other operations on this
+ * SessionState.
*/
- class IncompleteCommandContext : public AsyncCompletion
+ class AsyncCommandCompleter : public RefCounted {
+ private:
+ SessionState *session;
+ qpid::sys::Mutex completerLock;
+
+ // special-case message.transfer commands for optimization
+ struct MessageInfo {
+ SequenceNumber cmd; // message.transfer command id
+ bool requiresAccept;
+ bool requiresSync;
+ MessageInfo(SequenceNumber c, bool a, bool s)
+ : cmd(c), requiresAccept(a), requiresSync(s) {}
+ };
+ std::vector<MessageInfo> completedMsgs;
+
+ /** complete all pending commands, runs in IO thread */
+ void completeCommands();
+
+ /** for scheduling a run of "completeCommands()" on the IO thread */
+ static void schedule(boost::intrusive_ptr<AsyncCommandCompleter>);
+
+ public:
+ AsyncCommandCompleter(SessionState *s) : session(s) {};
+ ~AsyncCommandCompleter() {};
+
+ /** schedule the completion of an ingress message.transfer command */
+ void scheduleMsgCompletion(SequenceNumber cmd,
+ bool requiresAccept,
+ bool requiresSync);
+ void cancel(); // called by SessionState destructor.
+ };
+ boost::intrusive_ptr<AsyncCommandCompleter> asyncCommandCompleter;
+
+ /** Abstract class that represents a single asynchronous command that is
+ * pending completion.
+ */
+ class AsyncCommandContext : public AsyncCompletion::Callback
{
public:
- IncompleteCommandContext( SessionState *ss, SequenceNumber _id )
- : id(_id), session(ss) {}
- virtual ~IncompleteCommandContext() {}
-
- /* allows manual invokation of completion, used by IO thread to
- * complete a command that was originally finished on a different
- * thread.
- */
- void do_completion() { completed(true); }
+ AsyncCommandContext( SessionState *ss, SequenceNumber _id )
+ : id(_id), completerContext(ss->asyncCommandCompleter) {}
+ virtual ~AsyncCommandContext() {}
protected:
SequenceNumber id;
- SessionState *session;
+ boost::intrusive_ptr<AsyncCommandCompleter> completerContext;
};
/** incomplete Message.transfer commands - inbound to broker from client
*/
- class IncompleteIngressMsgXfer : public SessionState::IncompleteCommandContext
+ class IncompleteIngressMsgXfer : public SessionState::AsyncCommandContext
{
public:
IncompleteIngressMsgXfer( SessionState *ss,
- SequenceNumber _id,
- boost::intrusive_ptr<Message> msg )
- : IncompleteCommandContext(ss, _id),
- requiresAccept(msg->requiresAccept()),
- requiresSync(msg->getFrames().getMethod()->isSync()) {};
+ boost::intrusive_ptr<Message> m )
+ : AsyncCommandContext(ss, m->getCommandId()),
+ session(ss),
+ msg(m.get()),
+ requiresAccept(msg->requiresAccept()),
+ requiresSync(msg->getFrames().getMethod()->isSync()) {};
virtual ~IncompleteIngressMsgXfer() {};
- protected:
virtual void completed(bool);
+ virtual boost::intrusive_ptr<AsyncCompletion::Callback> clone();
private:
- /** meta-info required to complete the message */
+ SessionState *session; // only valid if sync == true
+ Message *msg; // only valid if sync == true
bool requiresAccept;
- bool requiresSync; // method's isSync() flag
+ bool requiresSync;
};
- /** creates a command context suitable for use as an AsyncCompletion in a message */
- boost::shared_ptr<SessionState::IncompleteIngressMsgXfer> createIngressMsgXferContext( boost::intrusive_ptr<Message> msg);
-
- /* A list of commands that are pending completion. These commands are
- * awaiting some set of asynchronous operations to finish (eg: store,
- * flow-control, etc). before the command can be completed to the client
- */
- std::map<SequenceNumber, boost::shared_ptr<IncompleteCommandContext> > incompleteCmds;
- qpid::sys::Mutex incompleteCmdsLock; // locks above container
-
- /** This context is shared between the SessionState and scheduledCompleter,
- * holds the sequence numbers of all commands that have completed asynchronously.
- */
- class ScheduledCompleterContext {
- private:
- std::list<SequenceNumber> completedCmds;
- // ordering: take this lock first, then incompleteCmdsLock
- qpid::sys::Mutex completedCmdsLock;
- SessionState *session;
- public:
- ScheduledCompleterContext(SessionState *s) : session(s) {};
- bool scheduleCompletion(SequenceNumber cmd);
- void completeCommands();
- void cancel();
- };
- boost::shared_ptr<ScheduledCompleterContext> scheduledCompleterContext;
-
- /** The following method runs the in IO thread and completes commands that
- * where finished asynchronously.
- */
- static void scheduledCompleter(boost::shared_ptr<ScheduledCompleterContext>);
friend class SessionManager;
};
diff --git a/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp b/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
index 4f35884af8..d616abadd6 100644
--- a/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
+++ b/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
@@ -28,6 +28,52 @@
namespace qpid {
namespace broker {
+namespace {
+const qmf::org::apache::qpid::broker::EventQueueThresholdExceeded EVENT("dummy", 0, 0);
+bool isQMFv2(const boost::intrusive_ptr<Message> message)
+{
+ const qpid::framing::MessageProperties* props = message->getProperties<qpid::framing::MessageProperties>();
+ return props && props->getAppId() == "qmf2";
+}
+
+bool isThresholdEvent(const boost::intrusive_ptr<Message> message)
+{
+ if (message->getIsManagementMessage()) {
+ //is this a qmf event? if so is it a threshold event?
+ if (isQMFv2(message)) {
+ const qpid::framing::FieldTable* headers = message->getApplicationHeaders();
+ if (headers && headers->getAsString("qmf.content") == "_event") {
+ //decode as list
+ std::string content = message->getFrames().getContent();
+ qpid::types::Variant::List list;
+ qpid::amqp_0_10::ListCodec::decode(content, list);
+ if (list.empty() || list.front().getType() != qpid::types::VAR_MAP) return false;
+ qpid::types::Variant::Map map = list.front().asMap();
+ try {
+ std::string eventName = map["_schema_id"].asMap()["_class_name"].asString();
+ return eventName == EVENT.getEventName();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Error checking for recursive threshold alert: " << e.what());
+ }
+ }
+ } else {
+ std::string content = message->getFrames().getContent();
+ qpid::framing::Buffer buffer(const_cast<char*>(content.data()), content.size());
+ if (buffer.getOctet() == 'A' && buffer.getOctet() == 'M' && buffer.getOctet() == '2' && buffer.getOctet() == 'e') {
+ buffer.getLong();//sequence
+ std::string packageName;
+ buffer.getShortString(packageName);
+ if (packageName != EVENT.getPackageName()) return false;
+ std::string eventName;
+ buffer.getShortString(eventName);
+ return eventName == EVENT.getEventName();
+ }
+ }
+ }
+ return false;
+}
+}
+
ThresholdAlerts::ThresholdAlerts(const std::string& n,
qpid::management::ManagementAgent& a,
const uint32_t ct,
@@ -44,8 +90,13 @@ void ThresholdAlerts::enqueued(const QueuedMessage& m)
if ((countThreshold && count >= countThreshold) || (sizeThreshold && size >= sizeThreshold)) {
if ((repeatInterval == 0 && lastAlert == qpid::sys::EPOCH)
|| qpid::sys::Duration(lastAlert, qpid::sys::now()) > repeatInterval) {
- agent.raiseEvent(qmf::org::apache::qpid::broker::EventQueueThresholdExceeded(name, count, size));
+ //Note: Raising an event may result in messages being
+ //enqueued on queues; it may even be that this event
+ //causes a message to be enqueued on the queue we are
+ //tracking, and so we need to avoid recursing
+ if (isThresholdEvent(m.payload)) return;
lastAlert = qpid::sys::now();
+ agent.raiseEvent(qmf::org::apache::qpid::broker::EventQueueThresholdExceeded(name, count, size));
}
}
}
@@ -75,12 +126,12 @@ void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& a
}
void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::framing::FieldTable& settings)
+ const qpid::framing::FieldTable& settings, uint16_t limitRatio)
{
qpid::types::Variant::Map map;
qpid::amqp_0_10::translate(settings, map);
- observe(queue, agent, map);
+ observe(queue, agent, map, limitRatio);
}
template <class T>
@@ -118,19 +169,19 @@ class Option
};
void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::types::Variant::Map& settings)
+ const qpid::types::Variant::Map& settings, uint16_t limitRatio)
{
//Note: aliases are keys defined by java broker
Option<int64_t> repeatInterval("qpid.alert_repeat_gap", 60);
repeatInterval.addAlias("x-qpid-minimum-alert-repeat-gap");
- //If no explicit threshold settings were given use 80% of any
- //limit from the policy.
+ //If no explicit threshold settings were given use specified
+ //percentage of any limit from the policy.
const QueuePolicy* policy = queue.getPolicy();
- Option<uint32_t> countThreshold("qpid.alert_count", (uint32_t) (policy ? policy->getMaxCount()*0.8 : 0));
+ Option<uint32_t> countThreshold("qpid.alert_count", (uint32_t) (policy && limitRatio ? (policy->getMaxCount()*limitRatio/100) : 0));
countThreshold.addAlias("x-qpid-maximum-message-count");
- Option<uint64_t> sizeThreshold("qpid.alert_size", (uint64_t) (policy ? policy->getMaxSize()*0.8 : 0));
+ Option<uint64_t> sizeThreshold("qpid.alert_size", (uint64_t) (policy && limitRatio ? (policy->getMaxSize()*limitRatio/100) : 0));
sizeThreshold.addAlias("x-qpid-maximum-message-size");
observe(queue, agent, countThreshold.get(settings), sizeThreshold.get(settings), repeatInterval.get(settings));
diff --git a/qpid/cpp/src/qpid/broker/ThresholdAlerts.h b/qpid/cpp/src/qpid/broker/ThresholdAlerts.h
index e1f59252c4..c77722e700 100644
--- a/qpid/cpp/src/qpid/broker/ThresholdAlerts.h
+++ b/qpid/cpp/src/qpid/broker/ThresholdAlerts.h
@@ -55,9 +55,9 @@ class ThresholdAlerts : public QueueObserver
const uint64_t sizeThreshold,
const long repeatInterval);
static void observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::framing::FieldTable& settings);
+ const qpid::framing::FieldTable& settings, uint16_t limitRatio);
static void observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::types::Variant::Map& settings);
+ const qpid::types::Variant::Map& settings, uint16_t limitRatio);
private:
const std::string name;
qpid::management::ManagementAgent& agent;
diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
index 1b0fe71bcf..f3baf00d1f 100644
--- a/qpid/cpp/src/qpid/broker/TopicExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/TopicExchange.cpp
@@ -221,6 +221,7 @@ TopicExchange::TopicExchange(const std::string& _name, bool _durable,
bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args)
{
+ ClearCache cc(&cacheLock,&bindingCache); // clear the cache on function exit.
string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
string fedTags(args ? args->getAsString(qpidFedTags) : "");
string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
@@ -288,6 +289,7 @@ bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, cons
}
bool TopicExchange::unbind(Queue::shared_ptr queue, const string& constRoutingKey, const FieldTable* /*args*/){
+ ClearCache cc(&cacheLock,&bindingCache); // clear the cache on function exit.
RWlock::ScopedWlock l(lock);
string routingKey = normalize(constRoutingKey);
BindingKey* bk = bindingTree.getBindingKey(routingKey);
@@ -333,13 +335,24 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string& pattern)
void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
{
// Note: PERFORMANCE CRITICAL!!!
- BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ BindingList b;
+ std::map<std::string, BindingList>::iterator it;
+ { // only lock the cache for read
+ RWlock::ScopedRlock cl(cacheLock);
+ it = bindingCache.find(routingKey);
+ }
PreRoute pr(msg, this);
- BindingsFinderIter bindingsFinder(b);
+ if (it == bindingCache.end()) // no cache hit
{
RWlock::ScopedRlock l(lock);
+ b = BindingList(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ BindingsFinderIter bindingsFinder(b);
bindingTree.iterateMatch(routingKey, bindingsFinder);
- }
+ RWlock::ScopedWlock cwl(cacheLock);
+ bindingCache[routingKey] = b; // update cache
+ }else {
+ b = it->second;
+ }
doRoute(msg, b);
}
diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.h b/qpid/cpp/src/qpid/broker/TopicExchange.h
index a6c457dcb3..3d2b3a95a9 100644
--- a/qpid/cpp/src/qpid/broker/TopicExchange.h
+++ b/qpid/cpp/src/qpid/broker/TopicExchange.h
@@ -135,7 +135,19 @@ class TopicExchange : public virtual Exchange {
BindingNode bindingTree;
unsigned long nBindings;
qpid::sys::RWlock lock; // protects bindingTree and nBindings
-
+ qpid::sys::RWlock cacheLock; // protects cache
+ std::map<std::string, BindingList> bindingCache; // cache of matched routes.
+ class ClearCache {
+ private:
+ qpid::sys::RWlock* cacheLock;
+ std::map<std::string, BindingList>* bindingCache;
+ public:
+ ClearCache(qpid::sys::RWlock* l, std::map<std::string, BindingList>* bc): cacheLock(l),bindingCache(bc) {};
+ ~ClearCache(){
+ qpid::sys::RWlock::ScopedWlock l(*cacheLock);
+ bindingCache->clear();
+ };
+ };
bool isBound(Queue::shared_ptr queue, const std::string& pattern);
class ReOriginIter;
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
index 8dc1e8338a..4fbf55aa60 100644
--- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -22,6 +22,7 @@
#include "qpid/client/ConnectionHandler.h"
#include "qpid/SaslFactory.h"
+#include "qpid/StringUtils.h"
#include "qpid/client/Bounds.h"
#include "qpid/framing/amqp_framing.h"
#include "qpid/framing/all_method_bodies.h"
@@ -202,6 +203,24 @@ void ConnectionHandler::fail(const std::string& message)
namespace {
std::string SPACE(" ");
+
+std::string join(const std::vector<std::string>& in)
+{
+ std::string result;
+ for (std::vector<std::string>::const_iterator i = in.begin(); i != in.end(); ++i) {
+ if (result.size()) result += SPACE;
+ result += *i;
+ }
+ return result;
+}
+
+void intersection(const std::vector<std::string>& a, const std::vector<std::string>& b, std::vector<std::string>& results)
+{
+ for (std::vector<std::string>::const_iterator i = a.begin(); i != a.end(); ++i) {
+ if (std::find(b.begin(), b.end(), *i) != b.end()) results.push_back(*i);
+ }
+}
+
}
void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& mechanisms, const Array& /*locales*/)
@@ -216,25 +235,24 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me
maxSsf
);
- std::string mechlist;
- bool chosenMechanismSupported = mechanism.empty();
- for (Array::const_iterator i = mechanisms.begin(); i != mechanisms.end(); ++i) {
- if (!mechanism.empty() && mechanism == (*i)->get<std::string>()) {
- chosenMechanismSupported = true;
- mechlist = (*i)->get<std::string>() + SPACE + mechlist;
- } else {
- if (i != mechanisms.begin()) mechlist += SPACE;
- mechlist += (*i)->get<std::string>();
+ std::vector<std::string> mechlist;
+ if (mechanism.empty()) {
+ //mechlist is simply what the server offers
+ mechanisms.collect(mechlist);
+ } else {
+ //mechlist is the intersection of those indicated by user and
+ //those supported by server, in the order listed by user
+ std::vector<std::string> allowed = split(mechanism, " ");
+ std::vector<std::string> supported;
+ mechanisms.collect(supported);
+ intersection(allowed, supported, mechlist);
+ if (mechlist.empty()) {
+ throw Exception(QPID_MSG("Desired mechanism(s) not valid: " << mechanism << " (supported: " << join(supported) << ")"));
}
}
- if (!chosenMechanismSupported) {
- fail("Selected mechanism not supported: " + mechanism);
- }
-
if (sasl.get()) {
- string response = sasl->start(mechanism.empty() ? mechlist : mechanism,
- getSecuritySettings ? getSecuritySettings() : 0);
+ string response = sasl->start(join(mechlist), getSecuritySettings ? getSecuritySettings() : 0);
proxy.startOk(properties, sasl->getMechanism(), response, locale);
} else {
//TODO: verify that desired mechanism and locale are supported
diff --git a/qpid/cpp/src/qpid/client/TCPConnector.cpp b/qpid/cpp/src/qpid/client/TCPConnector.cpp
index e284d57bec..d90781b365 100644
--- a/qpid/cpp/src/qpid/client/TCPConnector.cpp
+++ b/qpid/cpp/src/qpid/client/TCPConnector.cpp
@@ -117,7 +117,7 @@ void TCPConnector::connected(const Socket&) {
void TCPConnector::start(sys::AsynchIO* aio_) {
aio = aio_;
- for (int i = 0; i < 32; i++) {
+ for (int i = 0; i < 4; i++) {
aio->queueReadBuffer(new Buff(maxFrameSize));
}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
index 5a545c1f6a..a87a8dea67 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -39,6 +39,7 @@ using qpid::types::Variant;
using qpid::types::VAR_LIST;
using qpid::framing::Uuid;
+namespace {
void convert(const Variant::List& from, std::vector<std::string>& to)
{
for (Variant::List::const_iterator i = from.begin(); i != from.end(); ++i) {
@@ -46,19 +47,6 @@ void convert(const Variant::List& from, std::vector<std::string>& to)
}
}
-template <class T> bool setIfFound(const Variant::Map& map, const std::string& key, T& value)
-{
- Variant::Map::const_iterator i = map.find(key);
- if (i != map.end()) {
- value = (T) i->second;
- QPID_LOG(debug, "option " << key << " specified as " << i->second);
- return true;
- } else {
- return false;
- }
-}
-
-namespace {
std::string asString(const std::vector<std::string>& v) {
std::stringstream os;
os << "[";
@@ -71,47 +59,6 @@ std::string asString(const std::vector<std::string>& v) {
}
}
-template <> bool setIfFound< std::vector<std::string> >(const Variant::Map& map,
- const std::string& key,
- std::vector<std::string>& value)
-{
- Variant::Map::const_iterator i = map.find(key);
- if (i != map.end()) {
- value.clear();
- if (i->second.getType() == VAR_LIST) {
- convert(i->second.asList(), value);
- } else {
- value.push_back(i->second.asString());
- }
- QPID_LOG(debug, "option " << key << " specified as " << asString(value));
- return true;
- } else {
- return false;
- }
-}
-
-void convert(const Variant::Map& from, ConnectionSettings& to)
-{
- setIfFound(from, "username", to.username);
- setIfFound(from, "password", to.password);
- setIfFound(from, "sasl-mechanism", to.mechanism);
- setIfFound(from, "sasl-service", to.service);
- setIfFound(from, "sasl-min-ssf", to.minSsf);
- setIfFound(from, "sasl-max-ssf", to.maxSsf);
-
- setIfFound(from, "heartbeat", to.heartbeat);
- setIfFound(from, "tcp-nodelay", to.tcpNoDelay);
-
- setIfFound(from, "locale", to.locale);
- setIfFound(from, "max-channels", to.maxChannels);
- setIfFound(from, "max-frame-size", to.maxFrameSize);
- setIfFound(from, "bounds", to.bounds);
-
- setIfFound(from, "transport", to.protocol);
-
- setIfFound(from, "ssl-cert-name", to.sslCertName);
-}
-
ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options) :
reconnect(false), timeout(-1), limit(-1),
minReconnectInterval(3), maxReconnectInterval(60),
@@ -124,27 +71,64 @@ ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& optio
void ConnectionImpl::setOptions(const Variant::Map& options)
{
- sys::Mutex::ScopedLock l(lock);
- convert(options, settings);
- setIfFound(options, "reconnect", reconnect);
- setIfFound(options, "reconnect-timeout", timeout);
- setIfFound(options, "reconnect-limit", limit);
- int64_t reconnectInterval;
- if (setIfFound(options, "reconnect-interval", reconnectInterval)) {
- minReconnectInterval = maxReconnectInterval = reconnectInterval;
- } else {
- setIfFound(options, "reconnect-interval-min", minReconnectInterval);
- setIfFound(options, "reconnect-interval-max", maxReconnectInterval);
+ for (Variant::Map::const_iterator i = options.begin(); i != options.end(); ++i) {
+ setOption(i->first, i->second);
}
- setIfFound(options, "reconnect-urls", urls);
- setIfFound(options, "x-reconnect-on-limit-exceeded", reconnectOnLimitExceeded);
}
void ConnectionImpl::setOption(const std::string& name, const Variant& value)
{
- Variant::Map options;
- options[name] = value;
- setOptions(options);
+ sys::Mutex::ScopedLock l(lock);
+ if (name == "reconnect") {
+ reconnect = value;
+ } else if (name == "reconnect-timeout" || name == "reconnect_timeout") {
+ timeout = value;
+ } else if (name == "reconnect-limit" || name == "reconnect_limit") {
+ limit = value;
+ } else if (name == "reconnect-interval" || name == "reconnect_interval") {
+ maxReconnectInterval = minReconnectInterval = value;
+ } else if (name == "reconnect-interval-min" || name == "reconnect_interval_min") {
+ minReconnectInterval = value;
+ } else if (name == "reconnect-interval-max" || name == "reconnect_interval_max") {
+ maxReconnectInterval = value;
+ } else if (name == "reconnect-urls" || name == "reconnect_urls") {
+ if (value.getType() == VAR_LIST) {
+ convert(value.asList(), urls);
+ } else {
+ urls.push_back(value.asString());
+ }
+ } else if (name == "username") {
+ settings.username = value.asString();
+ } else if (name == "password") {
+ settings.password = value.asString();
+ } else if (name == "sasl-mechanism" || name == "sasl_mechanism" ||
+ name == "sasl-mechanisms" || name == "sasl_mechanisms") {
+ settings.mechanism = value.asString();
+ } else if (name == "sasl-service" || name == "sasl_service") {
+ settings.service = value.asString();
+ } else if (name == "sasl-min-ssf" || name == "sasl_min_ssf") {
+ settings.minSsf = value;
+ } else if (name == "sasl-max-ssf" || name == "sasl_max_ssf") {
+ settings.maxSsf = value;
+ } else if (name == "heartbeat") {
+ settings.heartbeat = value;
+ } else if (name == "tcp-nodelay" || name == "tcp_nodelay") {
+ settings.tcpNoDelay = value;
+ } else if (name == "locale") {
+ settings.locale = value.asString();
+ } else if (name == "max-channels" || name == "max_channels") {
+ settings.maxChannels = value;
+ } else if (name == "max-frame-size" || name == "max_frame_size") {
+ settings.maxFrameSize = value;
+ } else if (name == "bounds") {
+ settings.bounds = value;
+ } else if (name == "transport") {
+ settings.protocol = value.asString();
+ } else if (name == "ssl-cert-name" || name == "ssl_cert_name") {
+ settings.sslCertName = value.asString();
+ } else {
+ throw qpid::messaging::MessagingException(QPID_MSG("Invalid option: " << name << " not recognised"));
+ }
}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
index 82358961c8..d93416da75 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
@@ -59,7 +59,9 @@ void OutgoingMessage::convert(const qpid::messaging::Message& from)
message.getMessageProperties().setReplyTo(AddressResolution::convert(address));
}
translate(from.getProperties(), message.getMessageProperties().getApplicationHeaders());
- message.getDeliveryProperties().setTtl(from.getTtl().getMilliseconds());
+ if (from.getTtl().getMilliseconds()) {
+ message.getDeliveryProperties().setTtl(from.getTtl().getMilliseconds());
+ }
if (from.getDurable()) {
message.getDeliveryProperties().setDeliveryMode(DELIVERY_MODE_PERSISTENT);
}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
index e1b75ec0cf..f2f0f1a9e5 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -135,6 +135,7 @@ void SenderImpl::sendUnreliable(const qpid::messaging::Message& m)
void SenderImpl::replay(const sys::Mutex::ScopedLock&)
{
for (OutgoingMessages::iterator i = outgoing.begin(); i != outgoing.end(); ++i) {
+ i->message.setRedelivered(true);
sink->send(session, name, *i);
}
}
@@ -147,7 +148,7 @@ uint32_t SenderImpl::checkPendingSends(bool flush) {
uint32_t SenderImpl::checkPendingSends(bool flush, const sys::Mutex::ScopedLock&)
{
if (flush) {
- session.flush();
+ session.flush();
flushed = true;
} else {
flushed = false;
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp
index fe5a1c806e..a8a99d83b5 100644
--- a/qpid/cpp/src/qpid/cluster/Cluster.cpp
+++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp
@@ -943,6 +943,10 @@ void Cluster::checkUpdateIn(Lock& l) {
mAgent->suppress(false); // Enable management output.
mAgent->clusterUpdate();
}
+ // Restore alternate exchange settings on exchanges.
+ broker.getExchanges().eachExchange(
+ boost::bind(&broker::Exchange::recoveryComplete, _1,
+ boost::ref(broker.getExchanges())));
enableClusterSafe(); // Enable cluster-safe assertions
deliverEventQueue.start();
}
diff --git a/qpid/cpp/src/qpid/cluster/Connection.cpp b/qpid/cpp/src/qpid/cluster/Connection.cpp
index e9b718e6de..c1304c2b75 100644
--- a/qpid/cpp/src/qpid/cluster/Connection.cpp
+++ b/qpid/cpp/src/qpid/cluster/Connection.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -143,7 +143,7 @@ void Connection::init() {
// Called when we have consumed a read buffer to give credit to the
// connection layer to continue reading.
void Connection::giveReadCredit(int credit) {
- if (cluster.getSettings().readMax && credit)
+ if (cluster.getSettings().readMax && credit)
output.giveReadCredit(credit);
}
@@ -201,7 +201,7 @@ void Connection::received(framing::AMQFrame& f) {
}
else { // Shadow or updated catch-up connection.
if (f.getMethod() && f.getMethod()->isA<ConnectionCloseBody>()) {
- if (isShadow())
+ if (isShadow())
cluster.addShadowConnection(this);
AMQFrame ok((ConnectionCloseOkBody()));
connection->getOutput().send(ok);
@@ -241,7 +241,7 @@ void Connection::deliverDoOutput(uint32_t limit) {
void Connection::deliveredFrame(const EventFrame& f) {
GiveReadCreditOnExit gc(*this, f.readCredit);
assert(!catchUp);
- currentChannel = f.frame.getChannel();
+ currentChannel = f.frame.getChannel();
if (f.frame.getBody() // frame can be emtpy with just readCredit
&& !framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol.
&& !checkUnsupported(*f.frame.getBody())) // Unsupported operation.
@@ -287,7 +287,7 @@ void Connection::deliverClose () {
cluster.erase(self);
}
-// Close the connection
+// Close the connection
void Connection::close() {
if (connection.get()) {
QPID_LOG(debug, cluster << " closed connection " << *this);
@@ -332,9 +332,9 @@ size_t Connection::decode(const char* data, size_t size) {
if (!checkProtocolHeader(ptr, size)) // Updates ptr
return 0; // Incomplete header
- if (!connection->isOpen())
+ if (!connection->isOpen())
processInitialFrames(ptr, end-ptr); // Updates ptr
-
+
if (connection->isOpen() && end - ptr > 0) {
// We're multi-casting, we will give read credit on delivery.
grc.credit = 0;
@@ -432,7 +432,7 @@ void Connection::sessionState(
unknownCompleted,
receivedIncomplete);
QPID_LOG(debug, cluster << " received session state update for " << sessionState().getId());
- // The output tasks will be added later in the update process.
+ // The output tasks will be added later in the update process.
connection->getOutputTasks().removeAll();
}
@@ -478,7 +478,7 @@ void Connection::retractOffer() {
void Connection::closeUpdated() {
self.second = 0; // Mark this as completed update connection.
- if (connection.get())
+ if (connection.get())
connection->close(connection::CLOSE_CODE_NORMAL, "OK");
}
@@ -529,7 +529,7 @@ void Connection::deliveryRecord(const string& qname,
m = getUpdateMessage();
m.queue = queue.get();
m.position = position;
- if (enqueued) queue->updateEnqueued(m); //inform queue of the message
+ if (enqueued) queue->updateEnqueued(m); //inform queue of the message
} else { // Message at original position in original queue
m = queue->find(position);
}
@@ -591,7 +591,7 @@ void Connection::txEnqueue(const std::string& queue) {
void Connection::txPublish(const framing::Array& queues, bool delivered) {
boost::shared_ptr<broker::TxPublish> txPub(new broker::TxPublish(getUpdateMessage().payload));
- for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i)
+ for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i)
txPub->deliverTo(findQueue((*i)->get<std::string>()));
txPub->delivered = delivered;
txBuffer->enlist(txPub);
@@ -614,12 +614,6 @@ void Connection::exchange(const std::string& encoded) {
QPID_LOG(debug, cluster << " updated exchange " << ex->getName());
}
-void Connection::queue(const std::string& encoded) {
- Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
- broker::Queue::shared_ptr q = broker::Queue::decode(cluster.getBroker().getQueues(), buf);
- QPID_LOG(debug, cluster << " updated queue " << q->getName());
-}
-
void Connection::sessionError(uint16_t , const std::string& msg) {
// Ignore errors before isOpen(), we're not multicasting yet.
if (connection->isOpen())
@@ -678,6 +672,12 @@ void Connection::config(const std::string& encoded) {
else throw Exception(QPID_MSG("Update failed, invalid kind of config: " << kind));
}
+void Connection::doCatchupIoCallbacks() {
+ // We need to process IO callbacks during the catch-up phase in
+ // order to service asynchronous completions for messages
+ // transferred during catch-up.
+ if (catchUp) getBrokerConnection()->doIoCallbacks();
+}
}} // Namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/cluster/Connection.h b/qpid/cpp/src/qpid/cluster/Connection.h
index 7ee85bf1aa..8a9891deb6 100644
--- a/qpid/cpp/src/qpid/cluster/Connection.h
+++ b/qpid/cpp/src/qpid/cluster/Connection.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -62,7 +62,7 @@ class Connection :
public sys::ConnectionInputHandler,
public framing::AMQP_AllOperations::ClusterConnectionHandler,
private broker::Connection::ErrorListener
-
+
{
public:
@@ -73,7 +73,7 @@ class Connection :
Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, const ConnectionId& id,
const qpid::sys::SecuritySettings& external);
~Connection();
-
+
ConnectionId getId() const { return self; }
broker::Connection* getBrokerConnection() { return connection.get(); }
const broker::Connection* getBrokerConnection() const { return connection.get(); }
@@ -108,9 +108,9 @@ class Connection :
void deliveredFrame(const EventFrame&);
void consumerState(const std::string& name, bool blocked, bool notifyEnabled, const qpid::framing::SequenceNumber& position);
-
+
// ==== Used in catch-up mode to build initial state.
- //
+ //
// State update methods.
void shadowPrepare(const std::string&);
@@ -123,9 +123,9 @@ class Connection :
const framing::SequenceNumber& received,
const framing::SequenceSet& unknownCompleted,
const SequenceSet& receivedIncomplete);
-
+
void outputTask(uint16_t channel, const std::string& name);
-
+
void shadowReady(uint64_t memberId,
uint64_t connectionId,
const std::string& managementId,
@@ -163,8 +163,7 @@ class Connection :
void txEnd();
void accumulatedAck(const framing::SequenceSet&);
- // Encoded queue/exchange replication.
- void queue(const std::string& encoded);
+ // Encoded exchange replication.
void exchange(const std::string& encoded);
void giveReadCredit(int credit);
@@ -189,6 +188,8 @@ class Connection :
void setSecureConnection ( broker::SecureConnection * sc );
+ void doCatchupIoCallbacks();
+
private:
struct NullFrameHandler : public framing::FrameHandler {
void handle(framing::AMQFrame&) {}
@@ -233,7 +234,7 @@ class Connection :
// Error listener functions
void connectionError(const std::string&);
void sessionError(uint16_t channel, const std::string&);
-
+
void init();
bool checkUnsupported(const framing::AMQBody& body);
void deliverDoOutput(uint32_t limit);
diff --git a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
index 1354dab17b..13e95d1ec2 100644
--- a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
+++ b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -66,11 +66,14 @@ void OutputInterceptor::giveReadCredit(int32_t credit) {
}
// Called in write thread when the IO layer has no more data to write.
-// We do nothing in the write thread, we run doOutput only on delivery
-// of doOutput requests.
-bool OutputInterceptor::doOutput() { return false; }
+// We only process IO callbacks in the write thread during catch-up.
+// Normally we run doOutput only on delivery of doOutput requests.
+bool OutputInterceptor::doOutput() {
+ parent.doCatchupIoCallbacks();
+ return false;
+}
-// Send output up to limit, calculate new limit.
+// Send output up to limit, calculate new limit.
void OutputInterceptor::deliverDoOutput(uint32_t limit) {
sentDoOutput = false;
sendMax = limit;
@@ -78,7 +81,7 @@ void OutputInterceptor::deliverDoOutput(uint32_t limit) {
if (parent.isLocal()) {
size_t buffered = getBuffered();
if (buffered == 0 && sent == sendMax) // Could have sent more, increase the limit.
- newLimit = sendMax*2;
+ newLimit = sendMax*2;
else if (buffered > 0 && sent > 1) // Data left unsent, reduce the limit.
newLimit = (sendMax + sent) / 2;
}
diff --git a/qpid/cpp/src/qpid/cluster/UpdateDataExchange.cpp b/qpid/cpp/src/qpid/cluster/UpdateDataExchange.cpp
index 2a079b8881..e5cd82e3d3 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateDataExchange.cpp
+++ b/qpid/cpp/src/qpid/cluster/UpdateDataExchange.cpp
@@ -36,13 +36,8 @@ const std::string UpdateDataExchange::MANAGEMENT_AGENTS_KEY("management-agents")
const std::string UpdateDataExchange::MANAGEMENT_SCHEMAS_KEY("management-schemas");
const std::string UpdateDataExchange::MANAGEMENT_DELETED_OBJECTS_KEY("management-deleted-objects");
-std::ostream& operator<<(std::ostream& o, const UpdateDataExchange& c) {
- return o << "cluster(" << c.clusterId << " UPDATER)";
-}
-
UpdateDataExchange::UpdateDataExchange(Cluster& cluster) :
- Exchange(EXCHANGE_NAME, &cluster),
- clusterId(cluster.getId())
+ Exchange(EXCHANGE_NAME, &cluster)
{}
void UpdateDataExchange::route(broker::Deliverable& msg, const std::string& routingKey,
@@ -62,11 +57,9 @@ void UpdateDataExchange::updateManagementAgent(management::ManagementAgent* agen
framing::Buffer buf1(const_cast<char*>(managementAgents.data()), managementAgents.size());
agent->importAgents(buf1);
- QPID_LOG(debug, *this << " updated management agents.");
framing::Buffer buf2(const_cast<char*>(managementSchemas.data()), managementSchemas.size());
agent->importSchemas(buf2);
- QPID_LOG(debug, *this << " updated management schemas.");
using amqp_0_10::ListCodec;
using types::Variant;
@@ -78,7 +71,6 @@ void UpdateDataExchange::updateManagementAgent(management::ManagementAgent* agen
new management::ManagementAgent::DeletedObject(*i)));
}
agent->importDeletedObjects(objects);
- QPID_LOG(debug, *this << " updated management deleted objects.");
}
diff --git a/qpid/cpp/src/qpid/cluster/UpdateDataExchange.h b/qpid/cpp/src/qpid/cluster/UpdateDataExchange.h
index 8c493e400a..d2f6c35ad0 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateDataExchange.h
+++ b/qpid/cpp/src/qpid/cluster/UpdateDataExchange.h
@@ -74,11 +74,9 @@ class UpdateDataExchange : public broker::Exchange
void updateManagementAgent(management::ManagementAgent* agent);
private:
- MemberId clusterId;
std::string managementAgents;
std::string managementSchemas;
std::string managementDeletedObjects;
- friend std::ostream& operator<<(std::ostream&, const UpdateDataExchange&);
};
}} // namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index 8b4defaa73..7c9771fe79 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -75,6 +75,18 @@ namespace {
}
return n2;
}
+
+struct ScopedManagementContext
+{
+ ScopedManagementContext(const qpid::broker::ConnectionState* context)
+ {
+ setManagementExecutionContext(context);
+ }
+ ~ScopedManagementContext()
+ {
+ setManagementExecutionContext(0);
+ }
+};
}
@@ -536,6 +548,7 @@ void ManagementAgent::sendBufferLH(Buffer& buf,
dp->setRoutingKey(routingKey);
msg->getFrames().append(content);
+ msg->setIsManagementMessage(true);
{
sys::Mutex::ScopedUnlock u(userLock);
@@ -612,6 +625,7 @@ void ManagementAgent::sendBufferLH(const string& data,
msg->setTimestamp(broker->getExpiryPolicy());
}
msg->getFrames().append(content);
+ msg->setIsManagementMessage(true);
{
sys::Mutex::ScopedUnlock u(userLock);
@@ -2238,7 +2252,7 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
uint32_t bufferLen = inBuffer.getPosition();
inBuffer.reset();
- setManagementExecutionContext((const qpid::broker::ConnectionState*) msg.getPublisher());
+ ScopedManagementContext context((const qpid::broker::ConnectionState*) msg.getPublisher());
const framing::FieldTable *headers = msg.getApplicationHeaders();
if (headers && msg.getAppId() == "qmf2")
{
diff --git a/qpid/cpp/src/qpid/sys/ClusterSafe.cpp b/qpid/cpp/src/qpid/sys/ClusterSafe.cpp
index b67b04c267..dd37615145 100644
--- a/qpid/cpp/src/qpid/sys/ClusterSafe.cpp
+++ b/qpid/cpp/src/qpid/sys/ClusterSafe.cpp
@@ -51,6 +51,16 @@ ClusterSafeScope::~ClusterSafeScope() {
inContext = save;
}
+ClusterUnsafeScope::ClusterUnsafeScope() {
+ save = inContext;
+ inContext = false;
+}
+
+ClusterUnsafeScope::~ClusterUnsafeScope() {
+ assert(!inContext);
+ inContext = save;
+}
+
void enableClusterSafe() { inCluster = true; }
}} // namespace qpid::sys
diff --git a/qpid/cpp/src/qpid/sys/ClusterSafe.h b/qpid/cpp/src/qpid/sys/ClusterSafe.h
index 42e290f4c8..27e4eb46a5 100644
--- a/qpid/cpp/src/qpid/sys/ClusterSafe.h
+++ b/qpid/cpp/src/qpid/sys/ClusterSafe.h
@@ -53,10 +53,8 @@ QPID_COMMON_EXTERN void assertClusterSafe();
QPID_COMMON_EXTERN bool isClusterSafe();
/**
- * Base class for classes that encapsulate state which is replicated
- * to all members of a cluster. Acts as a marker for clustered state
- * and provides functions to assist detecting bugs in cluster
- * behavior.
+ * Mark a scope as cluster safe. Sets isClusterSafe in constructor and resets
+ * to previous value in destructor.
*/
class ClusterSafeScope {
public:
@@ -67,6 +65,18 @@ class ClusterSafeScope {
};
/**
+ * Mark a scope as cluster unsafe. Clears isClusterSafe in constructor and resets
+ * to previous value in destructor.
+ */
+class ClusterUnsafeScope {
+ public:
+ QPID_COMMON_EXTERN ClusterUnsafeScope();
+ QPID_COMMON_EXTERN ~ClusterUnsafeScope();
+ private:
+ bool save;
+};
+
+/**
* Enable cluster-safe assertions. By default they are no-ops.
* Called by cluster code.
*/
diff --git a/qpid/cpp/src/qpid/sys/SslPlugin.cpp b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
index b0e791d60b..0ec051caab 100644
--- a/qpid/cpp/src/qpid/sys/SslPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
@@ -95,7 +95,7 @@ static struct SslPlugin : public Plugin {
// Only provide to a Broker
if (broker) {
if (options.certDbPath.empty()) {
- QPID_LOG(info, "SSL plugin not enabled, you must set --ssl-cert-db to enable it.");
+ QPID_LOG(notice, "SSL plugin not enabled, you must set --ssl-cert-db to enable it.");
} else {
try {
ssl::initNSS(options, true);
diff --git a/qpid/cpp/src/qpid/types/Variant.cpp b/qpid/cpp/src/qpid/types/Variant.cpp
index 5d8878bdac..9cc3cfe5fc 100644
--- a/qpid/cpp/src/qpid/types/Variant.cpp
+++ b/qpid/cpp/src/qpid/types/Variant.cpp
@@ -108,7 +108,6 @@ class VariantImpl
} value;
std::string encoding;//optional encoding for variable length data
- std::string getTypeName(VariantType type) const;
template<class T> T convertFromString() const
{
std::string* s = reinterpret_cast<std::string*>(value.v);
@@ -582,7 +581,7 @@ const std::string& VariantImpl::getString() const
void VariantImpl::setEncoding(const std::string& s) { encoding = s; }
const std::string& VariantImpl::getEncoding() const { return encoding; }
-std::string VariantImpl::getTypeName(VariantType type) const
+std::string getTypeName(VariantType type)
{
switch (type) {
case VAR_VOID: return "void";
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index ffa4a65ba7..da01ee7588 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -287,18 +287,6 @@ check_PROGRAMS+=datagen
datagen_SOURCES=datagen.cpp
datagen_LDADD=$(lib_common) $(lib_client)
-check_PROGRAMS+=qrsh_server
-qrsh_server_SOURCES=qrsh_server.cpp
-qrsh_server_LDADD=$(lib_client)
-
-check_PROGRAMS+=qrsh_run
-qrsh_run_SOURCES=qrsh_run.cpp
-qrsh_run_LDADD=$(lib_client)
-
-check_PROGRAMS+=qrsh
-qrsh_SOURCES=qrsh.cpp
-qrsh_LDADD=$(lib_client)
-
check_PROGRAMS+=qpid-stream
qpid_stream_INCLUDES=$(PUBLIC_INCLUDES)
qpid_stream_SOURCES=qpid-stream.cpp
diff --git a/qpid/cpp/src/tests/MessageUtils.h b/qpid/cpp/src/tests/MessageUtils.h
index baca14cf4e..a1b140d484 100644
--- a/qpid/cpp/src/tests/MessageUtils.h
+++ b/qpid/cpp/src/tests/MessageUtils.h
@@ -20,7 +20,6 @@
*/
#include "qpid/broker/Message.h"
-#include "qpid/broker/AsyncCompletion.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/Uuid.h"
@@ -29,17 +28,6 @@ using namespace qpid;
using namespace broker;
using namespace framing;
-namespace {
- class DummyCompletion : public AsyncCompletion
- {
- public:
- DummyCompletion() {}
- virtual ~DummyCompletion() {}
- protected:
- void completed(bool) {}
- };
-}
-
namespace qpid {
namespace tests {
@@ -62,8 +50,6 @@ struct MessageUtils
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
if (durable)
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(2);
- boost::shared_ptr<AsyncCompletion>dc(new DummyCompletion());
- msg->setIngressCompletion(dc);
return msg;
}
diff --git a/qpid/cpp/src/tests/QueueTest.cpp b/qpid/cpp/src/tests/QueueTest.cpp
index e4e9897195..2059727e7b 100644
--- a/qpid/cpp/src/tests/QueueTest.cpp
+++ b/qpid/cpp/src/tests/QueueTest.cpp
@@ -88,8 +88,6 @@ intrusive_ptr<Message> create_message(std::string exchange, std::string routingK
msg->getFrames().append(method);
msg->getFrames().append(header);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
- boost::shared_ptr<AsyncCompletion>dc(new DummyCompletion());
- msg->setIngressCompletion(dc);
return msg;
}
@@ -637,7 +635,7 @@ QPID_AUTO_TEST_CASE(testLVQRecover){
Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
intrusive_ptr<Message> received;
- queue1->configure(args);
+ queue1->create(args);
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "A");
@@ -709,9 +707,9 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
args.setPersistLastNode();
Queue::shared_ptr queue1(new Queue("queue1", true, &testStore ));
- queue1->configure(args);
+ queue1->create(args);
Queue::shared_ptr queue2(new Queue("queue2", true, &testStore ));
- queue2->configure(args);
+ queue2->create(args);
intrusive_ptr<Message> msg1 = create_message("e", "A");
@@ -797,7 +795,7 @@ not requeued to the store.
Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
intrusive_ptr<Message> received;
- queue1->configure(args);
+ queue1->create(args);
// check requeue 1
intrusive_ptr<Message> msg1 = create_message("e", "C");
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 2d6a5b489d..5e9a150d8f 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -26,10 +26,11 @@ from qpid.datatypes import uuid4
from qpid.testlib import TestBase010
from qmf.console import Session
from qpid.datatypes import Message
+import qpid.messaging
class ACLFile:
- def __init__(self):
- self.f = open('data_dir/policy.acl','w');
+ def __init__(self, policy='data_dir/policy.acl'):
+ self.f = open(policy,'w')
def write(self,line):
self.f.write(line)
@@ -50,14 +51,24 @@ class ACLTests(TestBase010):
acl = self.qmf.getObjects(_class="acl")[0]
return acl.reloadACLFile()
+ def get_acl_file(self):
+ return ACLFile(self.config.defines.get("policy-file", "data_dir/policy.acl"))
+
def setUp(self):
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl allow all all\n')
aclf.close()
TestBase010.setUp(self)
self.startQmf()
self.reload_acl()
-
+
+ def tearDown(self):
+ aclf = self.get_acl_file()
+ aclf.write('acl allow all all\n')
+ aclf.close()
+ self.reload_acl()
+ TestBase010.tearDown(self)
+
#=====================================
# ACL general tests
#=====================================
@@ -66,7 +77,7 @@ class ACLTests(TestBase010):
"""
Test the deny all mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl allow anonymous all all\n')
aclf.write('acl allow bob@QPID create queue\n')
aclf.write('acl deny all all')
@@ -94,7 +105,7 @@ class ACLTests(TestBase010):
"""
Test the allow all mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID bind exchange\n')
aclf.write('acl allow all all')
aclf.close()
@@ -126,7 +137,7 @@ class ACLTests(TestBase010):
"""
Test empty groups
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl group\n')
aclf.write('acl group admins bob@QPID joe@QPID\n')
aclf.write('acl allow all all')
@@ -140,7 +151,7 @@ class ACLTests(TestBase010):
"""
Test illegal acl formats
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl group admins bob@QPID joe@QPID\n')
aclf.write('acl allow all all')
aclf.close()
@@ -154,7 +165,7 @@ class ACLTests(TestBase010):
Test illegal extension lines
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('group admins bob@QPID \n')
aclf.write(' \ \n')
aclf.write('joe@QPID \n')
@@ -172,7 +183,7 @@ class ACLTests(TestBase010):
"""
Test proper extention lines
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('group test1 joe@EXAMPLE.com \\ \n') # should be allowed
aclf.write(' jack@EXAMPLE.com \\ \n') # should be allowed
aclf.write('jill@TEST.COM \\ \n') # should be allowed
@@ -189,7 +200,7 @@ class ACLTests(TestBase010):
Test a user defined without a realm
Ex. group admin rajith
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('group admin bob\n') # shouldn't be allowed
aclf.write('acl deny admin bind exchange\n')
aclf.write('acl allow all all')
@@ -204,7 +215,7 @@ class ACLTests(TestBase010):
Test a user defined without a realm
Ex. group admin rajith
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('group test1 joe@EXAMPLE.com\n') # should be allowed
aclf.write('group test2 jack_123-jill@EXAMPLE.com\n') # should be allowed
aclf.write('group test4 host/somemachine.example.com@EXAMPLE.COM\n') # should be allowed
@@ -215,7 +226,7 @@ class ACLTests(TestBase010):
if (result.text.find("ACL format error",0,len(result.text)) != -1):
self.fail(result)
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('group test1 joe$H@EXAMPLE.com\n') # shouldn't be allowed
aclf.write('acl allow all all')
aclf.close()
@@ -233,7 +244,7 @@ class ACLTests(TestBase010):
Test illegal queue policy
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ding\n')
aclf.write('acl allow all all')
aclf.close()
@@ -249,7 +260,7 @@ class ACLTests(TestBase010):
Test illegal queue policy
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create queue name=q2 maxqueuesize=-1\n')
aclf.write('acl allow all all')
aclf.close()
@@ -260,7 +271,7 @@ class ACLTests(TestBase010):
if (result.text != expected):
self.fail(result)
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create queue name=q2 maxqueuesize=9223372036854775808\n')
aclf.write('acl allow all all')
aclf.close()
@@ -277,7 +288,7 @@ class ACLTests(TestBase010):
Test illegal queue policy
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create queue name=q2 maxqueuecount=-1\n')
aclf.write('acl allow all all')
aclf.close()
@@ -288,7 +299,7 @@ class ACLTests(TestBase010):
if (result.text != expected):
self.fail(result)
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create queue name=q2 maxqueuecount=9223372036854775808\n')
aclf.write('acl allow all all')
aclf.close()
@@ -308,7 +319,7 @@ class ACLTests(TestBase010):
"""
Test cases for queue acl in allow mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
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 policytype=ring\n')
aclf.write('acl deny bob@QPID access queue name=q3\n')
@@ -411,7 +422,7 @@ class ACLTests(TestBase010):
"""
Test cases for queue acl in deny mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
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 policytype=ring\n')
aclf.write('acl allow bob@QPID access queue name=q3\n')
@@ -534,7 +545,7 @@ class ACLTests(TestBase010):
"""
Test cases for exchange acl in allow mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n')
aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n')
aclf.write('acl deny bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n')
@@ -665,7 +676,7 @@ class ACLTests(TestBase010):
"""
Test cases for exchange acl in deny mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl allow bob@QPID create exchange name=myEx durable=true passive=false\n')
aclf.write('acl allow bob@QPID bind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
aclf.write('acl allow bob@QPID unbind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
@@ -772,6 +783,52 @@ class ACLTests(TestBase010):
if (403 == e.args[0].error_code):
self.fail("ACL should allow exchange delete request for myEx");
+ def test_create_and_delete_exchange_via_qmf(self):
+ """
+ Test acl is enforced when creating/deleting via QMF
+ methods. Note that in order to be able to send the QMF methods
+ and receive the responses a significant amount of permissions
+ need to be enabled (TODO: can the set below be narrowed down
+ at all?)
+ """
+ aclf = self.get_acl_file()
+ aclf.write('acl allow bob@QPID create exchange\n')
+ aclf.write('acl allow admin@QPID delete exchange\n')
+ aclf.write('acl allow all access exchange\n')
+ aclf.write('acl allow all bind exchange\n')
+ aclf.write('acl allow all create queue\n')
+ aclf.write('acl allow all access queue\n')
+ aclf.write('acl allow all delete queue\n')
+ aclf.write('acl allow all consume queue\n')
+ aclf.write('acl allow all access method\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)
+
+ bob = BrokerAdmin(self.config.broker, "bob", "bob")
+ bob.create_exchange("my-exchange") #should pass
+ #cleanup by deleting exchange
+ try:
+ bob.delete_exchange("my-exchange") #should fail
+ self.fail("ACL should deny exchange delete request for my-exchange");
+ except Exception, e:
+ self.assertEqual(7,e.args[0]["error_code"])
+ assert e.args[0]["error_text"].find("unauthorized-access") == 0
+ admin = BrokerAdmin(self.config.broker, "admin", "admin")
+ admin.delete_exchange("my-exchange") #should pass
+
+ anonymous = BrokerAdmin(self.config.broker)
+ try:
+ anonymous.create_exchange("another-exchange") #should fail
+ self.fail("ACL should deny exchange create request for another-exchange");
+ except Exception, e:
+ self.assertEqual(7,e.args[0]["error_code"])
+ assert e.args[0]["error_text"].find("unauthorized-access") == 0
+
+
#=====================================
# ACL consume tests
#=====================================
@@ -780,7 +837,7 @@ class ACLTests(TestBase010):
"""
Test cases for consume in allow mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID consume queue name=q1\n')
aclf.write('acl deny bob@QPID consume queue name=q2\n')
aclf.write('acl allow all all')
@@ -826,7 +883,7 @@ class ACLTests(TestBase010):
"""
Test cases for consume in allow mode
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl allow bob@QPID consume queue name=q1\n')
aclf.write('acl allow bob@QPID consume queue name=q2\n')
aclf.write('acl allow bob@QPID create queue\n')
@@ -872,7 +929,7 @@ class ACLTests(TestBase010):
"""
Test various publish acl
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
aclf.write('acl deny bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
aclf.write('acl deny bob@QPID publish exchange name=amq.topic\n')
aclf.write('acl deny bob@QPID publish exchange name=myEx routingkey=rk2\n')
@@ -921,7 +978,7 @@ class ACLTests(TestBase010):
"""
Test various publish acl
"""
- aclf = ACLFile()
+ aclf = self.get_acl_file()
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')
@@ -972,3 +1029,49 @@ class ACLTests(TestBase010):
except qpid.session.SessionException, e:
if (403 == e.args[0].error_code):
self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk1");
+
+class BrokerAdmin:
+ def __init__(self, broker, username=None, password=None):
+ self.connection = qpid.messaging.Connection(broker)
+ if username:
+ self.connection.username = username
+ self.connection.password = password
+ self.connection.sasl_mechanisms = "PLAIN"
+ self.connection.open()
+ self.session = self.connection.session()
+ self.sender = self.session.sender("qmf.default.direct/broker")
+ self.reply_to = "responses-#; {create:always}"
+ self.receiver = self.session.receiver(self.reply_to)
+
+ def invoke(self, method, arguments):
+ content = {
+ "_object_id": {"_object_name": "org.apache.qpid.broker:broker:amqp-broker"},
+ "_method_name": method,
+ "_arguments": arguments
+ }
+ request = qpid.messaging.Message(reply_to=self.reply_to, content=content)
+ request.properties["x-amqp-0-10.app-id"] = "qmf2"
+ request.properties["qmf.opcode"] = "_method_request"
+ self.sender.send(request)
+ response = self.receiver.fetch()
+ self.session.acknowledge()
+ if response.properties['x-amqp-0-10.app-id'] == 'qmf2':
+ if response.properties['qmf.opcode'] == '_method_response':
+ return response.content['_arguments']
+ elif response.properties['qmf.opcode'] == '_exception':
+ raise Exception(response.content['_values'])
+ else: raise Exception("Invalid response received, unexpected opcode: %s" % response.properties['qmf.opcode'])
+ else: raise Exception("Invalid response received, not a qmfv2 method: %s" % response.properties['x-amqp-0-10.app-id'])
+ def create_exchange(self, name, exchange_type=None, options={}):
+ properties = options
+ if exchange_type: properties["exchange_type"] = exchange_type
+ self.invoke("create", {"type": "exchange", "name":name, "properties":properties})
+
+ def create_queue(self, name, properties={}):
+ self.invoke("create", {"type": "queue", "name":name, "properties":properties})
+
+ def delete_exchange(self, name):
+ self.invoke("delete", {"type": "exchange", "name":name})
+
+ def delete_queue(self, name):
+ self.invoke("delete", {"type": "queue", "name":name})
diff --git a/qpid/cpp/src/tests/brokertest.py b/qpid/cpp/src/tests/brokertest.py
index 54327873db..67765c0e46 100644
--- a/qpid/cpp/src/tests/brokertest.py
+++ b/qpid/cpp/src/tests/brokertest.py
@@ -62,24 +62,6 @@ def is_running(pid):
class BadProcessStatus(Exception):
pass
-class ExceptionWrapper:
- """Proxy object that adds a message to exceptions raised"""
- def __init__(self, obj, msg):
- self.obj = obj
- self.msg = msg
-
- def __getattr__(self, name):
- func = getattr(self.obj, name)
- if type(func) != callable:
- return func
- return lambda *args, **kwargs: self._wrap(func, args, kwargs)
-
- def _wrap(self, func, args, kwargs):
- try:
- return func(*args, **kwargs)
- except Exception, e:
- raise Exception("%s: %s" %(self.msg, str(e)))
-
def error_line(filename, n=1):
"""Get the last n line(s) of filename for error messages"""
result = []
@@ -89,7 +71,8 @@ def error_line(filename, n=1):
for l in f:
if len(result) == n: result.pop(0)
result.append(" "+l)
- finally: f.close()
+ finally:
+ f.close()
except: return ""
return ":\n" + "".join(result)
@@ -97,111 +80,85 @@ def retry(function, timeout=10, delay=.01):
"""Call function until it returns True or timeout expires.
Double the delay for each retry. Return True if function
returns true, False if timeout expires."""
+ deadline = time.time() + timeout
while not function():
- if delay > timeout: delay = timeout
+ remaining = deadline - time.time()
+ if remaining <= 0: return False
+ delay = min(delay, remaining)
time.sleep(delay)
- timeout -= delay
- if timeout <= 0: return False
delay *= 2
return True
+class AtomicCounter:
+ def __init__(self):
+ self.count = 0
+ self.lock = Lock()
+
+ def next(self):
+ self.lock.acquire();
+ ret = self.count
+ self.count += 1
+ self.lock.release();
+ return ret
+
+_popen_id = AtomicCounter() # Popen identifier for use in output file names.
+
+# Constants for file descriptor arguments to Popen
+FILE = "FILE" # Write to file named after process
+PIPE = subprocess.PIPE
+
class Popen(subprocess.Popen):
"""
Can set and verify expectation of process status at end of test.
Dumps command line, stdout, stderr to data dir for debugging.
"""
- class DrainThread(Thread):
- """Thread to drain a file object and write the data to a file."""
- def __init__(self, infile, outname):
- Thread.__init__(self)
- self.infile, self.outname = infile, outname
- self.outfile = None
-
- def run(self):
- try:
- for line in self.infile:
- if self.outfile is None:
- self.outfile = open(self.outname, "w")
- self.outfile.write(line)
- finally:
- self.infile.close()
- if self.outfile is not None: self.outfile.close()
-
- class OutStream(ExceptionWrapper):
- """Wrapper for output streams, handles exceptions & draining output"""
- def __init__(self, infile, outfile, msg):
- ExceptionWrapper.__init__(self, infile, msg)
- self.infile, self.outfile = infile, outfile
- self.thread = None
-
- def drain(self):
- if self.thread is None:
- self.thread = Popen.DrainThread(self.infile, self.outfile)
- self.thread.start()
-
- def outfile(self, ext): return "%s.%s" % (self.pname, ext)
-
- def __init__(self, cmd, expect=EXPECT_EXIT_OK, drain=True):
- """Run cmd (should be a list of arguments)
+ def __init__(self, cmd, expect=EXPECT_EXIT_OK, stdin=None, stdout=FILE, stderr=FILE):
+ """Run cmd (should be a list of program and arguments)
expect - if set verify expectation at end of test.
- drain - if true (default) drain stdout/stderr to files.
+ stdout, stderr - can have the same values as for subprocess.Popen as well as
+ FILE (the default) which means write to a file named after the process.
+ stdin - like subprocess.Popen but defauts to PIPE
"""
self._clean = False
self._clean_lock = Lock()
assert find_exe(cmd[0]), "executable not found: "+cmd[0]
if type(cmd) is type(""): cmd = [cmd] # Make it a list.
self.cmd = [ str(x) for x in cmd ]
- self.returncode = None
self.expect = expect
+ self.id = _popen_id.next()
+ self.pname = "%s-%d" % (os.path.split(self.cmd[0])[1], self.id)
+ if stdout == FILE: stdout = open(self.outfile("out"), "w")
+ if stderr == FILE: stderr = open(self.outfile("err"), "w")
try:
- subprocess.Popen.__init__(self, self.cmd, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, close_fds=True)
- except ValueError: # Windows can't do close_fds
- subprocess.Popen.__init__(self, self.cmd, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE)
- self.pname = "%s-%d" % (os.path.split(self.cmd[0])[1], self.pid)
- msg = "Process %s" % self.pname
- self.stdin = ExceptionWrapper(self.stdin, msg)
- self.stdout = Popen.OutStream(self.stdout, self.outfile("out"), msg)
- self.stderr = Popen.OutStream(self.stderr, self.outfile("err"), msg)
+ subprocess.Popen.__init__(self, self.cmd, bufsize=0, executable=None,
+ stdin=stdin, stdout=stdout, stderr=stderr,
+ close_fds=True)
+ except ValueError: # Windows can't do close_fds
+ subprocess.Popen.__init__(self, self.cmd, bufsize=0, executable=None,
+ stdin=stdin, stdout=stdout, stderr=stderr)
+
f = open(self.outfile("cmd"), "w")
- try: f.write(self.cmd_str())
+ try: f.write("%s\n%d"%(self.cmd_str(), self.pid))
finally: f.close()
log.debug("Started process %s: %s" % (self.pname, " ".join(self.cmd)))
- if drain: self.drain()
-
- def __str__(self): return "Popen<%s>"%(self.pname)
- def drain(self):
- """Start threads to drain stdout/err"""
- self.stdout.drain()
- self.stderr.drain()
+ def __str__(self): return "Popen<%s>"%(self.pname)
- def _cleanup(self):
- """Close pipes to sub-process"""
- self._clean_lock.acquire()
- try:
- if self._clean: return
- self._clean = True
- self.stdin.close()
- self.drain() # Drain output pipes.
- self.stdout.thread.join() # Drain thread closes pipe.
- self.stderr.thread.join()
- finally: self._clean_lock.release()
+ def outfile(self, ext): return "%s.%s" % (self.pname, ext)
def unexpected(self,msg):
err = error_line(self.outfile("err")) or error_line(self.outfile("out"))
raise BadProcessStatus("%s %s%s" % (self.pname, msg, err))
-
+
def stop(self): # Clean up at end of test.
try:
if self.expect == EXPECT_UNKNOWN:
try: self.kill() # Just make sure its dead
except: pass
elif self.expect == EXPECT_RUNNING:
- try:
- self.kill()
- except:
- self.unexpected("expected running, exit code %d" % self.wait())
+ try: self.kill()
+ except: self.unexpected("expected running, exit code %d" % self.wait())
else:
retry(lambda: self.poll() is not None)
if self.returncode is None: # Still haven't stopped
@@ -213,40 +170,21 @@ class Popen(subprocess.Popen):
self.unexpected("expected error")
finally:
self.wait() # Clean up the process.
-
+
def communicate(self, input=None):
- if input:
- self.stdin.write(input)
- self.stdin.close()
- outerr = (self.stdout.read(), self.stderr.read())
- self.wait()
- return outerr
+ ret = subprocess.Popen.communicate(self, input)
+ self.cleanup()
+ return ret
- def is_running(self):
- return self.poll() is None
+ def is_running(self): return self.poll() is None
def assert_running(self):
if not self.is_running(): self.unexpected("Exit code %d" % self.returncode)
- def poll(self, _deadstate=None): # _deadstate required by base class in python 2.4
- if self.returncode is None:
- # Pass _deadstate only if it has been set, there is no _deadstate
- # parameter in Python 2.6
- if _deadstate is None: ret = subprocess.Popen.poll(self)
- else: ret = subprocess.Popen.poll(self, _deadstate)
-
- if (ret != -1):
- self.returncode = ret
- self._cleanup()
- return self.returncode
-
def wait(self):
- if self.returncode is None:
- self.drain()
- try: self.returncode = subprocess.Popen.wait(self)
- except OSError,e: raise OSError("Wait failed %s: %s"%(self.pname, e))
- self._cleanup()
- return self.returncode
+ ret = subprocess.Popen.wait(self)
+ self._cleanup()
+ return ret
def terminate(self):
try: subprocess.Popen.terminate(self)
@@ -255,7 +193,8 @@ class Popen(subprocess.Popen):
os.kill( self.pid , signal.SIGTERM)
except AttributeError: # no os.kill, using taskkill.. (Windows only)
os.popen('TASKKILL /PID ' +str(self.pid) + ' /F')
-
+ self._cleanup()
+
def kill(self):
try: subprocess.Popen.kill(self)
except AttributeError: # No terminate method
@@ -263,6 +202,20 @@ class Popen(subprocess.Popen):
os.kill( self.pid , signal.SIGKILL)
except AttributeError: # no os.kill, using taskkill.. (Windows only)
os.popen('TASKKILL /PID ' +str(self.pid) + ' /F')
+ self._cleanup()
+
+ def _cleanup(self):
+ """Clean up after a dead process"""
+ self._clean_lock.acquire()
+ if not self._clean:
+ self._clean = True
+ try: self.stdin.close()
+ except: pass
+ try: self.stdout.close()
+ except: pass
+ try: self.stderr.close()
+ except: pass
+ self._clean_lock.release()
def cmd_str(self): return " ".join([str(s) for s in self.cmd])
@@ -289,7 +242,7 @@ class Broker(Popen):
while (os.path.exists(self.log)):
self.log = "%s-%d.log" % (self.name, i)
i += 1
-
+
def get_log(self):
return os.path.abspath(self.log)
@@ -319,10 +272,10 @@ class Broker(Popen):
cmd += ["--log-to-file", self.log]
cmd += ["--log-to-stderr=no"]
if log_level != None:
- cmd += ["--log-enable=%s" % log_level]
+ cmd += ["--log-enable=%s" % log_level]
self.datadir = self.name
cmd += ["--data-dir", self.datadir]
- Popen.__init__(self, cmd, expect, drain=False)
+ Popen.__init__(self, cmd, expect, stdout=PIPE)
test.cleanup_stop(self)
self._host = "127.0.0.1"
log.debug("Started broker %s (%s, %s)" % (self.name, self.pname, self.log))
@@ -362,7 +315,7 @@ class Broker(Popen):
s = c.session(str(qpid.datatypes.uuid4()))
s.queue_declare(queue=queue)
c.close()
-
+
def _prep_sender(self, queue, durable, xprops):
s = queue + "; {create:always, node:{durable:" + str(durable)
if xprops != None: s += ", x-declare:{" + xprops + "}"
@@ -406,13 +359,14 @@ class Broker(Popen):
def log_ready(self):
"""Return true if the log file exists and contains a broker ready message"""
- if self._log_ready: return True
- self._log_ready = find_in_file("notice Broker running", self.log)
+ if not self._log_ready:
+ self._log_ready = find_in_file("notice Broker running", self.log)
+ return self._log_ready
def ready(self, **kwargs):
"""Wait till broker is ready to serve clients"""
# First make sure the broker is listening by checking the log.
- if not retry(self.log_ready, timeout=30):
+ if not retry(self.log_ready, timeout=60):
raise Exception(
"Timed out waiting for broker %s%s"%(self.name, error_line(self.log,5)))
# Create a connection and a session. For a cluster broker this will
@@ -421,17 +375,19 @@ class Broker(Popen):
c = self.connect(**kwargs)
try: c.session()
finally: c.close()
- except: raise RethrownException(
- "Broker %s failed ready test%s"%(self.name,error_line(self.log, 5)))
+ except Exception,e: raise RethrownException(
+ "Broker %s not responding: (%s)%s"%(self.name,e,error_line(self.log, 5)))
def store_state(self):
- uuids = open(os.path.join(self.datadir, "cluster", "store.status")).readlines()
+ f = open(os.path.join(self.datadir, "cluster", "store.status"))
+ try: uuids = f.readlines()
+ finally: f.close()
null_uuid="00000000-0000-0000-0000-000000000000\n"
if len(uuids) < 2: return "unknown" # we looked while the file was being updated.
if uuids[0] == null_uuid: return "empty"
if uuids[1] == null_uuid: return "dirty"
return "clean"
-
+
class Cluster:
"""A cluster of brokers in a test."""
@@ -495,7 +451,7 @@ class BrokerTest(TestCase):
rootdir = os.getcwd()
def configure(self, config): self.config=config
-
+
def setUp(self):
outdir = self.config.defines.get("OUTDIR") or "brokertest.tmp"
self.dir = os.path.join(self.rootdir, outdir, self.id())
@@ -516,10 +472,10 @@ class BrokerTest(TestCase):
"""Call thing.stop at end of test"""
self.stopem.append(stopable)
- def popen(self, cmd, expect=EXPECT_EXIT_OK, drain=True):
+ def popen(self, cmd, expect=EXPECT_EXIT_OK, stdin=None, stdout=FILE, stderr=FILE):
"""Start a process that will be killed at end of test, in the test dir."""
os.chdir(self.dir)
- p = Popen(cmd, expect, drain)
+ p = Popen(cmd, expect, stdin=stdin, stdout=stdout, stderr=stderr)
self.cleanup_stop(p)
return p
@@ -570,7 +526,7 @@ class StoppableThread(Thread):
self.stopped = True
self.join()
if self.error: raise self.error
-
+
class NumberedSender(Thread):
"""
Thread to run a sender client and send numbered messages until stopped.
@@ -589,7 +545,8 @@ class NumberedSender(Thread):
"--failover-updates",
"--content-stdin"
],
- expect=EXPECT_RUNNING)
+ expect=EXPECT_RUNNING,
+ stdin=PIPE)
self.condition = Condition()
self.max = max_depth
self.received = 0
@@ -629,7 +586,7 @@ class NumberedSender(Thread):
self.join()
self.write_message(-1) # end-of-messages marker.
if self.error: raise self.error
-
+
class NumberedReceiver(Thread):
"""
Thread to run a receiver client and verify it receives
@@ -649,14 +606,14 @@ class NumberedReceiver(Thread):
"--forever"
],
expect=EXPECT_RUNNING,
- drain=False)
+ stdout=PIPE)
self.lock = Lock()
self.error = None
self.sender = sender
def read_message(self):
return int(self.receiver.stdout.readline())
-
+
def run(self):
try:
self.received = 0
@@ -688,7 +645,7 @@ class ErrorGenerator(StoppableThread):
self.broker=broker
broker.test.cleanup_stop(self)
self.start()
-
+
def run(self):
c = self.broker.connect_old()
try:
diff --git a/qpid/cpp/src/tests/cli_tests.py b/qpid/cpp/src/tests/cli_tests.py
index deef03279d..6c75927461 100755
--- a/qpid/cpp/src/tests/cli_tests.py
+++ b/qpid/cpp/src/tests/cli_tests.py
@@ -365,6 +365,26 @@ class CliTests(TestBase010):
self.assertEqual(queue._altExchange_.name, altName)
self.assertEqual(found, True)
+ def test_qpid_config_list_queues_arguments(self):
+ """
+ Test to verify that when the type of a policy limit is
+ actually a string (though still a valid value), it does not
+ upset qpid-config
+ """
+ self.startQmf();
+ qmf = self.qmf
+
+ names = ["queue_capacity%s" % (i) for i in range(1, 6)]
+ for name in names:
+ self.session.queue_declare(queue=name, exclusive=True,
+ arguments={'qpid.max_count' : str(i), 'qpid.max_size': '100'})
+
+ output = os.popen(self.qpid_config_command(" queues")).readlines()
+ queues = [line.split()[0] for line in output[2:len(output)]] #ignore first two lines (header)
+
+ for name in names:
+ assert name in queues, "%s not in %s" % (name, queues)
+
def test_qpid_route(self):
self.startQmf();
qmf = self.qmf
@@ -405,7 +425,7 @@ class CliTests(TestBase010):
qmf = self.qmf
ret = self.qpid_route_api("dynamic add "
- + " --sasl-mechanism PLAIN "
+ + " --client-sasl-mechanism PLAIN "
+ "guest/guest@localhost:"+str(self.broker.port) + " "
+ str(self.remote_host())+":"+str(self.remote_port()) + " "
+"amq.direct")
@@ -424,7 +444,7 @@ class CliTests(TestBase010):
qmf = self.qmf
ret = self.qpid_route_api("dynamic add "
- + " --sasl-mechanism PLAIN "
+ + " --client-sasl-mechanism PLAIN "
+ "localhost:"+str(self.broker.port) + " "
+ str(self.remote_host())+":"+str(self.remote_port()) + " "
+"amq.direct")
diff --git a/qpid/cpp/src/tests/cluster_test_logs.py b/qpid/cpp/src/tests/cluster_test_logs.py
index 1fa9014d11..9f7d1e2f6c 100755
--- a/qpid/cpp/src/tests/cluster_test_logs.py
+++ b/qpid/cpp/src/tests/cluster_test_logs.py
@@ -60,9 +60,11 @@ def filter_log(log):
'task overran',
'warning CLOSING .* unsent data',
'Inter-broker link ',
- 'Running in a cluster, marking store'
+ 'Running in a cluster, marking store',
+ 'debug Sending keepalive signal to watchdog', # Watchdog timer thread
+ 'last broker standing joined by 1 replicas, updating queue policies.',
+ 'Connection .* timed out: closing' # heartbeat connection close
])
- skip_re = re.compile(skip)
# Regex to match a UUID
uuid='\w\w\w\w\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w\w\w\w\w\w\w\w\w'
# Substitutions to remove expected differences
@@ -80,6 +82,13 @@ def filter_log(log):
(r' map={.*_object_name:([^,}]*)[,}].*', r' \1'), # V2 map - just keep name
(r'\d+-\d+-\d+--\d+', 'X-X-X--X'), # V1 Object IDs
]
+ # Substitutions to mask known issue: durable test shows inconsistent "changed stats for com.redhat.rhm.store:journal" messages.
+ skip += '|Changed V[12] statistics com.redhat.rhm.store:journal'
+ subs += [(r'to=console.obj.1.0.com.redhat.rhm.store.journal props=\d+ stats=\d+',
+ 'to=console.obj.1.0.com.redhat.rhm.store.journal props=NN stats=NN')]
+
+ skip_re = re.compile(skip)
+ subs = [(re.compile(pattern), subst) for pattern, subst in subs]
for l in open(log):
if skip_re.search(l): continue
for pattern,subst in subs: l = re.sub(pattern,subst,l)
diff --git a/qpid/cpp/src/tests/cluster_tests.py b/qpid/cpp/src/tests/cluster_tests.py
index 3e13a3ce8a..42f3ae3d25 100755
--- a/qpid/cpp/src/tests/cluster_tests.py
+++ b/qpid/cpp/src/tests/cluster_tests.py
@@ -22,7 +22,7 @@ import os, signal, sys, time, imp, re, subprocess, glob, cluster_test_logs
from qpid import datatypes, messaging
from brokertest import *
from qpid.harness import Skipped
-from qpid.messaging import Message, Empty
+from qpid.messaging import Message, Empty, Disposition, REJECTED
from threading import Thread, Lock, Condition
from logging import getLogger
from itertools import chain
@@ -246,25 +246,6 @@ acl allow all all
session1 = cluster[1].connect().session()
for q in queues: self.assert_browse(session1, "q1", ["foo"])
- def test_dr_no_message(self):
- """Regression test for https://bugzilla.redhat.com/show_bug.cgi?id=655141
- Joining broker crashes with 'error deliveryRecord no update message'
- """
-
- cluster = self.cluster(1)
- session0 = cluster[0].connect().session()
- s = session0.sender("q1;{create:always}")
- s.send(Message("a", ttl=0.05), sync=False)
- s.send(Message("b", ttl=0.05), sync=False)
- r1 = session0.receiver("q1")
- self.assertEqual("a", r1.fetch(timeout=0).content)
- r2 = session0.receiver("q1;{mode:browse}")
- self.assertEqual("b", r2.fetch(timeout=0).content)
- # Leave messages un-acknowledged, let the expire, then start new broker.
- time.sleep(.1)
- cluster.start()
- self.assertRaises(Empty, cluster[1].connect().session().receiver("q1").fetch,0)
-
def test_route_update(self):
"""Regression test for https://issues.apache.org/jira/browse/QPID-2982
Links and bridges associated with routes were not replicated on update.
@@ -304,6 +285,36 @@ acl allow all all
# Verify logs are consistent
cluster_test_logs.verify_logs()
+ def test_redelivered(self):
+ """Verify that redelivered flag is set correctly on replayed messages"""
+ cluster = self.cluster(2, expect=EXPECT_EXIT_FAIL)
+ url = "amqp:tcp:%s,tcp:%s" % (cluster[0].host_port(), cluster[1].host_port())
+ queue = "my-queue"
+ cluster[0].declare_queue(queue)
+ self.sender = self.popen(
+ ["qpid-send",
+ "--broker", url,
+ "--address", queue,
+ "--sequence=true",
+ "--send-eos=1",
+ "--messages=100000",
+ "--connection-options={reconnect:true}"
+ ])
+ self.receiver = self.popen(
+ ["qpid-receive",
+ "--broker", url,
+ "--address", queue,
+ "--ignore-duplicates",
+ "--check-redelivered",
+ "--connection-options={reconnect:true}",
+ "--forever"
+ ])
+ time.sleep(1)#give sender enough time to have some messages to replay
+ cluster[0].kill()
+ self.sender.wait()
+ self.receiver.wait()
+ cluster[1].kill()
+
class BlockedSend(Thread):
"""Send a message, send is expected to block.
Verify that it does block (for a given timeout), then allow
@@ -411,6 +422,33 @@ acl allow all all
return cluster[1]
self.queue_flowlimit_test(Brokers())
+ def test_alternate_exchange_update(self):
+ """Verify that alternate-exchange on exchanges and queues is propagated to new members of a cluster. """
+ cluster = self.cluster(1)
+ s0 = cluster[0].connect().session()
+ # create alt queue bound to amq.fanout exchange, will be destination for alternate exchanges
+ self.evaluate_address(s0, "alt;{create:always,node:{x-bindings:[{exchange:'amq.fanout',queue:alt}]}}")
+ # create direct exchange ex with alternate-exchange amq.fanout and no queues bound
+ self.evaluate_address(s0, "ex;{create:always,node:{type:topic, x-declare:{type:'direct', alternate-exchange:'amq.fanout'}}}")
+ # create queue q with alternate-exchange amq.fanout
+ self.evaluate_address(s0, "q;{create:always,node:{type:queue, x-declare:{alternate-exchange:'amq.fanout'}}}")
+
+ def verify(broker):
+ s = broker.connect().session()
+ # Verify unmatched message goes to ex's alternate.
+ s.sender("ex").send("foo")
+ self.assertEqual("foo", s.receiver("alt").fetch(timeout=0).content)
+ # Verify rejected message goes to q's alternate.
+ s.sender("q").send("bar")
+ msg = s.receiver("q").fetch(timeout=0)
+ self.assertEqual("bar", msg.content)
+ s.acknowledge(msg, Disposition(REJECTED)) # Reject the message
+ self.assertEqual("bar", s.receiver("alt").fetch(timeout=0).content)
+
+ verify(cluster[0])
+ cluster.start()
+ verify(cluster[1])
+
class LongTests(BrokerTest):
"""Tests that can run for a long time if -DDURATION=<minutes> is set"""
def duration(self):
@@ -469,24 +507,24 @@ class LongTests(BrokerTest):
if self.stopped: break
self.process = self.broker.test.popen(
self.cmd, expect=EXPECT_UNKNOWN)
- finally: self.lock.release()
- try: exit = self.process.wait()
+ finally:
+ self.lock.release()
+ try:
+ exit = self.process.wait()
except OSError, e:
- # Seems to be a race in wait(), it throws
- # "no such process" during test shutdown.
- # Doesn't indicate a test error, ignore.
- return
+ # Process may already have been killed by self.stop()
+ break
except Exception, e:
self.process.unexpected(
"client of %s: %s"%(self.broker.name, e))
self.lock.acquire()
try:
- # Quit and ignore errors if stopped or expecting failure.
if self.stopped: break
if exit != 0:
self.process.unexpected(
"client of %s exit code %s"%(self.broker.name, exit))
- finally: self.lock.release()
+ finally:
+ self.lock.release()
except Exception, e:
self.error = RethrownException("Error in ClientLoop.run")
@@ -517,8 +555,10 @@ class LongTests(BrokerTest):
"""Start ordinary clients for a broker."""
cmds=[
["qpid-tool", "localhost:%s"%(broker.port())],
- ["qpid-perftest", "--count", 50000,
+ ["qpid-perftest", "--count=5000", "--durable=yes",
"--base-name", str(qpid.datatypes.uuid4()), "--port", broker.port()],
+ ["qpid-txtest", "--queue-base-name", "tx-%s"%str(qpid.datatypes.uuid4()),
+ "--port", broker.port()],
["qpid-queue-stats", "-a", "localhost:%s" %(broker.port())],
["testagent", "localhost", str(broker.port())] ]
clients.append([ClientLoop(broker, cmd) for cmd in cmds])
@@ -529,7 +569,8 @@ class LongTests(BrokerTest):
mclients.append(ClientLoop(broker, cmd))
endtime = time.time() + self.duration()
- runtime = self.duration() / 4 # First run is longer, use quarter of duration.
+ # For long duration, first run is a quarter of the duration.
+ runtime = max(5, self.duration() / 4.0)
alive = 0 # First live cluster member
for i in range(len(cluster)): start_clients(cluster[i])
start_mclients(cluster[alive])
@@ -555,14 +596,13 @@ class LongTests(BrokerTest):
start_mclients(cluster[alive])
for c in chain(mclients, *clients):
c.stop()
-
# Verify that logs are consistent
cluster_test_logs.verify_logs()
def test_management_qmf2(self):
self.test_management(args=["--mgmt-qmf2=yes"])
- def test_connect_consistent(self): # FIXME aconway 2011-01-18:
+ def test_connect_consistent(self):
args=["--mgmt-pub-interval=1","--log-enable=trace+:management"]
cluster = self.cluster(2, args=args)
end = time.time() + self.duration()
diff --git a/qpid/cpp/src/tests/python_tests b/qpid/cpp/src/tests/python_tests
index e367004a71..0216b5ca7b 100755
--- a/qpid/cpp/src/tests/python_tests
+++ b/qpid/cpp/src/tests/python_tests
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/src/tests/qpid-perftest.cpp b/qpid/cpp/src/tests/qpid-perftest.cpp
index 4d7b563c8c..8a5cf05775 100644
--- a/qpid/cpp/src/tests/qpid-perftest.cpp
+++ b/qpid/cpp/src/tests/qpid-perftest.cpp
@@ -423,8 +423,10 @@ struct Controller : public Client {
process(opts.totalSubs, subDone, fqn("sub_done"), boost::ref(subRates));
AbsTime end=now();
-
double time=secs(start, end);
+ if (time <= 0.0) {
+ throw Exception("ERROR: Test completed in zero seconds. Try again with a larger message count.");
+ }
double txrate=opts.transfers/time;
double mbytes=(txrate*opts.size)/(1024*1024);
@@ -543,6 +545,9 @@ struct PublishThread : public Client {
if (opts.confirm) session.sync();
AbsTime end=now();
double time=secs(start,end);
+ if (time <= 0.0) {
+ throw Exception("ERROR: Test completed in zero seconds. Try again with a larger message count.");
+ }
// Send result to controller.
Message report(lexical_cast<string>(opts.count/time), fqn("pub_done"));
diff --git a/qpid/cpp/src/tests/qpid-receive.cpp b/qpid/cpp/src/tests/qpid-receive.cpp
index 3189a13c6e..5a85da4fd2 100644
--- a/qpid/cpp/src/tests/qpid-receive.cpp
+++ b/qpid/cpp/src/tests/qpid-receive.cpp
@@ -53,6 +53,7 @@ struct Options : public qpid::Options
bool forever;
uint messages;
bool ignoreDuplicates;
+ bool checkRedelivered;
uint capacity;
uint ackFrequency;
uint tx;
@@ -75,6 +76,7 @@ struct Options : public qpid::Options
forever(false),
messages(0),
ignoreDuplicates(false),
+ checkRedelivered(false),
capacity(1000),
ackFrequency(100),
tx(0),
@@ -96,6 +98,7 @@ struct Options : public qpid::Options
("forever,f", qpid::optValue(forever), "ignore timeout and wait forever")
("messages,m", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely")
("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)")
+ ("check-redelivered", qpid::optValue(checkRedelivered), "Fails with exception if a duplicate is not marked as redelivered (only relevant when ignore-duplicates is selected)")
("capacity", qpid::optValue(capacity, "N"), "Pre-fetch window (0 implies no pre-fetch)")
("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)")
("tx", qpid::optValue(tx, "N"), "batch size for transactions (0 implies transaction are not used)")
@@ -216,6 +219,8 @@ int main(int argc, char ** argv)
std::cout << msg.getContent() << std::endl;//TODO: handle map or list messages
if (opts.messages && count >= opts.messages) done = true;
}
+ } else if (opts.checkRedelivered && !msg.getRedelivered()) {
+ throw qpid::Exception("duplicate sequence number received, message not marked as redelivered!");
}
if (opts.tx && (count % opts.tx == 0)) {
if (opts.rollbackFrequency && (++txCount % opts.rollbackFrequency == 0)) {
diff --git a/qpid/cpp/src/tests/qrsh.cpp b/qpid/cpp/src/tests/qrsh.cpp
deleted file mode 100644
index 0cb52b6b05..0000000000
--- a/qpid/cpp/src/tests/qrsh.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <qpid/client/Connection.h>
-#include <qpid/client/Session.h>
-#include <qpid/client/AsyncSession.h>
-#include <qpid/client/Message.h>
-#include <qpid/client/MessageListener.h>
-#include <qpid/client/SubscriptionManager.h>
-
-#include <stdio.h>
-#include <cstdlib>
-#include <iostream>
-
-#include <sstream>
-
-using namespace qpid::client;
-using namespace qpid::framing;
-
-using namespace std;
-
-namespace qpid {
-namespace tests {
-
-class ResponseListener : public MessageListener
-{
- public :
-
- int exitCode;
-
- ResponseListener ( SubscriptionManager & subscriptions )
- : exitCode(-1),
- subscriptions ( subscriptions )
- {
- }
-
- virtual void
- received ( Message & message )
- {
- char first_word[1000];
- sscanf ( message.getData().c_str(), "%s", first_word );
-
- if ( ! strcmp ( first_word, "wait_response" ) )
- {
- // If we receive a message here, parse out the exit code.
- sscanf ( message.getData().c_str(), "%*s%d", & exitCode );
- subscriptions.cancel(message.getDestination());
- }
- else
- if ( ! strcmp ( first_word, "get_response" ) )
- {
- // The remainder of the message is the file we requested.
- fprintf ( stdout,
- "%s",
- message.getData().c_str() + strlen("get_response" )
- );
- subscriptions.cancel(message.getDestination());
- }
- }
-
-
- private :
-
- SubscriptionManager & subscriptions;
-};
-
-}} // namespace qpid::tests
-
-using namespace qpid::tests;
-
-/*
- * argv[1] host
- * argv[2] port
- * argv[3] server name
- * argv[4] command name
- * argv[5..N] args to the command
- */
-int
-main ( int argc, char ** argv )
-{
- const char* host = argv[1];
- int port = atoi(argv[2]);
-
-
- Connection connection;
-
- try
- {
- connection.open ( host, port );
- Session session = connection.newSession ( );
-
- // Make a queue and bind it to fanout.
- string myQueue = session.getId().getName();
-
- session.queueDeclare ( arg::queue=myQueue,
- arg::exclusive=true,
- arg::autoDelete=true
- );
-
- session.exchangeBind ( arg::exchange="amq.fanout",
- arg::queue=myQueue,
- arg::bindingKey="my-key"
- );
-
- // Get ready to listen for the wait-response.
- // or maybe a get-response.
- // ( Although this may not be one of those types
- // of command, get ready anyway.
- SubscriptionManager subscriptions ( session );
- ResponseListener responseListener ( subscriptions );
- subscriptions.subscribe ( responseListener, myQueue );
-
- bool response_command = false;
- if(! strcmp("exec_wait", argv[4] ))
- response_command = true;
- else
- if(! strcmp("exited", argv[4] ))
- response_command = true;
- else
- if(! strcmp("get", argv[4] ))
- response_command = true;
-
- // Send the payload message.
- // Skip "qrsh host_name port"
- Message message;
- stringstream ss;
- for ( int i = 3; i < argc; ++ i )
- ss << argv[i] << ' ';
-
- message.setData ( ss.str() );
-
- session.messageTransfer(arg::content=message,
- arg::destination="amq.fanout");
-
- if ( response_command )
- subscriptions.run();
-
- session.close();
- connection.close();
- return responseListener.exitCode;
- }
- catch ( exception const & e)
- {
- cerr << e.what() << endl;
- }
-
- return 1;
-}
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_run.cpp b/qpid/cpp/src/tests/qrsh_run.cpp
deleted file mode 100644
index cfdd0cef80..0000000000
--- a/qpid/cpp/src/tests/qrsh_run.cpp
+++ /dev/null
@@ -1,321 +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 <iostream>
-#include <sstream>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-
-using namespace std;
-
-
-
-int
-main ( int argc, char ** argv )
-{
- int exit_code = -1;
- int fd[2];
- int my_pid = getpid();
- int child_pid;
-
- pipe(fd);
-
- char const * root_dir = argv[1]; // This arg is prepended by qrsh_server.
- char const * child_name = argv[2]; // This arg comes from qrsh.
- char const * child_path = argv[3]; // This arg comes from qrsh.
-
- // This is the problem..
- fprintf ( stderr, "MDEBUG qrsh_run: root_dir: |%s|\n", root_dir );
- fprintf ( stderr, "MDEBUG qrsh_run: child_name: |%s|\n", child_name );
- fprintf ( stderr, "MDEBUG qrsh_run: child_path: |%s|\n", child_path );
-
- /*
- * A named child is one for whom we will create a directory and
- * store information. There are some magic names that are not
- * real symbolic names -- but are instead the names of actions.
- */
-
- bool named_child = true;
-
- if ( ! strcmp ( child_name, "exec" ) )
- named_child = false;
- else
- if ( ! strcmp ( child_name, "exec_wait" ) )
- named_child = false;
- else
- if ( ! strcmp ( child_name, "exited" ) )
- named_child = false;
- else
- named_child = true;
-
- stringstream child_dir_name;
-
- if ( named_child )
- {
- child_dir_name << root_dir
- << '/'
- << child_name;
-
- /*
- * Make the child directory before forking, or there is
- * a race in which the child might be trying to make its
- * stdout and stderr files while we are tring to make
- * the directory.
- */
- if ( -1 == mkdir ( child_dir_name.str().c_str(), 0777 ) )
- {
- fprintf ( stderr,
- "qrsh_run error: Can't mkdir |%s|\n",
- child_dir_name.str().c_str()
- );
- exit ( 1 );
- }
-
- }
- else
- /*
- * If this is an 'exited' command that means we are
- * waiting for a pre-existing child.
- */
- if ( ! strcmp ( child_name, "exited" ) )
- {
- int wait_pid = atoi(child_path);
-
- // Find the child's symbolic name.
- stringstream pid_to_name_file_name;
- pid_to_name_file_name << root_dir
- << '/'
- << wait_pid;
- FILE * fp = fopen ( pid_to_name_file_name.str().c_str(), "r" );
- if (! fp)
- {
- fprintf ( stderr,
- "qrsh_run %d error: Can't open pid2name file |%s|.\n",
- my_pid,
- pid_to_name_file_name.str().c_str()
- );
- exit(1);
- }
- char symbolic_name[1000];
- strcpy ( symbolic_name, "qrsh_no_name" );
- fscanf ( fp, "%s", symbolic_name );
- fclose ( fp );
-
- // Make the name of the child's exit code file.
- stringstream exit_code_file_name;
- exit_code_file_name << root_dir
- << '/'
- << symbolic_name
- << "/exit_code";
-
- struct stat stat_buf;
- int file_does_not_exist = stat ( exit_code_file_name.str().c_str(), & stat_buf );
-
- /*
- * If the result of stat is zero, the file exists, which means that
- * the command has exited. The question we are being asked here is
- * "has it exited yet?"
- */
- if ( ! file_does_not_exist )
- return 1;
- else
- if ( errno == ENOENT )
- return 0;
- else
- return 2 ;
- }
-
-
- // We are not waiting on a pre-wxiting child: we have a
- // new child to create.
-
- child_pid = fork();
-
- if ( child_pid == 0 )
- {
- // This code is executed in the child process.
-
- // If it's a *named* child, then redirect its stdout and stderr.
- if ( named_child )
- {
- stringstream stdout_path,
- stderr_path;
-
- // Redirect the child's stdout. -----------------
- stdout_path << root_dir
- << '/'
- << child_name
- << '/'
- << "stdout";
-
- int redirected_stdout = open ( stdout_path.str().c_str(),
- O_WRONLY|O_CREAT|O_TRUNC,
- S_IRWXU|S_IRWXG|S_IRWXO
- );
- if ( redirected_stdout < 0 )
- {
- perror ( "qrsh_run: error opening redirected_stdout: " );
- fprintf ( stderr, "stdout path: |%s|\n", stdout_path.str().c_str() );
- exit ( 1 );
- }
- if ( -1 == dup2 ( redirected_stdout, 1 ) )
- {
- perror ( "qrsh_run: dup2 (stdout) error: " );
- exit(1);
- }
-
- // Redirect the child's stderr. -----------------
- stderr_path << root_dir
- << '/'
- << child_name
- << '/'
- << "stderr";
-
- int redirected_stderr = open ( stderr_path.str().c_str(),
- O_WRONLY|O_CREAT|O_TRUNC,
- S_IRWXU|S_IRWXG|S_IRWXO
- );
- if ( redirected_stderr < 0 )
- {
- perror ( "qrsh_run: error opening redirected_stderr: " );
- fprintf ( stderr, "stderr path: |%s|\n", stderr_path.str().c_str() );
- exit ( 1 );
- }
- if(-1 == dup2 ( redirected_stderr, 2 ) )
- {
- perror ( "qrsh_run: dup2 (stderr) error: " );
- exit(1);
- }
- }
-
- fprintf ( stderr, "MDEBUG ------------- qrsh_run argv -------------\n" );
- for ( int i = 0; i < argc; ++ i )
- fprintf ( stderr, "MDEBUG argv[%d] : |%s|\n", i, argv[i] );
-
- execv ( child_path, argv + 2 );
- perror ( "qrsh_run: execv error: " );
- fprintf ( stderr, "on path |%s|\n", child_path );
- exit ( 1 );
- }
- else
- {
- // This code is executed in the parent process.
-
- if ( named_child )
- {
- // Write the name-to-pid mapping.
- stringstream pid_file_name;
- pid_file_name << child_dir_name.str()
- << "/pid";
-
- FILE * fp;
- if ( ! (fp = fopen ( pid_file_name.str().c_str(), "w") ) )
- {
- fprintf ( stderr,
- "qrsh_run %d error: Can't open file |%s|\n",
- my_pid,
- pid_file_name.str().c_str()
- );
- exit(1);
- }
- fprintf ( fp, "%d\n", child_pid );
- fclose ( fp );
-
-
- // Write the pid-to-name mapping.
- stringstream name_to_pid_file_name;
- name_to_pid_file_name << root_dir
- << '/'
- << child_pid;
- if(! (fp = fopen ( name_to_pid_file_name.str().c_str(), "w")))
- {
- fprintf ( stderr,
- "qrsh_run %d error: Can't open file |%s|\n",
- my_pid,
- name_to_pid_file_name.str().c_str()
- );
- exit(1);
- }
- fprintf ( fp, "%s\n", child_name );
- fclose(fp);
- }
-
- pid_t awaited_pid;
- while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
- {
- fprintf ( stderr,
- "qrsh_run %d info: parent: waiting for child %d...\n",
- my_pid,
- child_pid
- );
- sleep(1);
- }
-
- if ( -1 == awaited_pid )
- {
- fprintf ( stderr, "qrsh_run error awaiting child!\n" );
- exit ( 1 );
- }
-
- /*
- * Write the exit code.
- */
- exit_code >>= 8;
-
- if ( named_child )
- {
- if ( child_pid == awaited_pid )
- {
- stringstream exit_code_file_name;
- exit_code_file_name << child_dir_name.str()
- << "/exit_code";
-
- FILE * fp;
- if ( ! (fp = fopen ( exit_code_file_name.str().c_str(), "w") ) )
- {
- fprintf ( stderr,
- "qrsh_run error: Can't open file |%s|\n",
- exit_code_file_name.str().c_str()
- );
- exit(1);
- }
- fprintf ( fp, "%d\n", exit_code );
- fclose ( fp );
- }
- }
- }
-
- fprintf ( stderr, "MDEBUG qrsh_run returning exit code %d\n", exit_code );
- return exit_code;
-}
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_server.cpp b/qpid/cpp/src/tests/qrsh_server.cpp
deleted file mode 100644
index 782f1e6c7c..0000000000
--- a/qpid/cpp/src/tests/qrsh_server.cpp
+++ /dev/null
@@ -1,1068 +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 <stdio.h>
-#include <set>
-#include <string>
-#include <sstream>
-#include <unistd.h>
-#include <cstdlib>
-#include <iostream>
-#include <map>
-#include <dirent.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <qpid/client/Connection.h>
-#include <qpid/client/Session.h>
-#include <qpid/client/AsyncSession.h>
-#include <qpid/client/Message.h>
-#include <qpid/client/MessageListener.h>
-#include <qpid/client/SubscriptionManager.h>
-
-
-using namespace qpid::client;
-using namespace qpid::framing;
-using namespace std;
-
-
-namespace qpid {
-namespace tests {
-
-int
-mrand ( int max_desired_val )
-{
- double zero_to_one = (double) rand() / (double) RAND_MAX;
- return (int) (zero_to_one * (double) max_desired_val);
-}
-
-
-
-char *
-file2str ( char const * file_name )
-{
- FILE * fp = fopen ( file_name, "r" );
- if(! fp)
- {
- fprintf ( stderr, "file2str error: can't open file |%s|.\n", file_name );
- return 0;
- }
-
- fseek ( fp, 0, SEEK_END );
- size_t file_len = (size_t) ftell ( fp );
- rewind ( fp );
- char * content = (char *) malloc ( file_len + 1 );
-
- if ( ! content )
- {
- fprintf ( stderr,
- "file2str error: can't malloc %d bytes.\n",
- (int)file_len
- );
- return 0;
- }
-
- size_t items_read = fread ( content, file_len, 1, fp );
-
- if ( 1 != items_read )
- {
- fprintf ( stderr, "file2str error: read failed.\n" );
- free ( content );
- return 0;
- }
-
- fclose ( fp );
- content[file_len] = 0;
-
- return content;
-}
-
-
-
-
-
-class QrshServer : public MessageListener
-{
- public:
-
- QrshServer ( SubscriptionManager & subscriptions,
- char const * name,
- char const * qrsh_run_path,
- char const * host,
- int port
- );
-
- virtual void received ( Message & message);
-
-
- private:
-
- set<string> all_server_names;
-
- stringstream data_dir;
-
- SubscriptionManager & subscriptions;
-
- // Is this message addressed to me?
- bool myMessage ( Message const & message );
-
- /* ----------------------------------------------
- * Special Commands
- * These are commands that the qrsh_server executes
- * directly, rather than through a child process
- * instance of qrsh_run.
- */
- void runCommand ( Message const & message );
- void execute ( Message const & message );
- void wait ( Message const & message );
- void exited ( Message const & message );
- void get ( Message const & message );
- void rememberIntroduction ( Message const & message );
- void getStraw ( Message const & message );
- void addAlias ( Message const & message );
-
- void start ( );
- void sayHello ( );
- void sayName ( );
- // end Special Commands ------------------------
-
-
- void saveCommand ( Message const & message );
-
- void send ( string const & content );
-
- void drawStraws ( );
- void getNames ( );
- void runSavedCommand ( );
-
- char ** getArgs ( char const * s );
- bool isProcessName ( char const * s );
- int string_countWords ( char const * s );
- char const * skipWord ( char const * s );
-
-
- void string_replaceAll ( string & str,
- string & target,
- string & replacement
- );
-
-
- string name,
- qrsh_run_path,
- host;
-
- vector<string *> aliases;
-
- int port;
-
- map < char *, int > abstract_name_map;
-
- set < string > myFellowBrokers;
-
- bool saidHello;
-
- Message savedCommand;
-
- vector < int > straws;
- int myStraw;
-
-};
-
-
-
-QrshServer::QrshServer ( SubscriptionManager & subs,
- char const * name,
- char const * qrsh_run_path,
- char const * host,
- int port
- )
- : subscriptions ( subs ),
- name ( name ),
- qrsh_run_path ( qrsh_run_path ),
- host ( host ),
- port ( port ),
- saidHello ( false ),
- myStraw ( 0 )
-{
- data_dir << "/tmp/qrsh_"
- << getpid();
-
- if(mkdir ( data_dir.str().c_str(), 0777 ) )
- {
- fprintf ( stderr,
- "QrshServer::QrshServer error: can't mkdir |%s|\n",
- data_dir.str().c_str()
- );
- exit ( 1 );
- }
-}
-
-
-
-void
-QrshServer::saveCommand ( Message const & message )
-{
- savedCommand = message;
-}
-
-
-
-void
-QrshServer::runSavedCommand ( )
-{
- runCommand ( savedCommand );
-}
-
-
-
-void
-QrshServer::start ( )
-{
- stringstream announcement_data;
- announcement_data << "hello_my_name_is "
- << name;
-
- send ( announcement_data.str() );
-
- saidHello = true;
-}
-
-
-
-
-void
-QrshServer::send ( string const & content )
-{
- try
- {
- Message message;
- message.setData ( content );
-
- Connection connection;
- connection.open ( host, port );
- Session session = connection.newSession ( );
- session.messageTransfer ( arg::content = message,
- arg::destination = "amq.fanout"
- );
- session.close();
- connection.close();
- }
- catch ( exception const & e )
- {
- fprintf ( stderr, "QrshServer::send error: |%s|\n", e.what() );
- }
-}
-
-
-
-
-void
-QrshServer::sayHello ( )
-{
- if ( saidHello )
- return;
-
- stringstream ss;
-
- ss << "hello_my_name_is "
- << name;
-
- send ( ss.str() );
- saidHello = true;
-}
-
-
-
-void
-QrshServer::sayName ( )
-{
- fprintf ( stderr, "My name is: |%s|\n", name.c_str() );
-}
-
-
-
-
-void
-QrshServer::drawStraws ( )
-{
- myStraw = mrand ( 1000000000 );
- stringstream ss;
- ss << "straw "
- << name
- << ' '
- << myStraw;
- send ( ss.str() );
-}
-
-
-
-void
-QrshServer::getStraw ( Message const & message )
-{
- int straw;
-
- char brokerName[1000];
- sscanf ( message.getData().c_str(), "%*s%s", brokerName );
-
- if ( ! strcmp ( brokerName, name.c_str() ) )
- return;
-
- sscanf ( message.getData().c_str(), "%*s%*s%d", & straw );
- straws.push_back ( straw );
-
- bool i_win = true;
- int ties = 0;
-
- if ( straws.size() >= myFellowBrokers.size() )
- {
- // All votes are in! Let's see if I win!
- for ( unsigned int i = 0; i < straws.size(); ++ i )
- {
- if ( straws[i] == myStraw )
- ++ ties;
- else
- if ( straws[i] > myStraw )
- {
- i_win = false;
- break;
- }
- }
-
- if ( i_win && (ties <= 0) )
- {
- myStraw = 0;
- straws.clear();
- runSavedCommand ( );
- }
- else
- if ( i_win && (ties > 0) )
- {
- fprintf ( stderr, "MDEBUG oh no! drawStraws error: server %s tied with straw %d!\n", name.c_str(), straw );
- }
- }
-}
-
-
-
-
-/*
- * "APB" command (all-points-bullitens (commands that are not addressed
- * specifically to any server)) are handled directly, here.
- * Because if I return simply "true", the normal command processing code
- * will misinterpret the command.
- */
-bool
-QrshServer::myMessage ( Message const & message )
-{
- int const maxlen = 100;
- char head[maxlen];
- char first_word [ maxlen + 1 ];
- strncpy ( head, message.getData().c_str(), maxlen );
- sscanf ( head, "%s", first_word );
-
- if ( ! strcmp ( name.c_str(), first_word ) )
- {
- return true;
- }
- else
- {
- // Is the given name one of my aliases?
- char possibleAlias[1000];
- if(1 == sscanf ( message.getData().c_str(), "%s", possibleAlias ))
- {
- for ( unsigned int i = 0; i < aliases.size(); ++ i )
- {
-
- if ( ! strcmp ( possibleAlias, aliases[i]->c_str() ))
- {
- return true;
- }
- }
- }
- }
-
- if ( ! strcmp ( first_word, "hello_my_name_is" ) )
- {
- rememberIntroduction ( message );
- sayHello ( );
- return false;
- }
- else
- if ( ! strcmp ( first_word, "straw" ) )
- {
- getStraw ( message );
- return false;
- }
- else
- if ( ! strcmp ( first_word, "all" ) )
- {
- return true;
- }
- else
- if ( ! strcmp ( first_word, "any" ) )
- {
- straws.clear();
- usleep ( 200000 );
- saveCommand ( message );
- drawStraws ( );
- return false;
- }
- else
- return false;
-}
-
-
-
-
-void
-QrshServer::rememberIntroduction ( Message const & message )
-{
- char brokerName [ 1000 ];
- sscanf ( message.getData().c_str(), "%*s%s", brokerName );
-
- if ( strcmp ( brokerName, name.c_str() ) )
- myFellowBrokers.insert ( string ( brokerName ) );
-}
-
-
-
-
-void
-QrshServer::addAlias ( Message const & message )
-{
- char alias[1000];
- sscanf ( message.getData().c_str(), "%*s%*s%s", alias );
- aliases.push_back ( new string(alias) );
-}
-
-
-
-
-void
-QrshServer::getNames ( )
-{
- abstract_name_map.clear();
-
- DIR * dir = opendir ( data_dir.str().c_str() );
-
- if ( ! dir )
- {
- fprintf ( stderr,
- "QrshServer::getNames error: could not open dir |%s|.\n",
- data_dir.str().c_str()
- );
- return;
- }
-
- struct dirent * file;
- while ( (file = readdir ( dir ) ) )
- {
- if ( '.' != file->d_name[0] )
- {
- stringstream pid_file_name;
- pid_file_name << data_dir.str()
- << '/'
- << file->d_name
- << "/pid";
-
- int pid = 0;
- FILE * fp;
- if ( (fp = fopen ( pid_file_name.str().c_str(), "r" ) ) )
- {
- fscanf ( fp, "%d", & pid );
- fclose ( fp );
- abstract_name_map.insert(pair<char*, int>(strdup(file->d_name), pid));
- }
- else
- {
- /*
- * Fail silently. The non-existence of this file
- * is not necessarily an error.
- */
- }
- }
- }
- closedir ( dir );
-}
-
-
-
-void
-QrshServer::string_replaceAll ( string & str,
- string & target,
- string & replacement
- )
-{
- int target_size = target.size();
- int found_pos = 0;
-
- while ( 0 <= (found_pos = str.find ( target ) ) )
- str.replace ( found_pos, target_size, replacement );
-}
-
-
-
-
-bool
-QrshServer::isProcessName ( char const * str )
-{
- getNames();
- map<char *, int>::iterator it;
- for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
- {
- if ( ! strcmp ( str, it->first ) )
- return true;
- }
-
- return false;
-}
-
-
-
-
-
-int
-QrshServer::string_countWords ( char const * s1 )
-{
- int count = 0;
- char const * s2 = s1 + 1;
-
- if ( ! isspace(* s1) )
- {
- ++ count;
- }
-
- for ( ; * s2; ++ s1, ++ s2 )
- {
- // count space-to-word transitions.
- if ( isspace(*s1) && (! isspace(*s2)) )
- ++ count;
- }
-
- return count;
-}
-
-
-
-
-void
-QrshServer::execute ( Message const & message )
-{
- // First, gather all the symbolic names we know.
- getNames();
-
- // Now make a copy of the command, that I can alter.
- string command ( message.getData() );
-
-
- // Replace each occurrence of every abstract name with its pid.
- char pid_str[100];
- map<char *, int>::iterator it;
- for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
- {
- sprintf ( pid_str, "%d", it->second );
- string target ( it->first ),
- replacement ( pid_str );
- string_replaceAll ( command, target, replacement );
- }
-
-
- char const * truncated_command = skipWord(skipWord(command.c_str()));
-
- if ( truncated_command )
- system ( truncated_command );
-}
-
-
-
-
-
-void
-QrshServer::get ( Message const & request_message )
-{
- char * file_content;
-
- /*
- * Get the contents of the requested file.
- */
- char file_or_process_name[1000];
- sscanf ( request_message.getData().c_str(), "%*s%*s%s", file_or_process_name );
-
- if ( isProcessName ( file_or_process_name ) )
- {
- stringstream desired_file_name;
- desired_file_name << data_dir.str()
- << '/'
- << file_or_process_name
- << '/';
- char requested_output_stream[1000];
- if(1 != sscanf ( request_message.getData().c_str(),
- "%*s%*s%*s%s",
- requested_output_stream
- )
- )
- {
- fprintf ( stderr,
- "QrshServer::get error: Can't read requested data file name from this message: |%s|\n",
- request_message.getData().c_str()
- );
- return;
- }
- desired_file_name << requested_output_stream;
- file_content = file2str ( desired_file_name.str().c_str() );
- }
- else
- {
- file_content = file2str ( file_or_process_name );
- }
-
- stringstream reply_data ;
- reply_data << "get_response "
- << file_content;
- /*
- * Send a response-message to the server who is waiting.
- */
- send ( reply_data.str() );
-}
-
-
-
-
-
-
-void
-QrshServer::exited ( Message const & message )
-{
- int exit_code = -1;
-
- // First, gather all the symbolic names we know.
- getNames();
-
- // Now make a copy of the command, that I can alter.
- string edited_command ( message.getData() );
-
- // Replace each occurrence of every abstract name with its pid.
- char pid_str[100];
- map<char *, int>::iterator it;
- for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
- {
- sprintf ( pid_str, "%d", it->second );
- string target ( it->first ),
- replacement ( pid_str );
- string_replaceAll ( edited_command, target, replacement );
- }
-
- // Skip the service name. That is not used by the child.
- char const * truncated_command = skipWord(edited_command.c_str());
-
- if ( truncated_command )
- {
- stringstream ss;
- ss << qrsh_run_path
- << ' '
- << data_dir.str()
- << ' '
- << truncated_command;
-
- int child_pid;
- if ( ! (child_pid = fork() ) )
- {
- // This is the child.
-
- char ** argv = getArgs ( ss.str().c_str() );
- execv ( qrsh_run_path.c_str(), argv );
-
- perror ( "qrsh_server: execv error: " );
- exit ( 1 );
- }
- else
- {
- // This is the parent.
- pid_t awaited_pid;
- while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
- {
- fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" );
- sleep(1);
- }
-
- if ( -1 == awaited_pid )
- {
- fprintf ( stderr, "qrsh_server error awaiting child!\n" );
- exit ( 1 );
- }
-
- exit_code >>= 8;
-
- stringstream data;
- data << "wait_response "
- << exit_code;
-
- send ( data.str() );
- }
- }
-}
-
-
-
-
-void
-QrshServer::wait ( Message const & message )
-{
- bool pre_existing = false;
- if ( 3 == string_countWords ( message.getData().c_str() ) )
- {
- // The first word is the name of this service.
- // The second word is "exec_wait".
- // The third word is the symbolic name of the command to wait for.
- // The fact that there are exactly three words means that this
- // must be a command that has already been named and started --
- // we just need to find its pid and wait on it.
- pre_existing = true;
- }
-
-
- int exit_code = -1;
-
- // First, gather all the symbolic names we know.
- getNames();
-
- // Now make a copy of the command, that I can alter.
- string edited_command ( message.getData() );
-
- // Replace each occurrence of every abstract name with its pid.
- char pid_str[100];
- map<char *, int>::iterator it;
- for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
- {
- sprintf ( pid_str, "%d", it->second );
- string target ( it->first ),
- replacement ( pid_str );
- string_replaceAll ( edited_command, target, replacement );
- }
-
- // Skip the service name. That is not used by the child.
- char const * truncated_command = skipWord(edited_command.c_str());
-
- if ( truncated_command )
- {
- stringstream ss;
- ss << qrsh_run_path
- << ' '
- << data_dir.str()
- << ' '
- << truncated_command;
-
- int child_pid;
- if ( ! (child_pid = fork() ) )
- {
- // This is the child.
-
- char ** argv = getArgs ( ss.str().c_str() );
- execv ( qrsh_run_path.c_str(), argv );
-
- perror ( "qrsh_server: execv error: " );
- exit ( 1 );
- }
- else
- {
- // This is the parent.
- pid_t awaited_pid;
- while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
- {
- fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" );
- sleep(1);
- }
-
- if ( -1 == awaited_pid )
- {
- fprintf ( stderr, "qrsh_server error awaiting child!\n" );
- exit ( 1 );
- }
- }
-
- exit_code >>= 8;
-
- stringstream data;
- data << "wait_response "
- << exit_code;
-
- send ( data.str() );
- }
-}
-
-
-
-
-
-char const *
-QrshServer::skipWord ( char const * s )
-{
- if(! (s && *s) )
- return 0;
-
- // skip past initial white space
- while ( isspace(*s) )
- {
- ++ s;
- if(! *s)
- return 0;
- }
-
- // skip past first word
- while ( ! isspace(*s) )
- {
- ++ s;
- if(! *s)
- return 0;
- }
-
- return s;
-}
-
-
-
-
-
-char **
-QrshServer::getArgs ( char const * str )
-{
- char const * s = str;
-
- char ** argv = 0;
- vector<int> start_positions,
- lengths;
-
- int pos = 0;
- int arg_len = 0;
-
- int n_args = 0;
- while ( 1 )
- {
- // advance over whitespace.
- while ( isspace ( *s ) )
- {
- ++ s; ++ pos;
- if(! *s)
- {
- goto done;
- }
- }
-
- ++ n_args;
- start_positions.push_back ( pos );
- arg_len = 0;
-
- // advance over non-whitespace.
- while ( ! isspace ( *s ) )
- {
- ++ s; ++ pos; ++ arg_len;
- if(! *s)
- {
- lengths.push_back ( arg_len );
- arg_len = 0;
- goto done;
- }
- }
-
- lengths.push_back ( arg_len );
- arg_len = 0;
- }
-
- done:
-
- if ( arg_len > 0 )
- lengths.push_back ( arg_len );
-
- // Alloc the array.
- argv = (char **) malloc ( sizeof(char *) * ( n_args + 1 ) );
- argv[n_args] = 0; // mull-term the array.
-
- for ( int i = 0; i < n_args; ++ i )
- {
- argv[i] = ( char *) malloc ( lengths[i] + 1 );
- strncpy ( argv[i],
- str + start_positions[i],
- lengths[i]
- );
- argv[i][lengths[i]] = 0;
- }
-
- return argv;
-}
-
-
-
-void
-QrshServer::runCommand ( Message const & message )
-{
- char const * s = message.getData().c_str();
-
- /*
- * Skip the first word, which is this server's name.
- */
- while ( isspace(*s) ) // go to start of first word.
- ++ s;
-
- while ( ! isspace(*s) ) // go to end of first word.
- ++ s;
-
- while ( isspace(*s) ) // go to start of second word.
- ++ s;
-
- char command_name[1000];
- sscanf ( s, "%s", command_name );
-
- if ( ! strcmp ( "get", command_name ) )
- {
- get ( message );
- }
- else
- if ( ! strcmp ( "exited", command_name ) )
- {
- exited ( message );
- }
- else
- if ( ! strcmp ( "exec_wait", command_name ) )
- {
- wait ( message );
- }
- else
- if ( ! strcmp ( "exec", command_name ) )
- {
- execute ( message );
- }
- else
- if ( ! strcmp ( "start", command_name ) )
- {
- start ( );
- }
- else
- if ( ! strcmp ( "alias", command_name ) )
- {
- addAlias ( message );
- }
- else
- if ( ! strcmp ( "sayName", command_name ) )
- {
- sayName ( );
- }
- else
- {
- /*
- * If the command is not any of the "special" commands
- * above, then it's a "normal" command.
- * That means we run it with a child process instance of
- * qrsh_run, which will save all its data in the qrsh dir.
- */
- stringstream ss;
- ss << qrsh_run_path
- << ' '
- << data_dir.str()
- << ' '
- << s;
-
- if ( ! fork() )
- {
- char ** argv = getArgs ( ss.str().c_str() );
- execv ( qrsh_run_path.c_str(), argv );
- perror ( "qrsh_server: execv error: " );
- }
- }
-}
-
-
-
-void
-QrshServer::received ( Message & message )
-{
- if ( myMessage ( message ) )
- runCommand ( message );
-}
-
-
-
-}} // namespace qpid::tests
-
-using namespace qpid::tests;
-
-/*
- * fixme mick Mon Aug 3 10:29:26 EDT 2009
- * argv[1] server name
- * argv[2] qrsh exe path
- * argv[3] host
- * argv[4] port
- */
-int
-main ( int /*argc*/, char** argv )
-{
- const char* host = argv[3];
- int port = atoi(argv[4]);
- Connection connection;
- Message msg;
-
- srand ( getpid() );
-
- try
- {
- connection.open ( host, port );
- Session session = connection.newSession();
-
-
- // Declare queues.
- string myQueue = session.getId().getName();
- session.queueDeclare ( arg::queue=myQueue,
- arg::exclusive=true,
- arg::autoDelete=true);
-
- session.exchangeBind ( arg::exchange="amq.fanout",
- arg::queue=myQueue,
- arg::bindingKey="my-key");
-
- // Create a server and subscribe it to my queue.
- SubscriptionManager subscriptions ( session );
- QrshServer server ( subscriptions,
- argv[1], // server name
- argv[2], // qrsh exe path
- host,
- port
- );
- subscriptions.subscribe ( server, myQueue );
-
- // Receive messages until the subscription is cancelled
- // by QrshServer::received()
- subscriptions.run();
-
- connection.close();
- }
- catch(const exception& error)
- {
- cout << error.what() << endl;
- return 1;
- }
-
- return 0;
-}
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/2_forever b/qpid/cpp/src/tests/qrsh_utils/2_forever
deleted file mode 100755
index 5528b0e4d8..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/2_forever
+++ /dev/null
@@ -1,26 +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.
- *
- */
-
-#! /bin/bash
-
-
-./qrsh 127.0.0.1 5813 \
- mrg23 command_2 /home/mick/redhat/qrsh/qrsh_run/forever foo bar baz
diff --git a/qpid/cpp/src/tests/qrsh_utils/4_wait_for_it b/qpid/cpp/src/tests/qrsh_utils/4_wait_for_it
deleted file mode 100755
index a4dc0da1ce..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/4_wait_for_it
+++ /dev/null
@@ -1,26 +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.
- *
- */
-
-#! /bin/bash
-
-./qrsh 127.0.0.1 5813 \
- mrg23 exec_wait /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
-echo "my_command returned an exit code of $?"
diff --git a/qpid/cpp/src/tests/qrsh_utils/5_exited b/qpid/cpp/src/tests/qrsh_utils/5_exited
deleted file mode 100755
index 4fec1dcc79..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/5_exited
+++ /dev/null
@@ -1,64 +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.
- *
- */
-
-#! /bin/bash
-
-path=/home/mick/redhat/qrsh/qrsh_run
-
-echo "Running command_3 ..."
-./qrsh 127.0.0.1 5813 \
- mrg23 command_3 $path/my_command foo bar baz
-
-echo "Now I do some other stuff..."
-sleep 1
-echo "And then some more stuff..."
-sleep 1
-echo "and so on..."
-sleep 1
-
-echo "Now I'm waiting for command_3 ..."
-./qrsh 127.0.0.1 5813 \
- mrg23 exited command_3
-echo "has command_3 exited: $? ."
-sleep 5
-
-./qrsh 127.0.0.1 5813 \
- mrg23 exited command_3
-echo "has command_3 exited: $? ."
-sleep 5
-
-./qrsh 127.0.0.1 5813 \
- mrg23 exited command_3
-echo "has command_3 exited: $? ."
-sleep 5
-
-./qrsh 127.0.0.1 5813 \
- mrg23 exited command_3
-echo "has command_3 exited: $? ."
-sleep 5
-
-./qrsh 127.0.0.1 5813 \
- mrg23 exited command_3
-echo "has command_3 exited: $? ."
-sleep 5
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/6_get b/qpid/cpp/src/tests/qrsh_utils/6_get
deleted file mode 100755
index 4b35ca98e6..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/6_get
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#! /bin/bash
-
-echo "getting /tmp/foo ..."
-./qrsh 127.0.0.1 5813 \
- mrg23 get /tmp/foo
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/7_get_output b/qpid/cpp/src/tests/qrsh_utils/7_get_output
deleted file mode 100755
index 59911089ec..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/7_get_output
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#! /bin/bash
-
-echo "Run a command..."
-./qrsh 127.0.0.1 5813 \
- mrg23 command_4 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
-
-echo "Wait for a while..."
-sleep 20
-
-echo "Get stderr output:"
-echo "------------- begin stderr ---------------"
-./qrsh 127.0.0.1 5813 \
- mrg23 get command_4 stderr
-echo "------------- end stderr ---------------"
-echo " "
-echo " "
-echo " "
-echo "Get stdout output:"
-echo "------------- begin stdout ---------------"
-./qrsh 127.0.0.1 5813 \
- mrg23 get command_4 stdout
-echo "------------- end stdout ---------------"
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/8_any b/qpid/cpp/src/tests/qrsh_utils/8_any
deleted file mode 100755
index 2a922ea0e0..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/8_any
+++ /dev/null
@@ -1,43 +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.
- *
- */
-
-#! /bin/bash
-
-echo "asking any server to say his name ..."
-./qrsh 127.0.0.1 5813 \
- any sayName
-sleep 1
-echo "asking any server to say his name ..."
-./qrsh 127.0.0.1 5813 \
- any sayName
-sleep 1
-echo "asking any server to say his name ..."
-./qrsh 127.0.0.1 5813 \
- any sayName
-sleep 1
-echo "asking any server to say his name ..."
-./qrsh 127.0.0.1 5813 \
- any sayName
-sleep 1
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/9_alias b/qpid/cpp/src/tests/qrsh_utils/9_alias
deleted file mode 100755
index a4cfdfdf9a..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/9_alias
+++ /dev/null
@@ -1,38 +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.
- *
- */
-
-#! /bin/bash
-
-# Make a group of two of the servers, using "alias",
-# and send the group a command.
-
-qrsh 127.0.0.1 5813 \
- mrg22 alias group_1
-qrsh 127.0.0.1 5813 \
- mrg23 alias group_1
-
-echo "Asking group_1 to say their names... "
-qrsh 127.0.0.1 5813 \
- group_1 sayName
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp b/qpid/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp
deleted file mode 100644
index 386e2f73f0..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-
-
-
-main ( int argc, char ** argv )
-{
- fprintf ( stderr, "Hello, I am the Example Child!\n");
- fprintf ( stderr, "my arguments %d are:\n", argc - 1 );
- fprintf ( stdout, "And hello to stdout, too!\n");
-
- int i;
- for ( i = 1; i < argc; ++ i )
- {
- fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] );
- }
-
- for ( i = 0; i < 15; ++ i )
- {
- fprintf ( stderr, "child sleeping...\n" );
- sleep ( 1 );
- }
-
- fprintf ( stderr, "child exiting with code 13.\n" );
-
- return 13;
-}
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/qrsh_forever.cpp b/qpid/cpp/src/tests/qrsh_utils/qrsh_forever.cpp
deleted file mode 100644
index 191a9bca11..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/qrsh_forever.cpp
+++ /dev/null
@@ -1,50 +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 <stdio.h>
-#include <unistd.h>
-
-
-
-main ( int argc, char ** argv )
-{
- fprintf ( stderr, "Hello, I am the Forever Example Child!\n");
- fprintf ( stderr, "my %d arguments are:\n", argc - 1 );
-
- int i;
- for ( i = 1; i < argc; ++ i )
- fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] );
-
- for ( i = 0; i >= 0; ++ i )
- {
- fprintf ( stderr, "child sleeping forever %d ...\n" , i);
- sleep ( 1 );
- }
-
- fprintf ( stderr, "child exiting with code 12.\n" );
-
- return 12;
-}
-
-
-
-
diff --git a/qpid/cpp/src/tests/qrsh_utils/qsh_doc.txt b/qpid/cpp/src/tests/qrsh_utils/qsh_doc.txt
deleted file mode 100644
index ad5990b38b..0000000000
--- a/qpid/cpp/src/tests/qrsh_utils/qsh_doc.txt
+++ /dev/null
@@ -1,309 +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.
- *
- */
-
-##############################################
- qrsh: a Qpid-based remote shell utility
-
- Last updated: 3 Aug 09 Mick Goulish
-##############################################
-
-
-
-=============================
-Overview
-=============================
-
- You're writing a multi-box test, and you want to write a
- shell script in which you start processes on other boxes
- and kill them (or send arbitrary signals to them).
-
- But ssh doesn't let you signal them, and bash isn't the
- greatest language in the world for creating data structures
- (like you need to associate the PIDs with box names and
- executable names.)
-
- Qsh is a utility implemented on Qpid that you can use from
- within your bash script, or any other scripting language.
- With it, you can:
-
- 1. run any executable on any box in your cluster.
-
- 2. don't worry about PIDs and box-names. You associate
- your own abstract names with the executable instances,
- and then use those names in the rest of your script.
- I.e. "broker_1" "sender_3" etc.
-
- 3. Launch the executable and wait until it returns, and
- get its exit code.
-
- 4. Launch your executable and do other stuff, then come
- back later and see if it has exited.
-
- 5. Get whatever it sent to stdout or stderr.
-
- 6. Get the contents of any other file.
-
- 7. send a command to all your boxes at once
-
- 8. send a command to a randomly selected box.
-
- 9. define groups of boxes, and send a command simultaneously
- to all boxes in a given group.
-
-
-
-
-=============================
-Using It
-=============================
-
- 1. You need to run a Qpid broker.
-
- 2. You start a Qpid client ( which is called a qrsh_server )
- on all the boxes you care about. And you give them all
- names like "mrg13", "mrg14" etc. The names can be anything
- you want, but I've always used one qrsh_server per box,
- and given it the box name. ( However, you can run two on
- one box, they won't collide. )
-
- 3. After you start all servers, send a "start" command to any
- one of them:
-
- 4. The qrsh_servers use the fanout exchange to talk to each
- other.
-
- 5. In your script, you run an executable called "qrsh". It knows
- how to talk to the servers, do what you want, and retrieve
- the data you want.
-
-
- example start script: (this does 4 servers on the same box)
- -------------------------------------------------------------
-
- echo "Starting server mrg22 ..."
- ./qrsh_server mrg22 ./qrsh_run 127.0.0.1 5813 &
-
- echo "Starting server mrg23 ..."
- ./qrsh_server mrg23 ./qrsh_run 127.0.0.1 5813 &
-
- echo "Starting server mrg24 ..."
- ./qrsh_server mrg24 ./qrsh_run 127.0.0.1 5813 &
-
- echo "Starting server mrg25 ..."
- ./qrsh_server mrg25 ./qrsh_run 127.0.0.1 5813 &
-
- echo "Issuing start command..."
- sleep 2
- ./qrsh 127.0.0.1 5813 mrg22 start
- sleep 1
-
- echo "Ready."
-
- # end of script.
-
-
-
-
-
-
-=============================
-Qrsh Syntax
-=============================
-
- qrsh host port server_name command_name arg*
-
-
- "host" and "port" specify the Qpid server to connect to.
-
- "server_name" can be anything you want. I always use the name
- of the box that the server is running on.
-
- "command_name" is the name that you choose to assign to
- the process you are running. Each process that you decide
- to name must have a unique name within this script.
-
- Or it could be a reserved command name, that Qsh
- interprets in a special way.
-
- Reserved command names are:
-
- exec
- exec_wait
- exited
- get
-
- "exec" means "interpret the rest of the command line as a
- command to be executed by the designated server.
-
- "exec_wait" means same as "exec", but wait for the command
- to terminate, and return its exit code.
-
- "exited" -- you provide 1 arg, which is an abstract
- process name. qrsh returns 1 if that process has exited,
- else 0.
-
- "get" -- you provide one arg which is a path. qrsh returns
- (by printing to stdout) the contents of that file.
-
- "arg*" is zero or more arguments. They are interpreted
- differently depending on whether you are using one of
- the above reserved command names, or making up your own
- abstract name for a command.
-
-
-
-
-=============================
-Examples
-=============================
-
- 1. Run a process on a remote box.
-
- qrsh mrg23 command_1 /usr/sbin/whatever foo bar baz
-
- Returns immediately.
-
-
-
- 2. Kill a process that you started earlier:
-
- qrsh mrg23 exec kill -9 command_1
-
- After the word "exec" put any command line you want.
- The server you're sending this to will replace all abstract
- names in the command with process IDs. ( In this example,
- just the word "command_1" will be replaced. ) Then it will
- execute the command.
-
-
-
- 3. Execute a command, and wait for it to finish
-
- qrsh mrg23 exec_wait command_name args
-
-
-
- 4. Check on whether a command you issude earlier has exited.
-
- ./qrsh mrg23 exited command_3
-
- Returns 1 if it has exited, else 0.
-
-
-
- 5. Get the contents of a file from the remote system:
-
- ./qrsh mrg23 get /tmp/foo
-
- Prints the contents to stdout.
-
-
-
- 6. Send a command to all servers at once:
-
- # This example causes them all to print thir names to stderr.
- ./qrsh all sayName
-
-
- 7. Define a group of servers and send a command to that group.
-
- #! /bin/bash
-
- # Make a group of two of the servers, using "alias",
- # and send the group a command.
-
- qrsh 127.0.0.1 5813 \
- mrg22 alias group_1
-
- qrsh 127.0.0.1 5813 \
- mrg23 alias group_1
-
- echo "Asking group_1 to say their names... "
- qrsh 127.0.0.1 5813 \
- group_1 sayName
-
- # end of script.
-
-
-
-
- 8. Execute a command and get its stdout and stderr contents.
-
- #! /bin/bash
-
- echo "Run a command..."
- ./qrsh 127.0.0.1 5813 \
- mrg23 command_4 my_command foo bar baz
-
- echo "Wait for a while..."
- sleep 10
-
- echo "Get stderr output:"
- echo "------------- begin stderr ---------------"
- ./qrsh 127.0.0.1 5813 \
- mrg23 get command_4 stderr
- echo "------------- end stderr ---------------"
- echo " "
-
- echo " "
- echo "Get stdout output:"
- echo "------------- begin stdout ---------------"
- ./qrsh 127.0.0.1 5813 \
- mrg23 get command_4 stdout
- echo "------------- end stdout ---------------"
-
- # end of script.
-
-
-
-
- 9. Send a command to one of your servers, selected
- at random.
-
- #! /bin/bash
-
- # I do it multiple times here, so I can see
- # that it really is selecting randomly.
-
- echo "asking any server to say his name ..."
- ./qrsh 127.0.0.1 5813 \
- any sayName
- sleep 1
-
- echo "asking any server to say his name ..."
- ./qrsh 127.0.0.1 5813 \
- any sayName
- sleep 1
-
- echo "asking any server to say his name ..."
- ./qrsh 127.0.0.1 5813 \
- any sayName
- sleep 1
-
- echo "asking any server to say his name ..."
- ./qrsh 127.0.0.1 5813 \
- any sayName
-
- # end of script.
-
-
-
-
diff --git a/qpid/cpp/src/tests/queue_flow_limit_tests.py b/qpid/cpp/src/tests/queue_flow_limit_tests.py
index ac62dcdd1e..bdd2a21b78 100644
--- a/qpid/cpp/src/tests/queue_flow_limit_tests.py
+++ b/qpid/cpp/src/tests/queue_flow_limit_tests.py
@@ -137,12 +137,12 @@ class QueueFlowLimitTests(TestBase010):
"""
self.startQmf();
oid = self._create_queue("test-q", stop_count=373, resume_count=229)
+ self.assertEqual(self.qmf.getObjects(_objectId=oid)[0].flowStoppedCount, 0)
sndr1 = self._start_qpid_send("test-q", count=1213, content="XXX", capacity=50);
sndr2 = self._start_qpid_send("test-q", count=797, content="Y", capacity=13);
sndr3 = self._start_qpid_send("test-q", count=331, content="ZZZZZ", capacity=149);
totalMsgs = 1213 + 797 + 331
-
# wait until flow control is active
count = 0
@@ -180,6 +180,7 @@ class QueueFlowLimitTests(TestBase010):
self.assertEqual(count, totalMsgs)
self.failIf(self.qmf.getObjects(_objectId=oid)[0].flowStopped)
+ self.failUnless(self.qmf.getObjects(_objectId=oid)[0].flowStoppedCount)
self._delete_queue("test-q")
diff --git a/qpid/cpp/src/tests/replication_test b/qpid/cpp/src/tests/replication_test
index 691fd20b0c..8c37568875 100755
--- a/qpid/cpp/src/tests/replication_test
+++ b/qpid/cpp/src/tests/replication_test
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/src/tests/run_acl_tests b/qpid/cpp/src/tests/run_acl_tests
index aff13408ed..41f41e20e1 100755
--- a/qpid/cpp/src/tests/run_acl_tests
+++ b/qpid/cpp/src/tests/run_acl_tests
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/src/tests/run_cli_tests b/qpid/cpp/src/tests/run_cli_tests
index 3f1388b9f5..ec5c71b646 100755
--- a/qpid/cpp/src/tests/run_cli_tests
+++ b/qpid/cpp/src/tests/run_cli_tests
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
@@ -70,7 +70,8 @@ stop_brokers() {
if test -d ${PYTHON_DIR} ; then
start_brokers
echo "Running CLI tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
- $QPID_PYTHON_TEST -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $targs $@
+ PYTHON_TESTS=${PYTHON_TESTS:-$*}
+ $QPID_PYTHON_TEST -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $targs $PYTHON_TESTS $@
RETCODE=$?
stop_brokers
if test x$RETCODE != x0; then
diff --git a/qpid/cpp/src/tests/run_federation_tests b/qpid/cpp/src/tests/run_federation_tests
index 4be27a2e85..590f74746e 100755
--- a/qpid/cpp/src/tests/run_federation_tests
+++ b/qpid/cpp/src/tests/run_federation_tests
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/src/tests/run_header_test b/qpid/cpp/src/tests/run_header_test
index 07658343e7..34008132cc 100755
--- a/qpid/cpp/src/tests/run_header_test
+++ b/qpid/cpp/src/tests/run_header_test
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/src/tests/run_test b/qpid/cpp/src/tests/run_test
index 4b227621bc..6ec1fd892b 100755
--- a/qpid/cpp/src/tests/run_test
+++ b/qpid/cpp/src/tests/run_test
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
diff --git a/qpid/cpp/src/tests/sasl.mk b/qpid/cpp/src/tests/sasl.mk
index 5b8419f604..20eaa7c7a5 100644
--- a/qpid/cpp/src/tests/sasl.mk
+++ b/qpid/cpp/src/tests/sasl.mk
@@ -30,9 +30,20 @@ check_PROGRAMS+=sasl_version
sasl_version_SOURCES=sasl_version.cpp
sasl_version_LDADD=$(lib_client)
-TESTS += run_cluster_authentication_test sasl_fed sasl_fed_ex
+TESTS += run_cluster_authentication_test sasl_fed sasl_fed_ex_dynamic sasl_fed_ex_link sasl_fed_ex_queue sasl_fed_ex_route sasl_fed_ex_route_cluster sasl_fed_ex_link_cluster sasl_fed_ex_queue_cluster sasl_fed_ex_dynamic_cluster
LONG_TESTS += run_cluster_authentication_soak
-EXTRA_DIST += run_cluster_authentication_test sasl_fed sasl_fed_ex run_cluster_authentication_soak
+EXTRA_DIST += run_cluster_authentication_test \
+ sasl_fed \
+ sasl_fed_ex \
+ run_cluster_authentication_soak \
+ sasl_fed_ex_dynamic \
+ sasl_fed_ex_link \
+ sasl_fed_ex_queue \
+ sasl_fed_ex_route \
+ sasl_fed_ex_dynamic_cluster \
+ sasl_fed_ex_link_cluster \
+ sasl_fed_ex_queue_cluster \
+ sasl_fed_ex_route_cluster
endif # HAVE_SASL
diff --git a/qpid/cpp/src/tests/sasl_fed_ex b/qpid/cpp/src/tests/sasl_fed_ex
index 0740650d6c..71dece56a9 100755
--- a/qpid/cpp/src/tests/sasl_fed_ex
+++ b/qpid/cpp/src/tests/sasl_fed_ex
@@ -21,20 +21,49 @@
#===============================================================================
-# This test creates a federated link between two brokers using SASL security.
+# These tests create federated links between two brokers using SASL security.
# The SASL mechanism used is EXTERNAL, which is satisfied by SSL
# transport-layer security.
#===============================================================================
source ./test_env.sh
+script_name=`basename $0`
+
+if [ $# -lt 1 ] || [ $# -gt 2 ]
+then
+ echo
+ # These are the four different ways of creating links ( or routes+links )
+ # that the qpid-route command provides.
+ echo "Usage: ${script_name} dynamic|link|queue|route [cluster]"
+ echo
+ exit 1
+fi
+
+# Has the user told us to do clustering ? -----------
+clustering_flag=
+if [ $# -eq "2" ] && [ "$2" == "cluster" ]; then
+ clustering_flag=true
+fi
+
+qpid_route_method=$1
+
+# Debugging print. --------------------------
+debug=
+function print {
+ if [ "$debug" ]; then
+ echo "${script_name}: $1"
+ fi
+}
+
+
# This minimum value corresponds to sasl version 2.1.22
minimum_sasl_version=131350
sasl_version=`$QPID_TEST_EXEC_DIR/sasl_version`
-# This test is necessary becasue this sasl version is the first one that permits
+# This test is necessary because this sasl version is the first one that permits
# redirection of the sasl config file path.
if [ "$sasl_version" -lt "$minimum_sasl_version" ]; then
echo "sasl_fed: must have sasl version 2.1.22 or greater. ( Integer value: $minimum_sasl_version ) Version is: $sasl_version"
@@ -60,6 +89,7 @@ create_certs() {
delete_certs() {
if [[ -e ${CERT_DIR} ]] ; then
+ print "removing cert dir ${CERT_DIR}"
rm -rf ${CERT_DIR}
fi
}
@@ -75,19 +105,31 @@ delete_certs
create_certs || error "Could not create test certificate"
-sasl_config_file=$builddir/sasl_config
+sasl_config_dir=$builddir/sasl_config
-my_random_number=$RANDOM
-tmp_root=/tmp/sasl_fed_$my_random_number
+tmp_root=${builddir}/sasl_fed_ex_temp
+print "results dir is ${tmp_root}"
+rm -rf ${tmp_root}
mkdir -p $tmp_root
SRC_SSL_PORT=6667
DST_SSL_PORT=6666
+SRC_SSL_PORT_2=6668
+DST_SSL_PORT_2=6669
+
SRC_TCP_PORT=5801
DST_TCP_PORT=5807
-SSL_LIB=../.libs/ssl.so
+SRC_TCP_PORT_2=5802
+DST_TCP_PORT_2=5803
+
+CLUSTER_1_NAME=sasl_fed_ex_cluster_1
+CLUSTER_2_NAME=sasl_fed_ex_cluster_2
+
+
+SSL_LIB=${moduledir}/ssl.so
+CLUSTER_LIB=${moduledir}/cluster.so
export QPID_SSL_CERT_NAME=${TEST_HOSTNAME}
@@ -116,52 +158,109 @@ export QPID_SSL_CERT_NAME=${TEST_HOSTNAME}
# 5. DST pulls messages off the temp queue on SRC to itself.
#
+COMMON_BROKER_OPTIONS=" \
+ --ssl-sasl-no-dict \
+ --sasl-config=$sasl_config_dir \
+ --ssl-require-client-authentication \
+ --auth yes \
+ --ssl-cert-db $CERT_DIR \
+ --ssl-cert-password-file $CERT_PW_FILE \
+ --ssl-cert-name $TEST_HOSTNAME \
+ --no-data-dir \
+ --no-module-dir \
+ --load-module ${SSL_LIB} \
+ --load-module ${CLUSTER_LIB} \
+ --mgmt-enable=yes \
+ --log-enable info+ \
+ --log-source yes \
+ --daemon "
+
+
+function start_brokers {
+ if [ $1 ]; then
+ # clustered ----------------------------------------
+ print "Starting SRC cluster"
+
+ print " src broker 1"
+ $QPIDD_EXEC \
+ --port=${SRC_TCP_PORT} \
+ --ssl-port ${SRC_SSL_PORT} \
+ ${COMMON_BROKER_OPTIONS} \
+ --cluster-name ${CLUSTER_1_NAME} \
+ --log-to-file $tmp_root/qpidd_src.log 2> /dev/null
+
+ broker_ports[0]=${SRC_TCP_PORT}
+
+ print " src broker 2"
+ $QPIDD_EXEC \
+ --port=${SRC_TCP_PORT_2} \
+ --ssl-port ${SRC_SSL_PORT_2} \
+ ${COMMON_BROKER_OPTIONS} \
+ --cluster-name ${CLUSTER_1_NAME} \
+ --log-to-file $tmp_root/qpidd_src_2.log 2> /dev/null
+
+ broker_ports[1]=${SRC_TCP_PORT_2}
+
+
+ print "Starting DST cluster"
+
+ print " dst broker 1"
+ $QPIDD_EXEC \
+ --port=${DST_TCP_PORT} \
+ --ssl-port ${DST_SSL_PORT} \
+ ${COMMON_BROKER_OPTIONS} \
+ --cluster-name ${CLUSTER_2_NAME} \
+ --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null
+
+ broker_ports[2]=${DST_TCP_PORT}
+
+ print " dst broker 2"
+ $QPIDD_EXEC \
+ --port=${DST_TCP_PORT_2} \
+ --ssl-port ${DST_SSL_PORT_2} \
+ ${COMMON_BROKER_OPTIONS} \
+ --cluster-name ${CLUSTER_2_NAME} \
+ --log-to-file $tmp_root/qpidd_dst_2.log 2> /dev/null
+
+ broker_ports[3]=${DST_TCP_PORT_2}
+
+ else
+ # vanilla brokers --------------------------------
+ print "Starting SRC broker"
+ $QPIDD_EXEC \
+ --port=${SRC_TCP_PORT} \
+ --ssl-port ${SRC_SSL_PORT} \
+ ${COMMON_BROKER_OPTIONS} \
+ --log-to-file $tmp_root/qpidd_src.log 2> /dev/null
+
+ broker_ports[0]=${SRC_TCP_PORT}
+
+ print "Starting DST broker"
+ $QPIDD_EXEC \
+ --port=${DST_TCP_PORT} \
+ --ssl-port ${DST_SSL_PORT} \
+ ${COMMON_BROKER_OPTIONS} \
+ --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null
+
+ broker_ports[1]=${DST_TCP_PORT}
+ fi
+}
-#echo "-----------------------"
-#echo "Starting SRC broker"
-#echo "-----------------------"
-$QPIDD_EXEC \
- --port=${SRC_TCP_PORT} \
- --ssl-port ${SRC_SSL_PORT} \
- --ssl-sasl-no-dict \
- --sasl-config=$sasl_config_file \
- --ssl-require-client-authentication \
- --auth yes \
- --ssl-cert-db $CERT_DIR \
- --ssl-cert-password-file $CERT_PW_FILE \
- --ssl-cert-name $TEST_HOSTNAME \
- --no-data-dir \
- --no-module-dir \
- --load-module ${SSL_LIB} \
- --mgmt-enable=yes \
- --log-enable info+ \
- --log-source yes \
- --daemon \
- --log-to-file $tmp_root/qpidd_src.log 2> /dev/null
-
-
-#echo "-----------------------"
-#echo "Starting DST broker"
-#echo "-----------------------"
-$QPIDD_EXEC \
- --port=${DST_TCP_PORT} \
- --ssl-port ${DST_SSL_PORT} \
- --ssl-cert-db $CERT_DIR \
- --ssl-cert-password-file $CERT_PW_FILE \
- --ssl-cert-name $TEST_HOSTNAME \
- --ssl-sasl-no-dict \
- --ssl-require-client-authentication \
- --sasl-config=$sasl_config_file \
- --no-data-dir \
- --no-module-dir \
- --load-module ${SSL_LIB} \
- --mgmt-enable=yes \
- --log-enable info+ \
- --log-source yes \
- --daemon \
- $COMMON_BROKER_OPTIONS \
- --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null
+function halt_brokers {
+ n_brokers=${#broker_ports[@]}
+ print "Halting ${n_brokers} brokers."
+ for i in $(seq 0 $((${n_brokers} - 1)))
+ do
+ halt_port=${broker_ports[$i]}
+ print "Halting broker $i on port ${halt_port}"
+ $QPIDD_EXEC --port ${halt_port} --quit
+ done
+
+}
+
+
+start_brokers $clustering_flag
# I am not randomizing these names, because this test creates its own brokers.
@@ -170,76 +269,77 @@ ROUTING_KEY=sasl_fed_queue
EXCHANGE_NAME=sasl_fedex
-#echo "-----------------------"
-#echo "add exchanges"
-#echo "-----------------------"
+print "add exchanges"
$QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} add exchange direct $EXCHANGE_NAME
$QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} add exchange direct $EXCHANGE_NAME
-#echo "-----------------------"
-#echo "add queues"
-#echo "-----------------------"
+print "add queues"
$QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} add queue $QUEUE_NAME
$QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} add queue $QUEUE_NAME
-#echo "-----------------------"
-#echo "create bindings"
-#echo "-----------------------"
+print "create bindings"
$QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} bind $EXCHANGE_NAME $QUEUE_NAME $ROUTING_KEY
$QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} bind $EXCHANGE_NAME $QUEUE_NAME $ROUTING_KEY
-#echo "-----------------------"
-#echo "qpid-route route add"
-#echo "-----------------------"
+#
# NOTE: The SRC broker *must* be referred to as $TEST_HOSTNAME, and not as "localhost".
# It must be referred to by the exact string given as the Common Name (CN) in the cert,
# which was created in the function create_certs, above.
-$QPID_ROUTE_EXEC route add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} -t ssl $EXCHANGE_NAME $ROUTING_KEY "" "" EXTERNAL
-#echo "-----------------------"
-#echo "view the route :"
-#echo "-----------------------"
-#$PYTHON_COMMANDS/qpid-route route list localhost:${DST_TCP_PORT}
-# I don't know how to avoid this sleep yet. It has to come after route-creation.
-sleep 5
-
-n_messages=100
-
-./datagen --count ${n_messages} | ./sender --broker localhost --port ${SRC_TCP_PORT} --exchange ${EXCHANGE_NAME} --routing-key ${ROUTING_KEY} --mechanism ANONYMOUS
+#----------------------------------------------------------------
+# Use qpid-route to create the link, or the link+route, depending
+# on which of its several methods was requested.
+#----------------------------------------------------------------
+if [ ${qpid_route_method} == "dynamic" ]; then
+ print "dynamic add"
+ $QPID_ROUTE_EXEC -t ssl dynamic add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME "" "" EXTERNAL
+elif [ ${qpid_route_method} == "link" ]; then
+ print "link add"
+ $QPID_ROUTE_EXEC -t ssl link add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} EXTERNAL
+elif [ ${qpid_route_method} == "queue" ]; then
+ print "queue add"
+ $QPID_ROUTE_EXEC -t ssl queue add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME $ROUTING_KEY EXTERNAL
+elif [ ${qpid_route_method} == "route" ]; then
+ print "route add"
+ $QPID_ROUTE_EXEC -t ssl route add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME $ROUTING_KEY "" "" EXTERNAL
+else
+ echo "unknown method: |${qpid_route_method}|"
+ echo " choices are: dynamic|link|queue|route "
+ print "Asking brokers to quit."
+ $QPIDD_EXEC --port ${SRC_TCP_PORT} --quit
+ $QPIDD_EXEC --port ${DST_TCP_PORT} --quit
+ exit 2
+fi
-#echo "-----------------------"
-#echo "Examine DST Broker"
-#echo "-----------------------"
-dst_message_count=`qpid-stat -q localhost:${DST_TCP_PORT} | grep sasl_fed_queue | awk '{print $2}'`
+# I don't know how to avoid this sleep yet. It has to come after route-creation
+# to avoid false negatives.
+sleep 5
+# This should work the same whether or not we are running a clustered test.
+print "check the link"
+link_status=$($QPID_ROUTE_EXEC link list localhost:${DST_TCP_PORT} | tail -1 | awk '{print $5}')
+print "link_status == ${link_status}"
-#echo "-----------------------"
-#echo "Asking brokers to quit."
-#echo "-----------------------"
-$QPIDD_EXEC --port ${SRC_TCP_PORT} --quit
-$QPIDD_EXEC --port ${DST_TCP_PORT} --quit
+halt_brokers
+sleep 1
-#echo "-----------------------"
-#echo "Removing temporary directory $tmp_root"
-#echo "-----------------------"
+print "Removing temporary directory $tmp_root"
rm -rf $tmp_root
-if [ "$dst_message_count" -eq "$n_messages" ]; then
- #echo "good: |$dst_message_count| == |$n_messages|"
+
+if [ ${link_status} == "Operational" ]; then
+ print "result: good"
exit 0
-else
- #echo "not ideal: |$dst_message_count| != |$n_messages|"
- exit 1
fi
-
-
+print "result: fail"
+exit 3
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_dynamic b/qpid/cpp/src/tests/sasl_fed_ex_dynamic
new file mode 100755
index 0000000000..c20b8d69a0
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_dynamic
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex dynamic
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_dynamic_cluster b/qpid/cpp/src/tests/sasl_fed_ex_dynamic_cluster
new file mode 100755
index 0000000000..273a543ec5
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_dynamic_cluster
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex dynamic cluster
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_link b/qpid/cpp/src/tests/sasl_fed_ex_link
new file mode 100755
index 0000000000..7b232d4874
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_link
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex link
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_link_cluster b/qpid/cpp/src/tests/sasl_fed_ex_link_cluster
new file mode 100755
index 0000000000..0e037b1969
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_link_cluster
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex link cluster
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_queue b/qpid/cpp/src/tests/sasl_fed_ex_queue
new file mode 100755
index 0000000000..be0c10cf63
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_queue
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex queue
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_queue_cluster b/qpid/cpp/src/tests/sasl_fed_ex_queue_cluster
new file mode 100755
index 0000000000..ec8750b861
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_queue_cluster
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex queue cluster
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_route b/qpid/cpp/src/tests/sasl_fed_ex_route
new file mode 100755
index 0000000000..dd5c4f3cac
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_route
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex route
+
+
diff --git a/qpid/cpp/src/tests/sasl_fed_ex_route_cluster b/qpid/cpp/src/tests/sasl_fed_ex_route_cluster
new file mode 100755
index 0000000000..fd59680b6e
--- /dev/null
+++ b/qpid/cpp/src/tests/sasl_fed_ex_route_cluster
@@ -0,0 +1,27 @@
+#! /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.
+#
+
+
+source ./test_env.sh
+
+${srcdir}/sasl_fed_ex route cluster
+
+
diff --git a/qpid/cpp/src/tests/ssl_test b/qpid/cpp/src/tests/ssl_test
index 04584f169d..cbf75eb237 100755
--- a/qpid/cpp/src/tests/ssl_test
+++ b/qpid/cpp/src/tests/ssl_test
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
diff --git a/qpid/cpp/xml/cluster.xml b/qpid/cpp/xml/cluster.xml
index ee5ef60e5e..e0cd647894 100644
--- a/qpid/cpp/xml/cluster.xml
+++ b/qpid/cpp/xml/cluster.xml
@@ -252,7 +252,6 @@
<!-- Replicate encoded exchanges/queues. -->
<control name="exchange" code="0x31"><field name="encoded" type="str32"/></control>
- <control name="queue" code="0x32"><field name="encoded" type="str32"/></control>
<!-- Set expiry-id for subsequent messages. -->
<control name="expiry-id" code="0x33"><field name="expiry-id" type="uint64"/></control>
diff --git a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
index 309492262d..6c27d7c668 100644
--- a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
+++ b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
@@ -56,6 +56,7 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="LVQ.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="queue-state-replication.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Starting-a-cluster.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="producer-flow-control.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="AMQP-Compatibility.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Qpid-Interoperability-Documentation.xml"/>
diff --git a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP.xml b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP.xml
index b9c513e511..15f5660455 100644
--- a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP.xml
+++ b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP.xml
@@ -50,7 +50,8 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="LVQ.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="queue-state-replication.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Starting-a-cluster.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ACL.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ACL.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="producer-flow-control.xml"/>
</chapter>
diff --git a/qpid/doc/book/src/Cheat-Sheet-for-configuring-Queue-Options.xml b/qpid/doc/book/src/Cheat-Sheet-for-configuring-Queue-Options.xml
index 60f1a4103d..d50948e0cc 100644
--- a/qpid/doc/book/src/Cheat-Sheet-for-configuring-Queue-Options.xml
+++ b/qpid/doc/book/src/Cheat-Sheet-for-configuring-Queue-Options.xml
@@ -65,6 +65,16 @@
</itemizedlist>
</para></listitem>
</itemizedlist>
+
+ <para>
+ The 0.10 C++ Broker supports the following additional Queue configuration options:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ <xref linkend="producer-flow-control"/>
+ </para></listitem>
+ </itemizedlist>
+
<section role="h3" id="CheatSheetforconfiguringQueueOptions-ApplyingQueueSizingConstraints"><title>
Applying Queue Sizing Constraints
</title>
diff --git a/qpid/doc/book/src/Programming-In-Apache-Qpid.xml b/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
index 3950b375da..6fae2f0bc7 100644
--- a/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
+++ b/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
@@ -1722,7 +1722,7 @@ try {
<row>
<entry>
- username
+ <literal>username</literal>
</entry>
<entry>
string
@@ -1733,7 +1733,7 @@ try {
</row>
<row>
<entry>
- password
+ <literal>password</literal>
</entry>
<entry>
string
@@ -1744,35 +1744,22 @@ try {
</row>
<row>
<entry>
- sasl-mechanism
+ <literal>sasl_mechanisms</literal>
</entry>
<entry>
string
</entry>
<entry>
- The specific SASL mechanism to use with the c++
- client when authenticating to the broker. Only a
- single value can be specified at present. [C++ only].
- </entry>
- </row>
- <row>
- <entry>
- sasl_mechanisms
- </entry>
- <entry>
- string
- </entry>
- <entry>
- The specific SASL mechanism to use with the python
+ The specific SASL mechanisms to use with the python
client when authenticating to the broker. The value
- is a space separated list in order of preference. [Python only].
+ is a space separated list.
</entry>
</row>
<row>
<entry>
- reconnect
+ <literal>reconnect</literal>
</entry>
<entry>
boolean
@@ -1783,7 +1770,7 @@ try {
</row>
<row>
<entry>
- <literal>reconnect_timeout&nbsp;[Python]</literal> <literal>reconnect-timeout&nbsp;[C++]</literal>
+ <literal>reconnect_timeout</literal>
</entry>
<entry>
integer
@@ -1794,7 +1781,7 @@ try {
</row>
<row>
<entry>
- <literal>reconnect_limit&nbsp;[Python]</literal> <literal>reconnect-limit&nbsp;[C++]</literal>
+ <literal>reconnect_limit</literal>
</entry>
<entry>
integer
@@ -1805,7 +1792,7 @@ try {
</row>
<row>
<entry>
- <literal>reconnect_interval_min&nbsp;[Python]</literal> <literal>reconnect-interval-min&nbsp;[C++]</literal>
+ <literal>reconnect_interval_min</literal>
</entry>
<entry>
integer representing time in seconds
@@ -1816,7 +1803,7 @@ try {
</row>
<row>
<entry>
- <literal>reconnect_interval_max&nbsp;[Python]</literal> <literal>reconnect-interval-max&nbsp;[C++]</literal>
+ <literal>reconnect_interval_max</literal>
</entry>
<entry>
integer representing time in seconds
@@ -1827,7 +1814,7 @@ try {
</row>
<row>
<entry>
- <literal>reconnect_interval&nbsp;[Python]</literal> <literal>reconnect-interval&nbsp;[C++]</literal>
+ <literal>reconnect_interval</literal>
</entry>
<entry>
integer representing time in seconds
@@ -1839,7 +1826,7 @@ try {
<row>
<entry>
- heartbeat
+ <literal>heartbeat</literal>
</entry>
<entry>
integer representing time in seconds
@@ -1852,7 +1839,7 @@ try {
</row>
<row>
<entry>
- protocol
+ <literal>protocol</literal>
</entry>
<entry>
string
@@ -1863,7 +1850,7 @@ try {
</row>
<row>
<entry>
- tcp-nodelay
+ <literal>tcp-nodelay</literal>
</entry>
<entry>
boolean
diff --git a/qpid/doc/book/src/producer-flow-control.xml b/qpid/doc/book/src/producer-flow-control.xml
new file mode 100644
index 0000000000..01ca4f8ac9
--- /dev/null
+++ b/qpid/doc/book/src/producer-flow-control.xml
@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<section id="producer-flow-control">
+ <title>
+ Producer Flow Control
+ </title>
+
+ <section role="h2" id="producerflowcontrol-Overview">
+ <title>
+ Overview
+ </title>
+ <para>
+ As of release 0.10, the C++ broker supports the use of flow control to
+ throttle back message producers that are at risk of overflowing a
+ destination queue.
+ </para>
+
+ <para>
+ Each queue in the C++ broker has two threshold values associated with it:
+ </para>
+
+ <para>
+ Flow Stop Threshold: this is the level of queue resource
+ utilization above which flow control will be enabled. Once this
+ threshold is crossed, the queue is considered in danger of overflow.
+ </para>
+
+ <para>
+ Flow Resume Threshold - this is the level of queue resource utilization
+ below which flow control will be disabled. Once this threshold is
+ crossed, the queue is no longer considered in danger of overflow.
+ </para>
+
+ <para>
+ In the above description, queue resource utilization may be
+ defined as the total count of messages currently enqueued, or the total
+ sum of all message content in bytes.
+ </para>
+
+ <para>
+ The value for a queue's Flow Stop Threshold must be greater than or
+ equal to the value of the queue's Flow Resume Threshold.
+ </para>
+
+ <section role="h3" id="producerflowcontrol-QueueThresholdsExample">
+ <title>
+ Example
+ </title>
+
+ <para>
+ Let's consider a queue with a maximum limit set on the total number of
+ messages that may be enqueued to that queue. Assume this maximum
+ message limit is 1000 messages. Assume also that the user configures a
+ Flow Stop Threshold of 900 messages, and a Flow Resume Threshold of 500
+ messages. Then the following holds:
+ </para>
+
+ <para>
+ When the total number of enqueued messages is greater than or equal to
+ 900, the queue's flow control state is OFF.
+ </para>
+
+ <para>
+ When the total number of enqueued messages is greater than 900, the
+ queue's flow control state transitions to ON.
+ </para>
+
+ <para>
+ When the queue's flow control state is "ON", it remains "ON" until the
+ total number of enqueued messages is less than 500. At that point, the queue's
+ flow control state transitions to "OFF".
+ </para>
+
+ <para>
+ A similar example using total enqueued content bytes as the threshold
+ units are permitted.
+ </para>
+ </section>
+
+ <para>
+ Thresholds may be set using both total message counts and total byte
+ counts. In this case, the following rules apply:
+ </para>
+
+ <para>
+ 1) Flow control is "ON" when either stop threshold value is crossed.
+ </para>
+ <para>
+ 2) Flow control remains "ON" until both resume thresholds are satisfied.
+ </para>
+
+ <section role="h3" id="producerflowcontro-MultiThresholdExample">
+ <title>
+ Example
+ </title>
+
+ <para>
+ Let's consider a queue with a maximum size limit of 10K bytes, and 5000
+ messages. A user may assign a Flow Stop Threshold based on a total
+ message count of 4000 messages. They may also assigne a Flow Stop
+ Threshold of 8K bytes. The queue's flow control state transitions to
+ "ON" if either threshold is crossed: (total-msgs greater-than 4000 OR total-bytes
+ greater-than 8K).
+ </para>
+
+ <para>
+ Assume the user has assigned Flow Resume threshold's of 3000 messages and
+ 6K bytes. Then the queue's flow control will remain active until both
+ thresholds are satified: (total-msg less-than 3000 AND total-bytes less-than 6K).
+ </para>
+ </section>
+
+ <para>
+ The Broker enforces flow control by delaying the completion of the
+ Message.Transfer command that causes a message to be delivered to a queue
+ with active flow control. The completion of the Message.Transfer command
+ is held off until flow control state transitions to "OFF" for all queues
+ that are a destination for that command.
+ </para>
+
+ <para>
+ A message producing client is permitted to have a finite number of
+ commands pending completion. When the total number of these outstanding
+ commands reaches the limit, the client must not issue further commands
+ until one or more of the outstanding commands have completed. This
+ window of outstanding commands is considered the sender's "capacity".
+ This allows any given producer to have a "capacity's" worth of messages
+ blocked due to flow control before the sender must stop sending further
+ messages.
+ </para>
+
+ <para>
+ This capacity window must be considered when determining a suitable
+ flow stop threshold for a given queue, as a producer may send its
+ capacity worth of messages _after_ a queue has reached the flow stop
+ threshold. Therefore, a flow stop threshould should be set such that
+ the queue can accomodate more messages without overflowing.
+ </para>
+
+ <para>
+ For example, assume two clients, C1 and C2, are producing messages to
+ one particular destination queue. Assume client C1 has a configured
+ capacity of 50 messages, and client C2's capacity is 15 messages. In
+ this example, assume C1 and C2 are the only clients queuing messages to
+ a given queue. If this queue has a Flow Stop Threshold of 100
+ messages, then, worst-case, the queue may receive up to 165 messages
+ before clients C1 and C2 are blocked from sending further messages.
+ This is due to the fact that the queue will enable flow control on
+ receipt of its 101'st message - preventing the completion of the
+ Message.Transfer command that carried the 101'st message. However, C1
+ and C2 are allowed to have a total of 65 (50 for C1 and 15 for C2)
+ messages pending completion of Message.Transfer before they will stop
+ producing messages. Thus, up to 65 messages may be enqueued beyond the
+ flow stop threshold before the producers will be blocked.
+ </para>
+ </section>
+
+ <section role="h2" id="producerflowcontrol-UserInterface">
+ <title>
+ User Interface
+ </title>
+
+ <para>
+ By default, the C++ broker assigns a queue's flow stop and flow resume
+ thresholds when the queue is created. The C++ broker also allows the
+ user to manually specify the flow control thresholds on a per queue
+ basis.
+ </para>
+
+ <para>
+ However, queues that have been configured with a Limit Policy of type
+ RING or RING-STRICT do NOT have queue flow thresholds enabled by
+ default. The nature of a RING queue defines its behavior when its
+ capacity is reach: replace the oldest message.
+ </para>
+
+ <para>
+ The flow control state of a queue can be determined by the "flowState"
+ boolean in the queue's QMF management object. The queue's management
+ object also contains a counter that increments each time flow control
+ becomes active for the queue.
+ </para>
+
+ <para>
+ The broker applies a threshold ratio to compute a queue's default flow
+ control configuration. These thresholds are expressed as a percentage
+ of a queue's maximum capacity. There is one value for determining the
+ stop threshold, and another for determining the resume threshold. The
+ user may configure these percentages using the following broker
+ configuration options:
+ </para>
+
+ <programlisting>
+ --default-flow-stop-threshold ("Queue capacity level at which flow control is activated.")
+ --default-flow-resume-threshold ("Queue capacity level at which flow control is de-activated.")
+ </programlisting>
+
+ <para>
+ For example:
+ </para>
+
+ <programlisting>
+ qpidd --default-flow-stop-threshold=90 --default-flow-resume-threshold=75
+ </programlisting>
+
+ <para>
+ Sets the default flow stop threshold to 90% of a queue's maximum
+ capacity and the flow resume threshold to 75% of the maximum capacity.
+ If a queue is created with a default-queue-limit of 10000 bytes, then
+ the default flow stop threshold would be 90% of 10000 = 9000 bytes and
+ the flow resume threshold would be 75% of 10000 = 7500. The same
+ computation is performed should a queue be created with a maximum size
+ expressed as a message count instead of a byte count.
+ </para>
+
+ <para>
+ If not overridden by the user, the value of the
+ default-flow-stop-threshold is 80% and the value of the
+ default-flow-resume-threshold is 70%.
+ </para>
+
+ <para>
+ The user may disable default queue flow control broker-wide by
+ specifying the value 0 for both of these configuration options. Note
+ that flow control may still be applied manually on a per-queue basis in
+ this case.
+ </para>
+
+ <para>
+ The user may manually set the flow thresholds when creating a queue.
+ The following options may be provided when adding a queue using the
+ <command>qpid-config</command> command line tool:
+ </para>
+
+ <programlisting>
+ --flow-stop-size=<replaceable>N</replaceable> Sets the queue's flow stop threshold to <replaceable>N</replaceable> total bytes.
+ --flow-resume-size=<replaceable>N</replaceable> Sets the queue's flow resume threshold to <replaceable>N</replaceable> total bytes.
+ --flow-stop-count=<replaceable>N</replaceable> Sets the queue's flow stop threshold to <replaceable>N</replaceable> total messages.
+ --flow-resume-count=<replaceable>N</replaceable> Sets the queue's flow resume threshold to <replaceable>N</replaceable> total messages.
+ </programlisting>
+
+ <para>
+ Flow thresholds may also be specified in the
+ <command>queue.declare</command> method, via the
+ <command>arguments</command> parameter map. The following keys can be
+ provided in the arguments map for setting flow thresholds:
+ </para>
+
+ <table>
+ <title>Queue Declare Method Flow Control Arguments</title>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Key</entry>
+ <entry>Value</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>qpid.flow_stop_size</entry>
+ <entry>integer - queue's flow stop threshold value in bytes</entry>
+ </row>
+ <row>
+ <entry>qpid.flow_resume_size</entry>
+ <entry>integer - queue's flow resume threshold value in bytes</entry>
+ </row>
+ <row>
+ <entry>qpid.flow_stop_count</entry>
+ <entry>integer - queue's flow stop threshold value as a message count</entry>
+ </row>
+ <row>
+ <entry>qpid.flow_resume_count</entry>
+ <entry>integer - queue's flow resume threshold value as a message count</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ The user may disable flow control on a per queue basis by setting
+ the flow-stop-size and flow-stop-count to zero for the queue.
+ </para>
+
+ <para>
+ The current state of flow control for a given queue can be
+ determined by the "flowStopped" statistic. This statistic is
+ available in the queue's QMF management object. The value of
+ flowStopped is True when the queue's capacity has exceeded the
+ flow stop threshold. The value of flowStopped is False when the
+ queue is no longer blocking due to flow control.
+ </para>
+
+ <para>
+ A queue will also track the number of times flow control has been
+ activated. The "flowStoppedCount" statistic is incremented each time
+ the queue's capacity exceeds a flow stop threshold. This statistic can
+ be used to monitor the activity of flow control for any given queue
+ over time.
+ </para>
+
+ <table>
+ <title>Flow Control Statistics available in Queue's QMF Class</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Statistic Name</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>flowStopped</entry>
+ <entry>Boolean</entry>
+ <entry>If true, producers are blocked by flow control.</entry>
+ </row>
+ <row>
+ <entry>flowStoppedCount</entry>
+ <entry>count32</entry>
+ <entry>Number of times flow control was activated for this queue</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+ <!--h2-->
+ </section>
diff --git a/qpid/cpp/src/tests/qrsh_utils/3_kill_it b/qpid/dotnet/Consumer/Program.cs
index afc7a03c9d..d9a6224a42 100755..100644
--- a/qpid/cpp/src/tests/qrsh_utils/3_kill_it
+++ b/qpid/dotnet/Consumer/Program.cs
@@ -9,7 +9,7 @@
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -17,11 +17,14 @@
* specific language governing permissions and limitations
* under the License.
*
- */
-
-#! /bin/bash
-
-echo "Killing command 2... "
-./qrsh 127.0.0.1 5813 \
- mrg23 exec kill -9 command_2
-
+ */
+namespace Consumer
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Client.Tests.interop.Consumer.Main(args);
+ }
+ }
+}
diff --git a/qpid/dotnet/Consumer/default.build b/qpid/dotnet/Consumer/default.build
new file mode 100644
index 0000000000..5b1e3166c5
--- /dev/null
+++ b/qpid/dotnet/Consumer/default.build
@@ -0,0 +1,47 @@
+<?xml version="1.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.
+
+-->
+
+<project name="Consumer" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/qpid/cpp/src/tests/qrsh_utils/10_all b/qpid/dotnet/Producer/Program.cs
index 7b486ea672..83dbf597ed 100755..100644
--- a/qpid/cpp/src/tests/qrsh_utils/10_all
+++ b/qpid/dotnet/Producer/Program.cs
@@ -9,7 +9,7 @@
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -17,14 +17,14 @@
* specific language governing permissions and limitations
* under the License.
*
- */
-
-#! /bin/bash
-
-echo "Asking all servers to say their names... "
-qrsh 127.0.0.1 5813 \
- all sayName
-
-
-
-
+ */
+namespace Producer
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Client.Tests.interop.Producer.Main(args);
+ }
+ }
+}
diff --git a/qpid/dotnet/Producer/default.build b/qpid/dotnet/Producer/default.build
new file mode 100644
index 0000000000..72d2a3fa8d
--- /dev/null
+++ b/qpid/dotnet/Producer/default.build
@@ -0,0 +1,47 @@
+<?xml version="1.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.
+
+-->
+
+<project name="Producer" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/qpid/cpp/src/tests/qrsh_utils/1_remote_run b/qpid/dotnet/Program.cs
index 5b9b307bba..d9a6224a42 100755..100644
--- a/qpid/cpp/src/tests/qrsh_utils/1_remote_run
+++ b/qpid/dotnet/Program.cs
@@ -9,7 +9,7 @@
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -17,10 +17,14 @@
* specific language governing permissions and limitations
* under the License.
*
- */
-
-#! /bin/bash
-
-
-./qrsh 127.0.0.1 5813 \
- mrg23 command_1 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
+ */
+namespace Consumer
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Client.Tests.interop.Consumer.Main(args);
+ }
+ }
+}
diff --git a/qpid/dotnet/Qpid.Client.Tests/interop/Consumer.cs b/qpid/dotnet/Qpid.Client.Tests/interop/Consumer.cs
new file mode 100644
index 0000000000..d60514ae4c
--- /dev/null
+++ b/qpid/dotnet/Qpid.Client.Tests/interop/Consumer.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Client.Tests.interop
+{
+ public class Consumer
+ {
+ public static void Main(string[] args)
+ {
+ try
+ {
+ const string connectionUrl = @"amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'";
+ const string queueName = @"test-queue";
+
+ var connectionInfo = QpidConnectionInfo.FromUrl(connectionUrl);
+ var connection = new AMQConnection(connectionInfo);
+ var channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
+
+ channel.DeclareQueue(queueName, false, true, true);
+ channel.Bind(queueName, ExchangeNameDefaults.DIRECT, queueName);
+ IMessageConsumer consumer = channel.CreateConsumerBuilder(queueName) .Create();
+ connection.Start();
+
+ ITextMessage message = (ITextMessage) consumer.Receive();
+ Console.WriteLine("Got: " + message.Text);
+ connection.Dispose();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+ }
+}
diff --git a/qpid/dotnet/Qpid.Client.Tests/interop/Producer.cs b/qpid/dotnet/Qpid.Client.Tests/interop/Producer.cs
new file mode 100644
index 0000000000..d775080fc3
--- /dev/null
+++ b/qpid/dotnet/Qpid.Client.Tests/interop/Producer.cs
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Client.Tests.interop
+{
+ public class Producer
+ {
+ public static void Main(string[] args)
+ {
+ try
+ {
+ const string connectionUrl = @"amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'";
+ const string queueName = @"test-queue";
+
+ var connectionInfo = QpidConnectionInfo.FromUrl(connectionUrl);
+ var connection = new AMQConnection(connectionInfo);
+ var channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+ var publisher = channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.DIRECT)
+ .WithRoutingKey(queueName)
+ .Create();
+ IMessage message = channel.CreateTextMessage("0123456789");
+ publisher.Send(message);
+ Console.WriteLine("Sent message");
+ connection.Dispose();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+ }
+}
diff --git a/qpid/dotnet/Qpid.Client.Tests/interop/TopicListener.cs b/qpid/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
index b355abb28d..e5daa64a89 100644
--- a/qpid/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
+++ b/qpid/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
@@ -19,6 +19,7 @@
*
*/
using System;
+using System.Threading;
using log4net;
using Apache.Qpid.Messaging;
using Apache.Qpid.Client.Qms;
@@ -47,6 +48,12 @@ namespace Apache.Qpid.Client.Tests.interop
/// <summary> Holds the producer to send report messages on. </summary>
private IMessagePublisher publisher;
+ /// <summary> A monitor used to wait for shutdown. </summary>
+ private AutoResetEvent shutdownReceivedEvt = new AutoResetEvent(false);
+
+ /// <summary> Holds the default test timeout for communications . </summary>
+ const int TIMEOUT = 60000;
+
/// <summary> Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. </summary> */
private bool init;
@@ -85,6 +92,15 @@ namespace Apache.Qpid.Client.Tests.interop
connection.Start();
Console.WriteLine("Waiting for messages...");
+
+ if (shutdownReceivedEvt.WaitOne(TIMEOUT, true))
+ {
+ Console.WriteLine("Shutting down - shut down message was received");
+ }
+ else
+ {
+ Console.WriteLine("Shutting down - timeout elapsed");
+ }
}
public static void Main(String[] argv)
@@ -185,6 +201,8 @@ namespace Apache.Qpid.Client.Tests.interop
connection.Stop();
channel.Dispose();
connection.Dispose();
+
+ shutdownReceivedEvt.Set();
}
/// <summary> Sends the report message to the response location. </summary>
diff --git a/qpid/dotnet/README.txt b/qpid/dotnet/README.txt
index 0199ad6410..70830a625c 100644
--- a/qpid/dotnet/README.txt
+++ b/qpid/dotnet/README.txt
@@ -32,6 +32,7 @@ If using nant, set up PATH to include Nant.exe, e.g.:
If using msbuild, it is recommended to use a "Visual Studio Command Prompt"
+
Building
========
@@ -49,6 +50,27 @@ If you are using nant, the script build-nant.bat contains standard arguments tha
To build for Mono on Linux (to bin/mono-2.0) the build-mono shell script is provided.
+Running the Examples
+====================
+
+The tree contains two paired examples that demonstrate some of the features of the library:
+Producer/Consumer and TopicPublisher/TopicListener.
+
+To run on Mono on Linux (cd to bin/mono-2.0) and execute
+
+mono Consumer.exe (in one window , and
+mono Producer.exe in another window)
+
+or:
+
+mono TopicListener.exe (in one window , and
+mono TopicPublisher.exe in another window)
+
+Both examples assume you have a broker running on localhost:5672. You must run Consumer/TopicListener
+before Producer/TopicPublisher in order that queue is created before the first message is sent.
+
+The source code for the examples is in directory Qpid.Client.Tests/interop.
+
Releasing
=========
diff --git a/qpid/dotnet/build-mono b/qpid/dotnet/build-mono
index 2bb6147b53..71d94ad268 100755
--- a/qpid/dotnet/build-mono
+++ b/qpid/dotnet/build-mono
@@ -18,4 +18,4 @@
# under the License.
#
-nant -t:mono-2.0
+nant -t:mono-2.0 "$@"
diff --git a/qpid/dotnet/build-nant-release b/qpid/dotnet/build-nant-release
index 611a1efe08..a6d73dc40a 100755
--- a/qpid/dotnet/build-nant-release
+++ b/qpid/dotnet/build-nant-release
@@ -1,24 +1,3 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#
-
#!/bin/bash
#
#
diff --git a/qpid/dotnet/default.build b/qpid/dotnet/default.build
index 4cd38e90ff..b038307623 100644
--- a/qpid/dotnet/default.build
+++ b/qpid/dotnet/default.build
@@ -62,9 +62,12 @@
<!-- Other test or utility assemblies. -->
<fileset id='other.builds'>
+ <include name="TestClient/default.build" />
+ <!-- Examples -->
<include name="TopicListener/default.build" />
<include name="TopicPublisher/default.build" />
- <include name="TestClient/default.build" />
+ <include name="Consumer/default.build" />
+ <include name="Producer/default.build" />
</fileset>
<!-- Prepare environment for a debug build. -->
diff --git a/qpid/extras/qmf/setup.py b/qpid/extras/qmf/setup.py
index 2e3ec7a38e..e7bf4b9717 100755
--- a/qpid/extras/qmf/setup.py
+++ b/qpid/extras/qmf/setup.py
@@ -20,10 +20,10 @@
from distutils.core import setup
setup(name="qpid-qmf",
- version="0.9",
+ version="0.11",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
- packages=["qmf", "qmf2", "qmf2.tests"],
+ packages=["qmf"],
package_dir={"": "src/py"},
url="http://qpid.apache.org/",
license="Apache Software License",
diff --git a/qpid/extras/qmf/src/py/qmf/console.py b/qpid/extras/qmf/src/py/qmf/console.py
index 6f4c11ae15..ecb0e1d9d0 100644
--- a/qpid/extras/qmf/src/py/qmf/console.py
+++ b/qpid/extras/qmf/src/py/qmf/console.py
@@ -1211,11 +1211,22 @@ class Session:
try:
agentName = ah["qmf.agent"]
values = content["_values"]
- timestamp = values["_timestamp"]
- interval = values["_heartbeat_interval"]
+
+ if '_timestamp' in values:
+ timestamp = values["_timestamp"]
+ else:
+ timestamp = values['timestamp']
+
+ if '_heartbeat_interval' in values:
+ interval = values['_heartbeat_interval']
+ else:
+ interval = values['heartbeat_interval']
+
epoch = 0
if '_epoch' in values:
epoch = values['_epoch']
+ elif 'epoch' in values:
+ epoch = values['epoch']
except Exception,e:
return
@@ -2416,7 +2427,7 @@ class Broker(Thread):
if uid.__class__ == tuple and len(uid) == 2:
self.saslUser = uid[1]
else:
- self.saslUser = None
+ self.saslUser = self.authUser
# prevent topic queues from filling up (and causing the agents to
# disconnect) by discarding the oldest queued messages when full.
diff --git a/qpid/extras/qmf/src/py/qmf2/__init__.py b/qpid/extras/qmf/src/py/qmf2-prototype/__init__.py
index 31d5a2ef58..31d5a2ef58 100644
--- a/qpid/extras/qmf/src/py/qmf2/__init__.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/__init__.py
diff --git a/qpid/extras/qmf/src/py/qmf2/agent.py b/qpid/extras/qmf/src/py/qmf2-prototype/agent.py
index 4ec00bd288..4ec00bd288 100644
--- a/qpid/extras/qmf/src/py/qmf2/agent.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/agent.py
diff --git a/qpid/extras/qmf/src/py/qmf2/common.py b/qpid/extras/qmf/src/py/qmf2-prototype/common.py
index 2e5367f54f..2e5367f54f 100644
--- a/qpid/extras/qmf/src/py/qmf2/common.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/common.py
diff --git a/qpid/extras/qmf/src/py/qmf2/console.py b/qpid/extras/qmf/src/py/qmf2-prototype/console.py
index 9227835b3f..9227835b3f 100644
--- a/qpid/extras/qmf/src/py/qmf2/console.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/console.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/__init__.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/__init__.py
index eff9357e1f..eff9357e1f 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/__init__.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/__init__.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/agent_discovery.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_discovery.py
index 2c20794aaa..2c20794aaa 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/agent_discovery.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_discovery.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/agent_test.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_test.py
index 14d8ada197..14d8ada197 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/agent_test.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/agent_test.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/async_method.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/async_method.py
index 2339fc71a9..2339fc71a9 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/async_method.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/async_method.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/async_query.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/async_query.py
index b1c01611f7..b1c01611f7 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/async_query.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/async_query.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/basic_method.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_method.py
index 8d038bc4c8..8d038bc4c8 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/basic_method.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_method.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/basic_query.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_query.py
index 9f5dda6d54..9f5dda6d54 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/basic_query.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/basic_query.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/console_test.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/console_test.py
index ac0e064f20..ac0e064f20 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/console_test.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/console_test.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/events.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/events.py
index 624c9b3823..624c9b3823 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/events.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/events.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/multi_response.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/multi_response.py
index 991fa0114e..991fa0114e 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/multi_response.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/multi_response.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/obj_gets.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/obj_gets.py
index 695b096973..695b096973 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/obj_gets.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/obj_gets.py
diff --git a/qpid/extras/qmf/src/py/qmf2/tests/subscriptions.py b/qpid/extras/qmf/src/py/qmf2-prototype/tests/subscriptions.py
index 5c39af4b32..5c39af4b32 100644
--- a/qpid/extras/qmf/src/py/qmf2/tests/subscriptions.py
+++ b/qpid/extras/qmf/src/py/qmf2-prototype/tests/subscriptions.py
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd
index 6e005f5bdb..f49578ba8c 100755
--- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.9.0
+ver: 0.11.0
Bundle-SymbolicName: qpid-shutdown-plugin
Bundle-Version: ${ver}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
index a6f319cb1f..5192d5be6f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
@@ -1096,6 +1096,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable
return Boolean.FALSE;
}
+ public Long getFlowStoppedCount()
+ {
+ return 0L;
+ }
+
public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory,
final Long request)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index a612f280d6..d1ea5dba69 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -327,4 +327,74 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
{
return getObjectNameForSingleInstanceMBean();
}
+
+ public void resetStatistics() throws Exception
+ {
+ getVirtualHost().resetStatistics();
+ }
+
+ public double getPeakMessageDeliveryRate()
+ {
+ return getVirtualHost().getMessageDeliveryStatistics().getPeak();
+ }
+
+ public double getPeakDataDeliveryRate()
+ {
+ return getVirtualHost().getDataDeliveryStatistics().getPeak();
+ }
+
+ public double getMessageDeliveryRate()
+ {
+ return getVirtualHost().getMessageDeliveryStatistics().getRate();
+ }
+
+ public double getDataDeliveryRate()
+ {
+ return getVirtualHost().getDataDeliveryStatistics().getRate();
+ }
+
+ public long getTotalMessagesDelivered()
+ {
+ return getVirtualHost().getMessageDeliveryStatistics().getTotal();
+ }
+
+ public long getTotalDataDelivered()
+ {
+ return getVirtualHost().getDataDeliveryStatistics().getTotal();
+ }
+
+ public double getPeakMessageReceiptRate()
+ {
+ return getVirtualHost().getMessageReceiptStatistics().getPeak();
+ }
+
+ public double getPeakDataReceiptRate()
+ {
+ return getVirtualHost().getDataReceiptStatistics().getPeak();
+ }
+
+ public double getMessageReceiptRate()
+ {
+ return getVirtualHost().getMessageReceiptStatistics().getRate();
+ }
+
+ public double getDataReceiptRate()
+ {
+ return getVirtualHost().getDataReceiptStatistics().getRate();
+ }
+
+ public long getTotalMessagesReceived()
+ {
+ return getVirtualHost().getMessageReceiptStatistics().getTotal();
+ }
+
+ public long getTotalDataReceived()
+ {
+ return getVirtualHost().getDataReceiptStatistics().getTotal();
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return getVirtualHost().isStatisticsEnabled();
+ }
}
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 4f86c82578..dd3046cd01 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
@@ -22,6 +22,7 @@ package org.apache.qpid.server;
import org.apache.log4j.Logger;
+import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQMethodBody;
@@ -141,6 +142,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
private final AtomicLong _txnCommits = new AtomicLong(0);
private final AtomicLong _txnRejects = new AtomicLong(0);
private final AtomicLong _txnCount = new AtomicLong(0);
+ private final AtomicLong _txnUpdateTime = new AtomicLong(0);
private final AMQProtocolSession _session;
private AtomicBoolean _closing = new AtomicBoolean(false);
@@ -200,6 +202,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
return !(_transaction instanceof AutoCommitTransaction);
}
+ public boolean inTransaction()
+ {
+ return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0;
+ }
+
private void incrementOutstandingTxnsIfNecessary()
{
if(isTransactional())
@@ -295,7 +302,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
});
deliverCurrentMessageIfComplete();
-
}
}
@@ -333,11 +339,15 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
_transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues, isTransactional()));
incrementOutstandingTxnsIfNecessary();
+ updateTransactionalActivity();
}
}
}
finally
{
+ long bodySize = _currentMessage.getSize();
+ long timestamp = ((BasicContentHeaderProperties) _currentMessage.getContentHeader().properties).getTimestamp();
+ _session.registerMessageReceived(bodySize, timestamp);
_currentMessage = null;
}
}
@@ -794,6 +804,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
Collection<QueueEntry> ackedMessages = getAckedMessages(deliveryTag, multiple);
_transaction.dequeue(ackedMessages, new MessageAcknowledgeAction(ackedMessages));
+ updateTransactionalActivity();
}
private Collection<QueueEntry> getAckedMessages(long deliveryTag, boolean multiple)
@@ -968,6 +979,17 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
}
+ /**
+ * Update last transaction activity timestamp
+ */
+ private void updateTransactionalActivity()
+ {
+ if (isTransactional())
+ {
+ _txnUpdateTime.set(System.currentTimeMillis());
+ }
+ }
+
public String toString()
{
return "["+_session.toString()+":"+_channelId+"]";
@@ -1018,6 +1040,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(),
deliveryTag, sub.getConsumerTag());
+ _session.registerMessageDelivered(entry.getMessage().getSize());
}
};
@@ -1407,4 +1430,36 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
_session.mgmtCloseChannel(_channelId);
}
+
+ public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException
+ {
+ if (inTransaction())
+ {
+ long currentTime = System.currentTimeMillis();
+ long openTime = currentTime - _transaction.getTransactionStartTime();
+ long idleTime = currentTime - _txnUpdateTime.get();
+
+ // Log a warning on idle or open transactions
+ if (idleWarn > 0L && idleTime > idleWarn)
+ {
+ CurrentActor.get().message(_logSubject, ChannelMessages.IDLE_TXN(idleTime));
+ _logger.warn("IDLE TRANSACTION ALERT " + _logSubject.toString() + " " + idleTime + " ms");
+ }
+ else if (openWarn > 0L && openTime > openWarn)
+ {
+ CurrentActor.get().message(_logSubject, ChannelMessages.OPEN_TXN(openTime));
+ _logger.warn("OPEN TRANSACTION ALERT " + _logSubject.toString() + " " + openTime + " ms");
+ }
+
+ // Close connection for idle or open transactions that have timed out
+ if (idleClose > 0L && idleTime > idleClose)
+ {
+ getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Idle transaction timed out");
+ }
+ else if (openClose > 0L && openTime > openClose)
+ {
+ getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Open transaction timed out");
+ }
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
index 71cf17ed60..9d3c4dd2e8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
@@ -320,8 +320,7 @@ public class Main
ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean();
configMBean.register();
- ServerInformationMBean sysInfoMBean =
- new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion());
+ ServerInformationMBean sysInfoMBean = new ServerInformationMBean(config);
sysInfoMBean.register();
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 7197ec8cdc..43be0611a5 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
@@ -767,6 +767,36 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
DEFAULT_HOUSEKEEPING_PERIOD));
}
+ public long getStatisticsSamplePeriod()
+ {
+ return getConfig().getLong("statistics.sample.period", 5000L);
+ }
+
+ public boolean isStatisticsGenerationBrokerEnabled()
+ {
+ return getConfig().getBoolean("statistics.generation.broker", false);
+ }
+
+ public boolean isStatisticsGenerationVirtualhostsEnabled()
+ {
+ return getConfig().getBoolean("statistics.generation.virtualhosts", false);
+ }
+
+ public boolean isStatisticsGenerationConnectionsEnabled()
+ {
+ return getConfig().getBoolean("statistics.generation.connections", false);
+ }
+
+ public long getStatisticsReportingPeriod()
+ {
+ return getConfig().getLong("statistics.reporting.period", 0L);
+ }
+
+ public boolean isStatisticsReportResetEnabled()
+ {
+ return getConfig().getBoolean("statistics.reporting.reset", false);
+ }
+
public NetworkDriverConfiguration getNetworkConfiguration()
{
return new NetworkDriverConfiguration()
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 d9d7083543..48f2d776bb 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
@@ -313,4 +313,24 @@ public class VirtualHostConfiguration extends ConfigurationPlugin
{
return getIntValue("housekeeping.poolSize", Runtime.getRuntime().availableProcessors());
}
+
+ public long getTransactionTimeoutOpenWarn()
+ {
+ return getLongValue("transactionTimeout.openWarn", 0L);
+ }
+
+ public long getTransactionTimeoutOpenClose()
+ {
+ return getLongValue("transactionTimeout.openClose", 0L);
+ }
+
+ public long getTransactionTimeoutIdleWarn()
+ {
+ return getLongValue("transactionTimeout.idleWarn", 0L);
+ }
+
+ public long getTransactionTimeoutIdleClose()
+ {
+ return getLongValue("transactionTimeout.idleClose", 0L);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
index bac751e0c8..c06305ee4e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
@@ -20,19 +20,19 @@
*/
package org.apache.qpid.server.connection;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.log4j.Logger;
-import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.common.Closeable;
import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.protocol.AMQConnectionModel;
public class ConnectionRegistry implements IConnectionRegistry, Closeable
{
- private List<AMQProtocolSession> _registry = new CopyOnWriteArrayList<AMQProtocolSession>();
+ private List<AMQConnectionModel> _registry = new CopyOnWriteArrayList<AMQConnectionModel>();
private Logger _logger = Logger.getLogger(ConnectionRegistry.class);
@@ -40,44 +40,42 @@ public class ConnectionRegistry implements IConnectionRegistry, Closeable
{
// None required
}
-
- public void expireClosedChannels()
- {
- for (AMQProtocolSession connection : _registry)
- {
- connection.closeIfLingeringClosedChannels();
- }
- }
/** Close all of the currently open connections. */
public void close()
{
while (!_registry.isEmpty())
{
- AMQProtocolSession connection = _registry.get(0);
-
- try
- {
- connection.closeConnection(0, new AMQConnectionException(AMQConstant.INTERNAL_ERROR, "Broker is shutting down",
- 0, 0,
- connection.getProtocolOutputConverter().getProtocolMajorVersion(),
- connection.getProtocolOutputConverter().getProtocolMinorVersion(),
- (Throwable) null), true);
- }
- catch (AMQException e)
- {
- _logger.warn("Error closing connection:" + e.getMessage());
- }
+ AMQConnectionModel connection = _registry.get(0);
+ closeConnection(connection, AMQConstant.INTERNAL_ERROR, "Broker is shutting down");
+ }
+ }
+
+ public void closeConnection(AMQConnectionModel connection, AMQConstant cause, String message)
+ {
+ try
+ {
+ connection.close(cause, message);
+ }
+ catch (AMQException e)
+ {
+ _logger.warn("Error closing connection:" + e.getMessage());
}
}
- public void registerConnection(AMQProtocolSession connnection)
+ public void registerConnection(AMQConnectionModel connnection)
{
_registry.add(connnection);
}
- public void deregisterConnection(AMQProtocolSession connnection)
+ public void deregisterConnection(AMQConnectionModel connnection)
{
_registry.remove(connnection);
}
+
+ @Override
+ public List<AMQConnectionModel> getConnections()
+ {
+ return new ArrayList<AMQConnectionModel>(_registry);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
index 002269bbaa..b4f5bffa57 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
@@ -20,18 +20,23 @@
*/
package org.apache.qpid.server.connection;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
+import java.util.List;
+
import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.protocol.AMQConnectionModel;
public interface IConnectionRegistry
{
-
public void initialise();
public void close() throws AMQException;
+
+ public void closeConnection(AMQConnectionModel connection, AMQConstant cause, String message);
+
+ public List<AMQConnectionModel> getConnections();
- public void registerConnection(AMQProtocolSession connnection);
-
- public void deregisterConnection(AMQProtocolSession connnection);
+ public void registerConnection(AMQConnectionModel connnection);
+ public void deregisterConnection(AMQConnectionModel connnection);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
index 7aeff2561e..0f1b709475 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
@@ -90,12 +90,12 @@ public abstract class AbstractExchangeMBean<T extends AbstractExchange> extends
public String getObjectInstanceName()
{
- return _exchange.getNameShortString().toString();
+ return ObjectName.quote(_exchange.getName());
}
public String getName()
{
- return _exchange.getNameShortString().toString();
+ return _exchange.getName();
}
public String getExchangeType()
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java
index db2cc970b2..5e6a143d52 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java
@@ -22,9 +22,11 @@ package org.apache.qpid.server.information.management;
import java.io.IOException;
+import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.management.common.mbeans.ServerInformation;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import javax.management.JMException;
@@ -34,12 +36,15 @@ public class ServerInformationMBean extends AMQManagedObject implements ServerIn
{
private String buildVersion;
private String productVersion;
+ private ApplicationRegistry registry;
- public ServerInformationMBean(String buildVersion, String productVersion) throws JMException
+ public ServerInformationMBean(ApplicationRegistry applicationRegistry) throws JMException
{
super(ServerInformation.class, ServerInformation.TYPE);
- this.buildVersion = buildVersion;
- this.productVersion = productVersion;
+
+ registry = applicationRegistry;
+ buildVersion = QpidProperties.getBuildVersion();
+ productVersion = QpidProperties.getReleaseVersion();
}
public String getObjectInstanceName()
@@ -67,5 +72,75 @@ public class ServerInformationMBean extends AMQManagedObject implements ServerIn
return productVersion;
}
+
+ public void resetStatistics() throws Exception
+ {
+ registry.resetStatistics();
+ }
+
+ public double getPeakMessageDeliveryRate()
+ {
+ return registry.getMessageDeliveryStatistics().getPeak();
+ }
+
+ public double getPeakDataDeliveryRate()
+ {
+ return registry.getDataDeliveryStatistics().getPeak();
+ }
+
+ public double getMessageDeliveryRate()
+ {
+ return registry.getMessageDeliveryStatistics().getRate();
+ }
+
+ public double getDataDeliveryRate()
+ {
+ return registry.getDataDeliveryStatistics().getRate();
+ }
+
+ public long getTotalMessagesDelivered()
+ {
+ return registry.getMessageDeliveryStatistics().getTotal();
+ }
+
+ public long getTotalDataDelivered()
+ {
+ return registry.getDataDeliveryStatistics().getTotal();
+ }
+
+ public double getPeakMessageReceiptRate()
+ {
+ return registry.getMessageReceiptStatistics().getPeak();
+ }
+
+ public double getPeakDataReceiptRate()
+ {
+ return registry.getDataReceiptStatistics().getPeak();
+ }
+
+ public double getMessageReceiptRate()
+ {
+ return registry.getMessageReceiptStatistics().getRate();
+ }
+
+ public double getDataReceiptRate()
+ {
+ return registry.getDataReceiptStatistics().getRate();
+ }
+
+ public long getTotalMessagesReceived()
+ {
+ return registry.getMessageReceiptStatistics().getTotal();
+ }
+
+ public long getTotalDataReceived()
+ {
+ return registry.getDataReceiptStatistics().getTotal();
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return registry.isStatisticsEnabled();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
index 6b83a7e7a5..5d1e85fe41 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
@@ -32,4 +32,7 @@ STOPPED = BRK-1005 : Stopped
# 0 - path
CONFIG = BRK-1006 : Using configuration : {0}
# 0 - path
-LOG_CONFIG = BRK-1007 : Using logging configuration : {0} \ No newline at end of file
+LOG_CONFIG = BRK-1007 : Using logging configuration : {0}
+
+STATS_DATA = BRK-1008 : {0,choice,0#delivered|1#received} : {1,number,#.###} kB/s peak : {2,number,#} bytes total
+STATS_MSGS = BRK-1009 : {0,choice,0#delivered|1#received} : {1,number,#.###} msg/s peak : {2,number,#} msgs total \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
index 53bcd712f2..ed8c0d0ce9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
@@ -28,3 +28,7 @@ PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number}
# 0 - queue causing flow control
FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0})
FLOW_REMOVED = CHN-1006 : Flow Control Removed
+# Channel Transactions
+# 0 - time in milliseconds
+OPEN_TXN = CHN-1007 : Open Transaction : {0,number} ms
+IDLE_TXN = CHN-1008 : Idle Transaction : {0,number} ms
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties
index 66bbefacb0..3e640c7929 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/VirtualHost_logmessages.properties
@@ -20,4 +20,7 @@
#
# 0 - name
CREATED = VHT-1001 : Created : {0}
-CLOSED = VHT-1002 : Closed \ No newline at end of file
+CLOSED = VHT-1002 : Closed
+
+STATS_DATA = VHT-1003 : {0} : {1,choice,0#delivered|1#received} : {2,number,#.###} kB/s peak : {3,number,#} bytes total
+STATS_MSGS = VHT-1004 : {0} : {1,choice,0#delivered|1#received} : {2,number,#.###} msg/s peak : {3,number,#} msgs total` \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
index 0a739af695..7924964fdf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
@@ -153,32 +153,4 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return "";
}
- protected static StringBuffer jmxEncode(StringBuffer jmxName, int attrPos)
- {
- for (int i = attrPos; i < jmxName.length(); i++)
- {
- if (jmxName.charAt(i) == ',')
- {
- jmxName.setCharAt(i, ';');
- }
- else if (jmxName.charAt(i) == ':')
- {
- jmxName.setCharAt(i, '-');
- }
- else if (jmxName.charAt(i) == '?' ||
- jmxName.charAt(i) == '*' ||
- jmxName.charAt(i) == '\\')
- {
- jmxName.insert(i, '\\');
- i++;
- }
- else if (jmxName.charAt(i) == '\n')
- {
- jmxName.insert(i, '\\');
- i++;
- jmxName.setCharAt(i, 'n');
- }
- }
- return jmxName;
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
index 964b5ed5a0..380f51e308 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
@@ -213,6 +213,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
ObjectName object = (ObjectName) args[0];
String vhost = object.getKeyProperty("VirtualHost");
+ if(vhost != null)
+ {
+ try
+ {
+ //if the name is quoted in the ObjectName, unquote it
+ vhost = ObjectName.unquote(vhost);
+ }
+ catch(IllegalArgumentException e)
+ {
+ //ignore, this just means the name is not quoted
+ //and can be left unchanged
+ }
+ }
+
return vhost;
}
return null;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
index a6bab017a1..4e8d64a136 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
@@ -63,7 +63,7 @@ public class PluginManager implements Closeable
private static final Logger _logger = Logger.getLogger(PluginManager.class);
private static final int FELIX_STOP_TIMEOUT = 30000;
- private static final String QPID_VER_SUFFIX = "version=0.9,";
+ private static final String QPID_VER_SUFFIX = "version=0.11,";
private Framework _felix;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java
index bcda385f64..061ebf50cd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java
@@ -20,14 +20,35 @@
*/
package org.apache.qpid.server.protocol;
-import org.apache.qpid.protocol.AMQConstant;
+import java.util.List;
+import java.util.UUID;
+
import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.stats.StatisticsGatherer;
-public interface AMQConnectionModel
+public interface AMQConnectionModel extends StatisticsGatherer
{
+ /**
+ * get a unique id for this connection.
+ *
+ * @return a {@link UUID} representing the connection
+ */
+ public UUID getId();
+
+ /**
+ * Close the underlying Connection
+ *
+ * @param cause
+ * @param message
+ * @throws org.apache.qpid.AMQException
+ */
+ public void close(AMQConstant cause, String message) throws AMQException;
/**
* Close the given requested Session
+ *
* @param session
* @param cause
* @param message
@@ -36,4 +57,16 @@ public interface AMQConnectionModel
public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException;
public long getConnectionId();
+
+ /**
+ * Get a list of all sessions using this connection.
+ *
+ * @return a list of {@link AMQSessionModel}s
+ */
+ public List<AMQSessionModel> getSessionModels();
+
+ /**
+ * Return a {@link LogSubject} for the connection.
+ */
+ public LogSubject getLogSubject();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index a1ffe272fd..449f698c48 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -30,7 +30,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -92,6 +91,7 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.stats.StatisticsCounter;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
import org.apache.qpid.transport.NetworkDriver;
@@ -172,6 +172,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
private final UUID _id;
private final ConfigStore _configStore;
private long _createTime = System.currentTimeMillis();
+
+ private ApplicationRegistry _registry;
+ private boolean _statisticsEnabled = false;
+ private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
public ManagedObject getManagedObject()
{
@@ -195,9 +199,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
_configStore = virtualHostRegistry.getConfigStore();
_id = _configStore.createId();
-
_actor.message(ConnectionMessages.OPEN(null, null, false, false));
+ _registry = virtualHostRegistry.getApplicationRegistry();
+ initialiseStatistics();
}
private AMQProtocolSessionMBean createMBean() throws JMException
@@ -1078,19 +1083,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
return (_clientVersion == null) ? null : _clientVersion.toString();
}
- public void closeIfLingeringClosedChannels()
- {
- for (Entry<Integer, Long>id : _closingChannelsList.entrySet())
- {
- if (id.getValue() + 30000 > System.currentTimeMillis())
- {
- // We have a channel that we closed 30 seconds ago. Client's dead, kill the connection
- _logger.error("Closing connection as channel was closed more than 30 seconds ago and no ChannelCloseOk has been processed");
- closeProtocolSession();
- }
- }
- }
-
public Boolean isIncoming()
{
return true;
@@ -1263,7 +1255,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
public void closeSession(AMQSessionModel session, AMQConstant cause, String message) throws AMQException
{
-
closeChannel((Integer)session.getID());
MethodRegistry methodRegistry = getMethodRegistry();
@@ -1274,5 +1265,97 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
0,0);
writeFrame(responseBody.generateFrame((Integer)session.getID()));
- }
+ }
+
+ public void close(AMQConstant cause, String message) throws AMQException
+ {
+ closeConnection(0, new AMQConnectionException(cause, message, 0, 0,
+ getProtocolOutputConverter().getProtocolMajorVersion(),
+ getProtocolOutputConverter().getProtocolMinorVersion(),
+ (Throwable) null), true);
+ }
+
+ public List<AMQSessionModel> getSessionModels()
+ {
+ List<AMQSessionModel> sessions = new ArrayList<AMQSessionModel>();
+ for (AMQChannel channel : getChannels())
+ {
+ sessions.add((AMQSessionModel) channel);
+ }
+ return sessions;
+ }
+
+ public LogSubject getLogSubject()
+ {
+ return _logSubject;
+ }
+
+ public void registerMessageDelivered(long messageSize)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesDelivered.registerEvent(1L);
+ _dataDelivered.registerEvent(messageSize);
+ }
+ _virtualHost.registerMessageDelivered(messageSize);
+ }
+
+ public void registerMessageReceived(long messageSize, long timestamp)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesReceived.registerEvent(1L, timestamp);
+ _dataReceived.registerEvent(messageSize, timestamp);
+ }
+ _virtualHost.registerMessageReceived(messageSize, timestamp);
+ }
+
+ public StatisticsCounter getMessageReceiptStatistics()
+ {
+ return _messagesReceived;
+ }
+
+ public StatisticsCounter getDataReceiptStatistics()
+ {
+ return _dataReceived;
+ }
+
+ public StatisticsCounter getMessageDeliveryStatistics()
+ {
+ return _messagesDelivered;
+ }
+
+ public StatisticsCounter getDataDeliveryStatistics()
+ {
+ return _dataDelivered;
+ }
+
+ public void resetStatistics()
+ {
+ _messagesDelivered.reset();
+ _dataDelivered.reset();
+ _messagesReceived.reset();
+ _dataReceived.reset();
+ }
+
+ public void initialiseStatistics()
+ {
+ setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS &&
+ _registry.getConfiguration().isStatisticsGenerationConnectionsEnabled());
+
+ _messagesDelivered = new StatisticsCounter("messages-delivered-" + getSessionID());
+ _dataDelivered = new StatisticsCounter("data-delivered-" + getSessionID());
+ _messagesReceived = new StatisticsCounter("messages-received-" + getSessionID());
+ _dataReceived = new StatisticsCounter("data-received-" + getSessionID());
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return _statisticsEnabled;
+ }
+
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _statisticsEnabled = enabled;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
index f48a214933..c64ed4ad5a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
@@ -231,7 +231,5 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Prin
List<AMQChannel> getChannels();
- void closeIfLingeringClosedChannels();
-
void mgmtCloseChannel(int channelId);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
index f4f2cab2c2..fcac78fafa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
@@ -37,25 +37,15 @@
*/
package org.apache.qpid.server.protocol;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ConnectionCloseBody;
-import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.management.common.mbeans.ManagedConnection;
-import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
-import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.server.logging.actors.ManagementActor;
-import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.ManagedObject;
+import java.util.Date;
+import java.util.List;
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanNotificationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
+import javax.management.ObjectName;
import javax.management.monitor.MonitorNotification;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
@@ -66,8 +56,20 @@ import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
-import java.util.Date;
-import java.util.List;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.management.ManagedObject;
/**
* This MBean class implements the management interface. In order to make more attributes, operations and notifications
@@ -94,8 +96,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
super(ManagedConnection.class, ManagedConnection.TYPE);
_protocolSession = amqProtocolSession;
String remote = getRemoteAddress();
- remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote;
- _name = jmxEncode(new StringBuffer(remote), 0).toString();
+ _name = "anonymous".equals(remote) ? (remote + hashCode()) : remote;
init();
}
@@ -175,7 +176,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
public String getObjectInstanceName()
{
- return _name;
+ return ObjectName.quote(_name);
}
/**
@@ -339,4 +340,78 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
_broadcaster.sendNotification(n);
}
-} // End of MBean class
+ public void resetStatistics() throws Exception
+ {
+ _protocolSession.resetStatistics();
+ }
+
+ public double getPeakMessageDeliveryRate()
+ {
+ return _protocolSession.getMessageDeliveryStatistics().getPeak();
+ }
+
+ public double getPeakDataDeliveryRate()
+ {
+ return _protocolSession.getDataDeliveryStatistics().getPeak();
+ }
+
+ public double getMessageDeliveryRate()
+ {
+ return _protocolSession.getMessageDeliveryStatistics().getRate();
+ }
+
+ public double getDataDeliveryRate()
+ {
+ return _protocolSession.getDataDeliveryStatistics().getRate();
+ }
+
+ public long getTotalMessagesDelivered()
+ {
+ return _protocolSession.getMessageDeliveryStatistics().getTotal();
+ }
+
+ public long getTotalDataDelivered()
+ {
+ return _protocolSession.getDataDeliveryStatistics().getTotal();
+ }
+
+ public double getPeakMessageReceiptRate()
+ {
+ return _protocolSession.getMessageReceiptStatistics().getPeak();
+ }
+
+ public double getPeakDataReceiptRate()
+ {
+ return _protocolSession.getDataReceiptStatistics().getPeak();
+ }
+
+ public double getMessageReceiptRate()
+ {
+ return _protocolSession.getMessageReceiptStatistics().getRate();
+ }
+
+ public double getDataReceiptRate()
+ {
+ return _protocolSession.getDataReceiptStatistics().getRate();
+ }
+
+ public long getTotalMessagesReceived()
+ {
+ return _protocolSession.getMessageReceiptStatistics().getTotal();
+ }
+
+ public long getTotalDataReceived()
+ {
+ return _protocolSession.getDataReceiptStatistics().getTotal();
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return _protocolSession.isStatisticsEnabled();
+ }
+
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _protocolSession.setStatisticsEnabled(enabled);
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
index a9b2354d75..bc63403a86 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
@@ -20,15 +20,35 @@
*/
package org.apache.qpid.server.protocol;
+import org.apache.qpid.AMQException;
import org.apache.qpid.server.logging.LogSubject;
public interface AMQSessionModel
{
- Object getID();
+ public Object getID();
- AMQConnectionModel getConnectionModel();
+ public AMQConnectionModel getConnectionModel();
- String getClientID();
+ public String getClientID();
+
+ public void close() throws AMQException;
- LogSubject getLogSubject();
+ public LogSubject getLogSubject();
+
+ /**
+ * This method is called from the housekeeping thread to check the status of
+ * transactions on this session and react appropriately.
+ *
+ * If a transaction is open for too long or idle for too long then a warning
+ * is logged or the connection is closed, depending on the configuration. An open
+ * transaction is one that has recent activity. The transaction age is counted
+ * from the time the transaction was started. An idle transaction is one that
+ * has had no activity, such as publishing or acknowledgeing messages.
+ *
+ * @param openWarn time in milliseconds before alerting on open transaction
+ * @param openClose time in milliseconds before closing connection with open transaction
+ * @param idleWarn time in milliseconds before alerting on idle transaction
+ * @param idleClose time in milliseconds before closing connection with idle transaction
+ */
+ public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index b5294b6d2f..77c4e8fc23 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -43,6 +43,7 @@ import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
+import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.monitor.MonitorNotification;
import javax.management.openmbean.ArrayType;
@@ -97,7 +98,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
{
super(ManagedQueue.class, ManagedQueue.TYPE);
_queue = queue;
- _queueName = jmxEncode(new StringBuffer(queue.getNameShortString()), 0).toString();
+ _queueName = queue.getName();
}
public ManagedObject getParentObject()
@@ -147,7 +148,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
public String getObjectInstanceName()
{
- return _queueName;
+ return ObjectName.quote(_queueName);
}
public String getName()
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 78a642f22f..72b2a68450 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
@@ -23,6 +23,8 @@ package org.apache.qpid.server.registry;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.UUID;
import org.apache.commons.configuration.ConfigurationException;
@@ -41,11 +43,12 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.logging.CompositeStartupMessageLogger;
import org.apache.qpid.server.logging.Log4jMessageLogger;
import org.apache.qpid.server.logging.RootMessageLogger;
-import org.apache.qpid.server.logging.AbstractRootMessageLogger;
import org.apache.qpid.server.logging.SystemOutMessageLogger;
+import org.apache.qpid.server.logging.actors.AbstractActor;
import org.apache.qpid.server.logging.actors.BrokerActor;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.logging.messages.VirtualHostMessages;
import org.apache.qpid.server.management.ManagedObjectRegistry;
import org.apache.qpid.server.management.NoopManagedObjectRegistry;
import org.apache.qpid.server.plugins.PluginManager;
@@ -54,6 +57,7 @@ import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalD
import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.stats.StatisticsCounter;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostImpl;
@@ -104,6 +108,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
private ConfigStore _configStore;
protected String _registryName;
+
+ private Timer _reportingTimer;
+ private boolean _statisticsEnabled = false;
+ private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
static
{
@@ -294,6 +302,8 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
initialiseVirtualHosts();
+ initialiseStatistics();
+ initialiseStatisticsReporting();
}
finally
{
@@ -320,6 +330,72 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
{
_managedObjectRegistry = new NoopManagedObjectRegistry();
}
+
+ public void initialiseStatisticsReporting()
+ {
+ long report = _configuration.getStatisticsReportingPeriod() * 1000; // convert to ms
+ final boolean broker = _configuration.isStatisticsGenerationBrokerEnabled();
+ final boolean virtualhost = _configuration.isStatisticsGenerationVirtualhostsEnabled();
+ final boolean reset = _configuration.isStatisticsReportResetEnabled();
+
+ /* add a timer task to report statistics if generation is enabled for broker or virtualhosts */
+ if (report > 0L && (broker || virtualhost))
+ {
+ _reportingTimer = new Timer("Statistics-Reporting", true);
+
+ class StatisticsReportingTask extends TimerTask
+ {
+ private final int DELIVERED = 0;
+ private final int RECEIVED = 1;
+
+ public void run()
+ {
+ CurrentActor.set(new AbstractActor(ApplicationRegistry.getInstance().getRootMessageLogger()) {
+ public String getLogMessage()
+ {
+ return "[" + Thread.currentThread().getName() + "] ";
+ }
+ });
+
+ if (broker)
+ {
+ CurrentActor.get().message(BrokerMessages.STATS_DATA(DELIVERED, _dataDelivered.getPeak() / 1024.0, _dataDelivered.getTotal()));
+ CurrentActor.get().message(BrokerMessages.STATS_MSGS(DELIVERED, _messagesDelivered.getPeak(), _messagesDelivered.getTotal()));
+ CurrentActor.get().message(BrokerMessages.STATS_DATA(RECEIVED, _dataReceived.getPeak() / 1024.0, _dataReceived.getTotal()));
+ CurrentActor.get().message(BrokerMessages.STATS_MSGS(RECEIVED, _messagesReceived.getPeak(), _messagesReceived.getTotal()));
+ }
+
+ if (virtualhost)
+ {
+ for (VirtualHost vhost : getVirtualHostRegistry().getVirtualHosts())
+ {
+ String name = vhost.getName();
+ StatisticsCounter dataDelivered = vhost.getDataDeliveryStatistics();
+ StatisticsCounter messagesDelivered = vhost.getMessageDeliveryStatistics();
+ StatisticsCounter dataReceived = vhost.getDataReceiptStatistics();
+ StatisticsCounter messagesReceived = vhost.getMessageReceiptStatistics();
+
+ CurrentActor.get().message(VirtualHostMessages.STATS_DATA(name, DELIVERED, dataDelivered.getPeak() / 1024.0, dataDelivered.getTotal()));
+ CurrentActor.get().message(VirtualHostMessages.STATS_MSGS(name, DELIVERED, messagesDelivered.getPeak(), messagesDelivered.getTotal()));
+ CurrentActor.get().message(VirtualHostMessages.STATS_DATA(name, RECEIVED, dataReceived.getPeak() / 1024.0, dataReceived.getTotal()));
+ CurrentActor.get().message(VirtualHostMessages.STATS_MSGS(name, RECEIVED, messagesReceived.getPeak(), messagesReceived.getTotal()));
+ }
+ }
+
+ if (reset)
+ {
+ resetStatistics();
+ }
+
+ CurrentActor.remove();
+ }
+ }
+
+ _reportingTimer.scheduleAtFixedRate(new StatisticsReportingTask(),
+ report / 2,
+ report);
+ }
+ }
public static IApplicationRegistry getInstance()
{
@@ -369,6 +445,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
{
_logger.info("Shutting down ApplicationRegistry:" + this);
}
+
+ //Stop Statistics Reporting
+ if (_reportingTimer != null)
+ {
+ _reportingTimer.cancel();
+ }
//Stop incoming connections
unbind();
@@ -498,4 +580,76 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
getBroker().addVirtualHost(virtualHost);
return virtualHost;
}
+
+ public void registerMessageDelivered(long messageSize)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesDelivered.registerEvent(1L);
+ _dataDelivered.registerEvent(messageSize);
+ }
+ }
+
+ public void registerMessageReceived(long messageSize, long timestamp)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesReceived.registerEvent(1L, timestamp);
+ _dataReceived.registerEvent(messageSize, timestamp);
+ }
+ }
+
+ public StatisticsCounter getMessageReceiptStatistics()
+ {
+ return _messagesReceived;
+ }
+
+ public StatisticsCounter getDataReceiptStatistics()
+ {
+ return _dataReceived;
+ }
+
+ public StatisticsCounter getMessageDeliveryStatistics()
+ {
+ return _messagesDelivered;
+ }
+
+ public StatisticsCounter getDataDeliveryStatistics()
+ {
+ return _dataDelivered;
+ }
+
+ public void resetStatistics()
+ {
+ _messagesDelivered.reset();
+ _dataDelivered.reset();
+ _messagesReceived.reset();
+ _dataReceived.reset();
+
+ for (VirtualHost vhost : _virtualHostRegistry.getVirtualHosts())
+ {
+ vhost.resetStatistics();
+ }
+ }
+
+ public void initialiseStatistics()
+ {
+ setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS &&
+ getConfiguration().isStatisticsGenerationBrokerEnabled());
+
+ _messagesDelivered = new StatisticsCounter("messages-delivered");
+ _dataDelivered = new StatisticsCounter("bytes-delivered");
+ _messagesReceived = new StatisticsCounter("messages-received");
+ _dataReceived = new StatisticsCounter("bytes-received");
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return _statisticsEnabled;
+ }
+
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _statisticsEnabled = enabled;
+ }
}
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 228c3b9112..0ef55097ce 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
@@ -35,11 +35,12 @@ import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-public interface IApplicationRegistry
+public interface IApplicationRegistry extends StatisticsGatherer
{
/**
* Initialise the application registry. All initialisation must be done in this method so that any components
@@ -97,4 +98,6 @@ public interface IApplicationRegistry
ConfigStore getConfigStore();
void setConfigStore(ConfigStore store);
+
+ void initialiseStatisticsReporting();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java
new file mode 100644
index 0000000000..b732121180
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.stats;
+
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class collects statistics and counts the total, rate per second and
+ * peak rate per second values for the events that are registered with it.
+ */
+public class StatisticsCounter
+{
+ private static final Logger _log = LoggerFactory.getLogger(StatisticsCounter.class);
+
+ public static final long DEFAULT_SAMPLE_PERIOD = Long.getLong("qpid.statistics.samplePeriod", 2000L); // 2s
+ public static final boolean DISABLE_STATISTICS = Boolean.getBoolean("qpid.statistics.disable");
+
+ private static final String COUNTER = "counter";
+ private static final AtomicLong _counterIds = new AtomicLong(0L);
+
+ private long _peak = 0L;
+ private long _total = 0L;
+ private long _temp = 0L;
+ private long _last = 0L;
+ private long _rate = 0L;
+
+ private long _start;
+
+ private final long _period;
+ private final String _name;
+
+ public StatisticsCounter()
+ {
+ this(COUNTER);
+ }
+
+ public StatisticsCounter(String name)
+ {
+ this(name, DEFAULT_SAMPLE_PERIOD);
+ }
+
+ public StatisticsCounter(String name, long period)
+ {
+ _period = period;
+ _name = name + "-" + + _counterIds.incrementAndGet();
+ reset();
+ }
+
+ public void registerEvent()
+ {
+ registerEvent(1L);
+ }
+
+ public void registerEvent(long value)
+ {
+ registerEvent(value, System.currentTimeMillis());
+ }
+
+ public void registerEvent(long value, long timestamp)
+ {
+ if (DISABLE_STATISTICS)
+ {
+ return;
+ }
+
+ long thisSample = (timestamp / _period);
+ synchronized (this)
+ {
+ if (thisSample > _last)
+ {
+ _last = thisSample;
+ _rate = _temp;
+ _temp = 0L;
+ if (_rate > _peak)
+ {
+ _peak = _rate;
+ }
+ }
+
+ _total += value;
+ _temp += value;
+ }
+ }
+
+ /**
+ * Update the current rate and peak - may reset rate to zero if a new
+ * sample period has started.
+ */
+ private void update()
+ {
+ registerEvent(0L, System.currentTimeMillis());
+ }
+
+ /**
+ * Reset
+ */
+ public void reset()
+ {
+ _log.info("Resetting statistics for counter: " + _name);
+ _peak = 0L;
+ _rate = 0L;
+ _total = 0L;
+ _start = System.currentTimeMillis();
+ _last = _start / _period;
+ }
+
+ public double getPeak()
+ {
+ update();
+ return (double) _peak / ((double) _period / 1000.0d);
+ }
+
+ public double getRate()
+ {
+ update();
+ return (double) _rate / ((double) _period / 1000.0d);
+ }
+
+ public long getTotal()
+ {
+ return _total;
+ }
+
+ public long getStart()
+ {
+ return _start;
+ }
+
+ public Date getStartTime()
+ {
+ return new Date(_start);
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public long getPeriod()
+ {
+ return _period;
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java
new file mode 100644
index 0000000000..36fec4025a
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.stats;
+
+/**
+ * This interface is to be implemented by any broker business object that
+ * wishes to gather statistics about messages delivered through it.
+ *
+ * These statistics are exposed using a separate JMX Mbean interface, which
+ * calls these methods to retrieve the underlying {@link StatisticsCounter}s
+ * and return their attributes. This interface gives a standard way for
+ * parts of the broker to set up and configure statistics generation.
+ * <p>
+ * When creating these objects, there should be a parent/child relationship
+ * between them, such that the lowest level gatherer can record staticics if
+ * enabled, and pass on the notification to the parent object to allow higher
+ * level aggregation. When resetting statistics, this works in the opposite
+ * direction, with higher level gatherers also resetting all of their children.
+ */
+public interface StatisticsGatherer
+{
+ /**
+ * Initialise the statistics gathering for this object.
+ *
+ * This method is responsible for creating any {@link StatisticsCounter}
+ * objects and for determining whether statistics generation should be
+ * enabled, by checking broker and system configuration.
+ *
+ * @see StatisticsCounter#DISABLE_STATISTICS
+ */
+ void initialiseStatistics();
+
+ /**
+ * This method is responsible for registering the receipt of a message
+ * with the counters, and also for passing this notification to any parent
+ * {@link StatisticsGatherer}s. If statistics generation is not enabled,
+ * then this method should simple delegate to the parent gatherer.
+ *
+ * @param messageSize the size in bytes of the delivered message
+ * @param timestamp the time the message was delivered
+ */
+ void registerMessageReceived(long messageSize, long timestamp);
+
+ /**
+ * This method is responsible for registering the delivery of a message
+ * with the counters. Message delivery is recorded by the counter using
+ * the current system time, as opposed to the message timestamp.
+ *
+ * @param messageSize the size in bytes of the delivered message
+ * @see #registerMessageReceived(long, long)
+ */
+ void registerMessageDelivered(long messageSize);
+
+ /**
+ * Gives access to the {@link StatisticsCounter} that is used to count
+ * delivered message statistics.
+ *
+ * @return the {@link StatisticsCounter} that counts delivered messages
+ */
+ StatisticsCounter getMessageDeliveryStatistics();
+
+ /**
+ * Gives access to the {@link StatisticsCounter} that is used to count
+ * received message statistics.
+ *
+ * @return the {@link StatisticsCounter} that counts received messages
+ */
+ StatisticsCounter getMessageReceiptStatistics();
+
+ /**
+ * Gives access to the {@link StatisticsCounter} that is used to count
+ * delivered message size statistics.
+ *
+ * @return the {@link StatisticsCounter} that counts delivered bytes
+ */
+ StatisticsCounter getDataDeliveryStatistics();
+
+ /**
+ * Gives access to the {@link StatisticsCounter} that is used to count
+ * received message size statistics.
+ *
+ * @return the {@link StatisticsCounter} that counts received bytes
+ */
+ StatisticsCounter getDataReceiptStatistics();
+
+ /**
+ * Reset the counters for this, and any child {@link StatisticsGatherer}s.
+ */
+ void resetStatistics();
+
+ /**
+ * Check if this object has statistics generation enabled.
+ *
+ * @return true if statistics generation is enabled
+ */
+ boolean isStatisticsEnabled();
+
+ /**
+ * Enable or disable statistics generation for this object.
+ */
+ void setStatisticsEnabled(boolean enabled);
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
index b36ac84cdd..a20436f029 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -97,7 +97,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
private FlowCreditManager_0_10 _creditManager;
-
private StateListener _stateListener = new StateListener()
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
index d2addfde0c..75bd50e3a2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -24,6 +24,9 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*;
import java.text.MessageFormat;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
@@ -35,12 +38,16 @@ import org.apache.qpid.server.logging.actors.GenericActor;
import org.apache.qpid.server.logging.messages.ConnectionMessages;
import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.server.protocol.AMQSessionModel;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.stats.StatisticsCounter;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionCloseCode;
import org.apache.qpid.transport.ExecutionErrorCode;
import org.apache.qpid.transport.ExecutionException;
import org.apache.qpid.transport.Method;
import org.apache.qpid.transport.ProtocolEvent;
+import org.apache.qpid.transport.Session;
public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject
{
@@ -49,11 +56,20 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
private AtomicBoolean _logClosed = new AtomicBoolean(false);
private LogActor _actor = GenericActor.getInstance(this);
+ private ApplicationRegistry _registry;
+ private boolean _statisticsEnabled = false;
+ private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
+
public ServerConnection()
{
}
+ public UUID getId()
+ {
+ return _config.getId();
+ }
+
@Override
protected void invoke(Method method)
{
@@ -110,6 +126,9 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void setVirtualHost(VirtualHost virtualHost)
{
_virtualHost = virtualHost;
+ _virtualHost.getConnectionRegistry().registerConnection(this);
+
+ initialiseStatistics();
}
public void setConnectionConfig(final ConnectionConfig config)
@@ -145,6 +164,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
((ServerSession)session).close();
}
+
+ public LogSubject getLogSubject()
+ {
+ return (LogSubject) this;
+ }
@Override
public void received(ProtocolEvent event)
@@ -215,4 +239,100 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
{
return _actor;
}
+
+ @Override
+ public void close(AMQConstant cause, String message) throws AMQException
+ {
+ ConnectionCloseCode replyCode = ConnectionCloseCode.NORMAL;
+ try
+ {
+ replyCode = ConnectionCloseCode.get(cause.getCode());
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // Ignore
+ }
+ close(replyCode, message);
+ getVirtualHost().getConnectionRegistry().deregisterConnection(this);
+ }
+
+ @Override
+ public List<AMQSessionModel> getSessionModels()
+ {
+ List<AMQSessionModel> sessions = new ArrayList<AMQSessionModel>();
+ for (Session ssn : getChannels())
+ {
+ sessions.add((AMQSessionModel) ssn);
+ }
+ return sessions;
+ }
+
+ public void registerMessageDelivered(long messageSize)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesDelivered.registerEvent(1L);
+ _dataDelivered.registerEvent(messageSize);
+ }
+ _virtualHost.registerMessageDelivered(messageSize);
+ }
+
+ public void registerMessageReceived(long messageSize, long timestamp)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesReceived.registerEvent(1L, timestamp);
+ _dataReceived.registerEvent(messageSize, timestamp);
+ }
+ _virtualHost.registerMessageReceived(messageSize, timestamp);
+ }
+
+ public StatisticsCounter getMessageReceiptStatistics()
+ {
+ return _messagesReceived;
+ }
+
+ public StatisticsCounter getDataReceiptStatistics()
+ {
+ return _dataReceived;
+ }
+
+ public StatisticsCounter getMessageDeliveryStatistics()
+ {
+ return _messagesDelivered;
+ }
+
+ public StatisticsCounter getDataDeliveryStatistics()
+ {
+ return _dataDelivered;
+ }
+
+ public void resetStatistics()
+ {
+ _messagesDelivered.reset();
+ _dataDelivered.reset();
+ _messagesReceived.reset();
+ _dataReceived.reset();
+ }
+
+ public void initialiseStatistics()
+ {
+ setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS &&
+ _virtualHost.getApplicationRegistry().getConfiguration().isStatisticsGenerationConnectionsEnabled());
+
+ _messagesDelivered = new StatisticsCounter("messages-delivered-" + getConnectionId());
+ _dataDelivered = new StatisticsCounter("data-delivered-" + getConnectionId());
+ _messagesReceived = new StatisticsCounter("messages-received-" + getConnectionId());
+ _dataReceived = new StatisticsCounter("data-received-" + getConnectionId());
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return _statisticsEnabled;
+ }
+
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _statisticsEnabled = enabled;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index 2b9e92f685..174dcbfa69 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -20,26 +20,28 @@
*/
package org.apache.qpid.server.transport;
-import org.apache.qpid.transport.*;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.server.logging.actors.GenericActor;
-import org.apache.qpid.common.ClientProperties;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
import org.apache.qpid.protocol.ProtocolEngine;
-import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.virtualhost.VirtualHost;
-
-import javax.security.sasl.SaslServer;
-import javax.security.sasl.SaslException;
-import java.util.*;
+import org.apache.qpid.transport.*;
public class ServerConnectionDelegate extends ServerDelegate
{
private String _localFQDN;
private final IApplicationRegistry _appRegistry;
-
public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN)
{
this(new HashMap<String,Object>(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN);
@@ -138,6 +140,7 @@ public class ServerConnectionDelegate extends ServerDelegate
sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'"));
sconn.setState(Connection.State.CLOSING);
}
+
}
@Override
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index 540ad3fffd..60c94b43c0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -20,12 +20,26 @@
*/
package org.apache.qpid.server.transport;
-import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT;
-import static org.apache.qpid.util.Serial.gt;
+import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*;
+import static org.apache.qpid.util.Serial.*;
-import com.sun.security.auth.UserPrincipal;
+import java.lang.ref.WeakReference;
+import java.security.Principal;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.server.configuration.ConfigStore;
import org.apache.qpid.server.configuration.ConfiguredObject;
@@ -38,6 +52,8 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.protocol.AMQConnectionModel;
+import org.apache.qpid.server.protocol.AMQSessionModel;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.BaseQueue;
import org.apache.qpid.server.queue.QueueEntry;
@@ -48,8 +64,6 @@ import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.txn.LocalTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.transport.Binary;
import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.MessageTransfer;
@@ -58,24 +72,15 @@ import org.apache.qpid.transport.Range;
import org.apache.qpid.transport.RangeSet;
import org.apache.qpid.transport.Session;
import org.apache.qpid.transport.SessionDelegate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import java.lang.ref.WeakReference;
-import java.security.Principal;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicLong;
+import com.sun.security.auth.UserPrincipal;
public class ServerSession extends Session implements PrincipalHolder, SessionConfig, AMQSessionModel, LogSubject
{
+ private static final Logger _logger = LoggerFactory.getLogger(ServerSession.class);
+
private static final String NULL_DESTINTATION = UUID.randomUUID().toString();
private final UUID _id;
@@ -111,6 +116,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
private final AtomicLong _txnCommits = new AtomicLong(0);
private final AtomicLong _txnRejects = new AtomicLong(0);
private final AtomicLong _txnCount = new AtomicLong(0);
+ private final AtomicLong _txnUpdateTime = new AtomicLong(0);
private Principal _principal;
@@ -141,7 +147,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
_connectionConfig = connConfig;
_transaction = new AutoCommitTransaction(this.getMessageStore());
_principal = new UserPrincipal(connection.getAuthorizationID());
- _reference = new WeakReference(this);
+ _reference = new WeakReference<Session>(this);
_id = getConfigStore().createId();
getConfigStore().addConfiguredObject(this);
}
@@ -160,8 +166,8 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
public void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues)
{
-
- _transaction.enqueue(queues,message, new ServerTransaction.Action()
+ getConnectionModel().registerMessageReceived(message.getSize(), message.getArrivalTime());
+ _transaction.enqueue(queues,message, new ServerTransaction.Action()
{
BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]);
@@ -189,6 +195,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
});
incrementOutstandingTxnsIfNecessary();
+ updateTransactionalActivity();
}
@@ -196,6 +203,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
Runnable postIdSettingAction)
{
invoke(xfr, postIdSettingAction);
+ getConnectionModel().registerMessageDelivered(xfr.getBodySize());
}
public void onMessageDispositionChange(MessageTransfer xfr, MessageDispositionChangeListener acceptListener)
@@ -377,6 +385,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
entry.release();
}
});
+ updateTransactionalActivity();
}
public Collection<Subscription_0_10> getSubscriptions()
@@ -425,6 +434,11 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
// theory
return !(_transaction instanceof AutoCommitTransaction);
}
+
+ public boolean inTransaction()
+ {
+ return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0;
+ }
public void selectTx()
{
@@ -471,6 +485,17 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
}
}
+ /**
+ * Update last transaction activity timestamp
+ */
+ public void updateTransactionalActivity()
+ {
+ if (isTransactional())
+ {
+ _txnUpdateTime.set(System.currentTimeMillis());
+ }
+ }
+
public Long getTxnStarts()
{
return _txnStarts.get();
@@ -606,6 +631,38 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
return (LogSubject) this;
}
+ public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException
+ {
+ if (inTransaction())
+ {
+ long currentTime = System.currentTimeMillis();
+ long openTime = currentTime - _transaction.getTransactionStartTime();
+ long idleTime = currentTime - _txnUpdateTime.get();
+
+ // Log a warning on idle or open transactions
+ if (idleWarn > 0L && idleTime > idleWarn)
+ {
+ CurrentActor.get().message(getLogSubject(), ChannelMessages.IDLE_TXN(openTime));
+ _logger.warn("IDLE TRANSACTION ALERT " + getLogSubject().toString() + " " + idleTime + " ms");
+ }
+ else if (openWarn > 0L && openTime > openWarn)
+ {
+ CurrentActor.get().message(getLogSubject(), ChannelMessages.OPEN_TXN(openTime));
+ _logger.warn("OPEN TRANSACTION ALERT " + getLogSubject().toString() + " " + openTime + " ms");
+ }
+
+ // Close connection for idle or open transactions that have timed out
+ if (idleClose > 0L && idleTime > idleClose)
+ {
+ getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Idle transaction timed out");
+ }
+ else if (openClose > 0L && openTime > openClose)
+ {
+ getConnectionModel().closeSession(this, AMQConstant.RESOURCE_ERROR, "Open transaction timed out");
+ }
+ }
+ }
+
@Override
public String toLogString()
{
@@ -617,7 +674,5 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
getVirtualHost().getName(),
getChannel())
+ "] ";
-
}
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index 42a3975e24..be659c87ae 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -209,26 +209,27 @@ public class ServerSessionDelegate extends SessionDelegate
}
else
{
-
if(queue.isExclusive())
{
+ ServerSession s = (ServerSession) session;
+ queue.setExclusiveOwningSession(s);
if(queue.getPrincipalHolder() == null)
{
- queue.setPrincipalHolder((ServerSession)session);
+ queue.setPrincipalHolder(s);
+ queue.setExclusiveOwningSession(s);
((ServerSession) session).addSessionCloseTask(new ServerSession.Task()
{
-
public void doTask(ServerSession session)
{
if(queue.getPrincipalHolder() == session)
{
queue.setPrincipalHolder(null);
+ queue.setExclusiveOwningSession(null);
}
}
});
}
-
}
FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L);
@@ -369,7 +370,6 @@ public class ServerSessionDelegate extends SessionDelegate
}
ssn.processed(xfr);
-
}
@Override
@@ -969,10 +969,10 @@ public class ServerSessionDelegate extends SessionDelegate
}
- if(method.hasAutoDelete()
- && method.getAutoDelete()
- && method.hasExclusive()
- && method.getExclusive())
+ if (method.hasAutoDelete()
+ && method.getAutoDelete()
+ && method.hasExclusive()
+ && method.getExclusive())
{
final AMQQueue q = queue;
final ServerSession.Task deleteQueueTask = new ServerSession.Task()
@@ -999,12 +999,12 @@ public class ServerSessionDelegate extends SessionDelegate
}
});
}
- else if(method.getExclusive())
+ if (method.hasExclusive()
+ && method.getExclusive())
{
final AMQQueue q = queue;
final ServerSession.Task removeExclusive = new ServerSession.Task()
{
-
public void doTask(ServerSession session)
{
q.setPrincipalHolder(null);
@@ -1012,10 +1012,10 @@ public class ServerSessionDelegate extends SessionDelegate
}
};
final ServerSession s = (ServerSession) session;
+ q.setExclusiveOwningSession(s);
s.addSessionCloseTask(removeExclusive);
queue.addQueueDeleteTask(new AMQQueue.Task()
{
-
public void doTask(AMQQueue queue) throws AMQException
{
s.removeSessionCloseTask(removeExclusive);
@@ -1029,7 +1029,7 @@ public class ServerSessionDelegate extends SessionDelegate
}
}
}
- else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session)))
+ else if (method.getExclusive() && (queue.getExclusiveOwningSession() != null && !queue.getExclusiveOwningSession().equals(session)))
{
String description = "Cannot declare queue('" + queueName + "'),"
+ " as exclusive queue with same name "
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
index db781ead96..36e9d78440 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
@@ -50,6 +50,11 @@ public class AutoCommitTransaction implements ServerTransaction
_transactionLog = transactionLog;
}
+ public long getTransactionStartTime()
+ {
+ return 0L;
+ }
+
/**
* Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered
* by the caller are executed immediately.
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
index a04c743be1..f9dac782a6 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
@@ -20,18 +20,23 @@ package org.apache.qpid.server.txn;
*
*/
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.EnqueableMessage;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.queue.BaseQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.store.TransactionLog;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A concrete implementation of ServerTransaction where enqueue/dequeue
@@ -41,17 +46,28 @@ import org.apache.qpid.server.store.TransactionLog;
*/
public class LocalTransaction implements ServerTransaction
{
- protected static final Logger _logger = Logger.getLogger(LocalTransaction.class);
+ protected static final Logger _logger = LoggerFactory.getLogger(LocalTransaction.class);
private final List<Action> _postTransactionActions = new ArrayList<Action>();
private volatile TransactionLog.Transaction _transaction;
private TransactionLog _transactionLog;
+ private long _txnStartTime = 0L;
public LocalTransaction(TransactionLog transactionLog)
{
_transactionLog = transactionLog;
}
+
+ public boolean inTransaction()
+ {
+ return _transaction != null;
+ }
+
+ public long getTransactionStartTime()
+ {
+ return _txnStartTime;
+ }
public void addPostTransactionAction(Action postTransactionAction)
{
@@ -89,7 +105,6 @@ public class LocalTransaction implements ServerTransaction
try
{
-
for(QueueEntry entry : queueEntries)
{
ServerMessage message = entry.getMessage();
@@ -113,7 +128,6 @@ public class LocalTransaction implements ServerTransaction
_logger.error("Error during message dequeues", e);
tidyUpOnError(e);
}
-
}
private void tidyUpOnError(Exception e)
@@ -140,8 +154,7 @@ public class LocalTransaction implements ServerTransaction
}
finally
{
- _transaction = null;
- _postTransactionActions.clear();
+ resetDetails();
}
}
@@ -193,8 +206,25 @@ public class LocalTransaction implements ServerTransaction
{
_postTransactionActions.add(postTransactionAction);
+ if (_txnStartTime == 0L)
+ {
+ _txnStartTime = System.currentTimeMillis();
+ }
+
if(message.isPersistent())
{
+ if(_transaction == null)
+ {
+ for(BaseQueue queue : queues)
+ {
+ if(queue.isDurable())
+ {
+ beginTranIfNecessary();
+ break;
+ }
+ }
+ }
+
try
{
for(BaseQueue queue : queues)
@@ -248,17 +278,14 @@ public class LocalTransaction implements ServerTransaction
}
finally
{
- _transaction = null;
- _postTransactionActions.clear();
+ resetDetails();
}
-
}
public void rollback()
{
try
{
-
if(_transaction != null)
{
_transaction.abortTran();
@@ -280,9 +307,15 @@ public class LocalTransaction implements ServerTransaction
}
finally
{
- _transaction = null;
- _postTransactionActions.clear();
+ resetDetails();
}
}
}
+
+ private void resetDetails()
+ {
+ _transaction = null;
+ _postTransactionActions.clear();
+ _txnStartTime = 0L;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
index b61b8a5c64..b3c6e1ac3a 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
@@ -52,6 +52,13 @@ public interface ServerTransaction
public void onRollback();
}
+ /**
+ * Return the time the current transaction started.
+ *
+ * @return the time this transaction started or 0 if not in a transaction
+ */
+ long getTransactionStartTime();
+
/**
* Register an Action for execution after transaction commit or rollback. Actions
* will be executed in the order in which they are registered.
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
index 4ed0507228..04f19b79bb 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
@@ -20,30 +20,28 @@
*/
package org.apache.qpid.server.virtualhost;
+import java.util.UUID;
+
import org.apache.qpid.common.Closeable;
+import org.apache.qpid.server.binding.BindingFactory;
+import org.apache.qpid.server.configuration.ConfigStore;
+import org.apache.qpid.server.configuration.VirtualHostConfig;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.connection.IConnectionRegistry;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.federation.BrokerLink;
-import org.apache.qpid.server.configuration.VirtualHostConfiguration;
-import org.apache.qpid.server.configuration.VirtualHostConfig;
-import org.apache.qpid.server.configuration.ConfigStore;
+import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
-import org.apache.qpid.server.exchange.ExchangeFactory;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TransactionLog;
-import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.binding.BindingFactory;
-
-import java.util.List;
-import java.util.UUID;
-import java.util.TimerTask;
-import java.util.concurrent.FutureTask;
+import org.apache.qpid.server.stats.StatisticsGatherer;
+import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.TransactionLog;
-public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable
+public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable, StatisticsGatherer
{
IConnectionRegistry getConnectionRegistry();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
index 6ec1c512e5..5374a56f06 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
@@ -24,19 +24,18 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQInternalException;
import org.apache.qpid.AMQStoreException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
@@ -63,6 +62,8 @@ import org.apache.qpid.server.logging.messages.VirtualHostMessages;
import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.protocol.AMQConnectionModel;
+import org.apache.qpid.server.protocol.AMQSessionModel;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.queue.DefaultQueueRegistry;
@@ -72,6 +73,7 @@ import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.stats.StatisticsCounter;
import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.store.MessageStore;
@@ -111,6 +113,8 @@ public class VirtualHostImpl implements VirtualHost
private BrokerConfig _broker;
private UUID _id;
+ private boolean _statisticsEnabled = false;
+ private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
private final long _createTime = System.currentTimeMillis();
private final ConcurrentHashMap<BrokerLink,BrokerLink> _links = new ConcurrentHashMap<BrokerLink, BrokerLink>();
@@ -161,12 +165,12 @@ public class VirtualHostImpl implements VirtualHost
public String getObjectInstanceName()
{
- return _name.toString();
+ return ObjectName.quote(_name);
}
public String getName()
{
- return _name.toString();
+ return _name;
}
public VirtualHostImpl getVirtualHost()
@@ -249,6 +253,8 @@ public class VirtualHostImpl implements VirtualHost
_brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
_brokerMBean.register();
initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod());
+
+ initialiseStatistics();
}
private void initialiseHouseKeeping(long period)
@@ -281,19 +287,30 @@ public class VirtualHostImpl implements VirtualHost
// house keeping task from running.
}
}
+ for (AMQConnectionModel connection : getConnectionRegistry().getConnections())
+ {
+ _logger.debug("Checking for long running open transactions on connection " + connection);
+ for (AMQSessionModel session : connection.getSessionModels())
+ {
+ _logger.debug("Checking for long running open transactions on session " + session);
+ try
+ {
+ session.checkTransactionStatus(_configuration.getTransactionTimeoutOpenWarn(),
+ _configuration.getTransactionTimeoutOpenClose(),
+ _configuration.getTransactionTimeoutIdleWarn(),
+ _configuration.getTransactionTimeoutIdleClose());
+ }
+ catch (Exception e)
+ {
+ _logger.error("Exception in housekeeping for connection: " + connection.toString(), e);
+ }
+ }
+ }
}
}
scheduleHouseKeepingTask(period, new ExpiredMessagesTask(this));
- class ForceChannelClosuresTask extends TimerTask
- {
- public void run()
- {
- _connectionRegistry.expireClosedChannels();
- }
- }
-
Map<String, VirtualHostPluginFactory> plugins =
ApplicationRegistry.getInstance().getPluginManager().getVirtualHostPlugins();
@@ -627,6 +644,80 @@ public class VirtualHostImpl implements VirtualHost
{
return _bindingFactory;
}
+
+ public void registerMessageDelivered(long messageSize)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesDelivered.registerEvent(1L);
+ _dataDelivered.registerEvent(messageSize);
+ }
+ _appRegistry.registerMessageDelivered(messageSize);
+ }
+
+ public void registerMessageReceived(long messageSize, long timestamp)
+ {
+ if (isStatisticsEnabled())
+ {
+ _messagesReceived.registerEvent(1L, timestamp);
+ _dataReceived.registerEvent(messageSize, timestamp);
+ }
+ _appRegistry.registerMessageReceived(messageSize, timestamp);
+ }
+
+ public StatisticsCounter getMessageReceiptStatistics()
+ {
+ return _messagesReceived;
+ }
+
+ public StatisticsCounter getDataReceiptStatistics()
+ {
+ return _dataReceived;
+ }
+
+ public StatisticsCounter getMessageDeliveryStatistics()
+ {
+ return _messagesDelivered;
+ }
+
+ public StatisticsCounter getDataDeliveryStatistics()
+ {
+ return _dataDelivered;
+ }
+
+ public void resetStatistics()
+ {
+ _messagesDelivered.reset();
+ _dataDelivered.reset();
+ _messagesReceived.reset();
+ _dataReceived.reset();
+
+ for (AMQConnectionModel connection : _connectionRegistry.getConnections())
+ {
+ connection.resetStatistics();
+ }
+ }
+
+ public void initialiseStatistics()
+ {
+ setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS &&
+ _appRegistry.getConfiguration().isStatisticsGenerationVirtualhostsEnabled());
+
+ _messagesDelivered = new StatisticsCounter("messages-delivered-" + getName());
+ _dataDelivered = new StatisticsCounter("bytes-delivered-" + getName());
+ _messagesReceived = new StatisticsCounter("messages-received-" + getName());
+ _dataReceived = new StatisticsCounter("bytes-received-" + getName());
+ }
+
+ public boolean isStatisticsEnabled()
+ {
+ return _statisticsEnabled;
+ }
+
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _statisticsEnabled = enabled;
+ }
public void createBrokerConnection(final String transport,
final String host,
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/stats/StatisticsCounterTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/stats/StatisticsCounterTest.java
new file mode 100644
index 0000000000..fbaa1342c9
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/stats/StatisticsCounterTest.java
@@ -0,0 +1,144 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.stats;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for the {@link StatisticsCounter} class.
+ */
+public class StatisticsCounterTest extends TestCase
+{
+ /**
+ * Check that statistics counters are created correctly.
+ */
+ public void testCreate()
+ {
+ long before = System.currentTimeMillis();
+ StatisticsCounter counter = new StatisticsCounter("name", 1234L);
+ long after = System.currentTimeMillis();
+
+ assertTrue(before <= counter.getStart());
+ assertTrue(after >= counter.getStart());
+ assertTrue(counter.getName().startsWith("name-"));
+ assertEquals(1234L, counter.getPeriod());
+ }
+
+ /**
+ * Check that totals add up correctly.
+ */
+ public void testTotal()
+ {
+ StatisticsCounter counter = new StatisticsCounter("test", 1000L);
+ long start = counter.getStart();
+ for (int i = 0; i < 100; i++)
+ {
+ counter.registerEvent(i, start + i);
+ }
+ assertEquals(99 * 50, counter.getTotal()); // cf. Gauss
+ }
+
+ /**
+ * Test totals add up correctly even when messages are delivered
+ * out-of-order.
+ */
+ public void testTotalOutOfOrder()
+ {
+ StatisticsCounter counter = new StatisticsCounter("test", 1000L);
+ long start = counter.getStart();
+ assertEquals(0, counter.getTotal());
+ counter.registerEvent(10, start + 2500);
+ assertEquals(10, counter.getTotal());
+ counter.registerEvent(20, start + 1500);
+ assertEquals(30, counter.getTotal());
+ counter.registerEvent(10, start + 500);
+ assertEquals(40, counter.getTotal());
+ }
+
+ /**
+ * Test that the peak rate is reported correctly.
+ */
+ public void testPeak() throws Exception
+ {
+ StatisticsCounter counter = new StatisticsCounter("test", 1000L);
+ long start = counter.getStart();
+ assertEquals(0.0, counter.getPeak());
+ Thread.sleep(500);
+ counter.registerEvent(1000, start + 500);
+ Thread.sleep(1000);
+ assertEquals(1000.0, counter.getPeak());
+ counter.registerEvent(2000, start + 1500);
+ Thread.sleep(1000);
+ assertEquals(2000.0, counter.getPeak());
+ counter.registerEvent(1000, start + 2500);
+ Thread.sleep(1000);
+ assertEquals(2000.0, counter.getPeak());
+ }
+
+ /**
+ * Test that peak rate is reported correctly for out-of-order messages,
+ * and the total is also unaffected.
+ */
+ public void testPeakOutOfOrder() throws Exception
+ {
+ StatisticsCounter counter = new StatisticsCounter("test", 1000L);
+ long start = counter.getStart();
+ assertEquals(0.0, counter.getPeak());
+ counter.registerEvent(1000, start + 2500);
+ Thread.sleep(1500);
+ assertEquals(0.0, counter.getPeak());
+ counter.registerEvent(2000, start + 1500);
+ Thread.sleep(1000L);
+ assertEquals(0.0, counter.getPeak());
+ counter.registerEvent(1000, start + 500);
+ Thread.sleep(1500);
+ assertEquals(4000.0, counter.getPeak());
+ Thread.sleep(2000);
+ assertEquals(4000.0, counter.getPeak());
+ counter.registerEvent(1000, start + 500);
+ assertEquals(4000.0, counter.getPeak());
+ Thread.sleep(2000);
+ counter.registerEvent(1000);
+ assertEquals(4000.0, counter.getPeak());
+ assertEquals(6000, counter.getTotal());
+ }
+
+ /**
+ * Test the current rate is generated correctly.
+ */
+ public void testRate() throws Exception
+ {
+ StatisticsCounter counter = new StatisticsCounter("test", 1000L);
+ assertEquals(0.0, counter.getRate());
+ Thread.sleep(500);
+ counter.registerEvent(1000);
+ Thread.sleep(1000);
+ assertEquals(1000.0, counter.getRate());
+ counter.registerEvent(2000);
+ Thread.sleep(1000);
+ assertEquals(2000.0, counter.getRate());
+ counter.registerEvent(1000);
+ Thread.sleep(1000);
+ assertEquals(1000.0, counter.getRate());
+ Thread.sleep(1000);
+ assertEquals(0.0, counter.getRate());
+ }
+}
diff --git a/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
index 902b86f80b..a39799a6b6 100644
--- a/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
+++ b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
@@ -481,7 +481,7 @@ public class GenerateLogMessages
// Only check the text inside the braces '{}'
int typeIndexEnd = parametersString[index].indexOf("}", typeIndex);
String typeString = parametersString[index].substring(typeIndex, typeIndexEnd);
- if (typeString.contains("number"))
+ if (typeString.contains("number") || typeString.contains("choice"))
{
type = "Number";
}
diff --git a/qpid/java/build.xml b/qpid/java/build.xml
index 9031166d76..635e72bdd5 100644
--- a/qpid/java/build.xml
+++ b/qpid/java/build.xml
@@ -93,6 +93,10 @@
<fail if="failed" message="TEST SUITE FAILED"/>
</target>
+
+ <target name="report-module" description="generate junitreport for modules">
+ <iterate target="report-module"/>
+ </target>
<target name="jar" description="create module jars">
<iterate target="jar"/>
diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java
index c4edd9034f..88ee9ed2c5 100644
--- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java
+++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java
@@ -50,7 +50,7 @@ public class ConnectionSetup
final static String QUEUE_NAME = "example.MyQueue";
public static final String TOPIC_JNDI_NAME = "topic";
- final static String TOPIC_NAME = "example.hierarical.topic";
+ final static String TOPIC_NAME = "usa.news";
private Context _ctx;
diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java
index dd936e429f..ac3829d49e 100644
--- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java
+++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java
@@ -71,7 +71,7 @@ public class Publisher extends Client
public static void main(String[] args)
{
- String destination = args.length > 2 ? args[1] : null;
+ String destination = args.length > 2 ? args[1] : "usa.news";
int msgCount = args.length > 2 ? Integer.parseInt(args[2]) : 100;
diff --git a/qpid/java/client/src/main/java/client.bnd b/qpid/java/client/src/main/java/client.bnd
index 0ddd163d4f..d2bc4f8d50 100755
--- a/qpid/java/client/src/main/java/client.bnd
+++ b/qpid/java/client/src/main/java/client.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.9.0
+ver: 0.11.0
Bundle-SymbolicName: qpid-client
Bundle-Version: ${ver}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
index ee52cd50af..b31dd2bc91 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -105,6 +105,21 @@ public class AMQBrokerDetails implements BrokerDetails
if (host == null)
{
host = "";
+
+ String auth = connection.getAuthority();
+ if (auth != null)
+ {
+ // contains both host & port myhost:5672
+ if (auth.contains(":"))
+ {
+ host = auth.substring(0,auth.indexOf(":"));
+ }
+ else
+ {
+ host = auth;
+ }
+ }
+
}
setHost(host);
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 b0bd8f8e97..891819c227 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
@@ -69,6 +69,12 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
org.apache.qpid.transport.Connection _qpidConnection;
private ConnectionException exception = null;
+ static
+ {
+ // Register any configured SASL client factories.
+ org.apache.qpid.client.security.DynamicSaslRegistrar.registerSaslProviders();
+ }
+
//--- constructor
public AMQConnectionDelegate_0_10(AMQConnection conn)
{
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 1f940b62f0..5c2949960c 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
@@ -1043,7 +1043,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
throws JMSException
{
checkNotClosed();
- AMQTopic origTopic = checkValidTopic(topic, true);
+ Topic origTopic = checkValidTopic(topic, true);
AMQTopic dest = AMQTopic.createDurableTopic(origTopic, name, _connection);
String messageSelector = ((selector == null) || (selector.trim().length() == 0)) ? null : selector;
@@ -1307,8 +1307,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public QueueReceiver createQueueReceiver(Destination destination) throws JMSException
{
checkValidDestination(destination);
- AMQQueue dest = (AMQQueue) destination;
- C consumer = (C) createConsumer(destination);
+ Queue dest = validateQueue(destination);
+ C consumer = (C) createConsumer(dest);
return new QueueReceiverAdaptor(dest, consumer);
}
@@ -1326,8 +1326,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public QueueReceiver createQueueReceiver(Destination destination, String messageSelector) throws JMSException
{
checkValidDestination(destination);
- AMQQueue dest = (AMQQueue) destination;
- C consumer = (C) createConsumer(destination, messageSelector);
+ Queue dest = validateQueue(destination);
+ C consumer = (C) createConsumer(dest, messageSelector);
return new QueueReceiverAdaptor(dest, consumer);
}
@@ -1344,7 +1344,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public QueueReceiver createReceiver(Queue queue) throws JMSException
{
checkNotClosed();
- AMQQueue dest = (AMQQueue) queue;
+ Queue dest = validateQueue(queue);
C consumer = (C) createConsumer(dest);
return new QueueReceiverAdaptor(dest, consumer);
@@ -1363,11 +1363,23 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException
{
checkNotClosed();
- AMQQueue dest = (AMQQueue) queue;
+ Queue dest = validateQueue(queue);
C consumer = (C) createConsumer(dest, messageSelector);
return new QueueReceiverAdaptor(dest, consumer);
}
+
+ private Queue validateQueue(Destination dest) throws InvalidDestinationException
+ {
+ if (dest instanceof AMQDestination && dest instanceof javax.jms.Queue)
+ {
+ return (Queue)dest;
+ }
+ else
+ {
+ throw new InvalidDestinationException("The destination object used is not from this provider or of type javax.jms.Queue");
+ }
+ }
public QueueSender createSender(Queue queue) throws JMSException
{
@@ -1408,7 +1420,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public TopicSubscriber createSubscriber(Topic topic) throws JMSException
{
checkNotClosed();
- AMQTopic dest = checkValidTopic(topic);
+ Topic dest = checkValidTopic(topic);
// AMQTopic dest = new AMQTopic(topic.getTopicName());
return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest));
@@ -1428,7 +1440,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException
{
checkNotClosed();
- AMQTopic dest = checkValidTopic(topic);
+ Topic dest = checkValidTopic(topic);
// AMQTopic dest = new AMQTopic(topic.getTopicName());
return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest, messageSelector, noLocal));
@@ -2395,7 +2407,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/*
* I could have combined the last 3 methods, but this way it improves readability
*/
- protected AMQTopic checkValidTopic(Topic topic, boolean durable) throws JMSException
+ protected Topic checkValidTopic(Topic topic, boolean durable) throws JMSException
{
if (topic == null)
{
@@ -2414,17 +2426,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
("Cannot create a durable subscription with a temporary topic: " + topic);
}
- if (!(topic instanceof AMQTopic))
+ if (!(topic instanceof AMQDestination && topic instanceof javax.jms.Topic))
{
throw new javax.jms.InvalidDestinationException(
"Cannot create a subscription on topic created for another JMS Provider, class of topic provided is: "
+ topic.getClass().getName());
}
- return (AMQTopic) topic;
+ return topic;
}
- protected AMQTopic checkValidTopic(Topic topic) throws JMSException
+ protected Topic checkValidTopic(Topic topic) throws JMSException
{
return checkValidTopic(topic, false);
}
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 517a7a5ce8..3f84716df7 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
@@ -47,6 +47,8 @@ import org.apache.qpid.client.message.AMQMessageDelegateFactory;
import org.apache.qpid.client.message.FieldTableSupport;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import org.apache.qpid.client.message.UnprocessedMessage_0_10;
+import org.apache.qpid.client.messaging.address.Link;
+import org.apache.qpid.client.messaging.address.Link.Reliability;
import org.apache.qpid.client.messaging.address.Node.ExchangeNode;
import org.apache.qpid.client.messaging.address.Node.QueueNode;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
@@ -56,6 +58,7 @@ import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.transport.ExchangeBoundResult;
import org.apache.qpid.transport.ExchangeQueryResult;
+import org.apache.qpid.transport.ExecutionErrorCode;
import org.apache.qpid.transport.ExecutionException;
import org.apache.qpid.transport.MessageAcceptMode;
import org.apache.qpid.transport.MessageAcquireMode;
@@ -600,10 +603,16 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
(Map<? extends String, ? extends Object>) consumer.getDestination().getLink().getSubscription().getArgs());
}
+ boolean acceptModeNone = getAcknowledgeMode() == NO_ACKNOWLEDGE;
+
+ if (consumer.getDestination().getLink() != null)
+ {
+ acceptModeNone = consumer.getDestination().getLink().getReliability() == Link.Reliability.UNRELIABLE;
+ }
getQpidSession().messageSubscribe
(queueName.toString(), String.valueOf(tag),
- getAcknowledgeMode() == NO_ACKNOWLEDGE ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT,
+ acceptModeNone ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT,
preAcquire ? MessageAcquireMode.PRE_ACQUIRED : MessageAcquireMode.NOT_ACQUIRED, null, 0, arguments,
consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
}
@@ -1068,22 +1077,37 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
return match;
}
- public boolean isQueueExist(AMQDestination dest,QueueNode node,boolean assertNode)
+ public boolean isQueueExist(AMQDestination dest,QueueNode node,boolean assertNode) throws AMQException
{
boolean match = true;
- QueueQueryResult result = getQpidSession().queueQuery(dest.getAddressName(), Option.NONE).get();
- match = dest.getAddressName().equals(result.getQueue());
-
- if (match && assertNode)
+ try
{
- match = (result.getDurable() == node.isDurable()) &&
- (result.getAutoDelete() == node.isAutoDelete()) &&
- (result.getExclusive() == node.isExclusive()) &&
- (matchProps(result.getArguments(),node.getDeclareArgs()));
+ QueueQueryResult result = getQpidSession().queueQuery(dest.getAddressName(), Option.NONE).get();
+ match = dest.getAddressName().equals(result.getQueue());
+
+ if (match && assertNode)
+ {
+ match = (result.getDurable() == node.isDurable()) &&
+ (result.getAutoDelete() == node.isAutoDelete()) &&
+ (result.getExclusive() == node.isExclusive()) &&
+ (matchProps(result.getArguments(),node.getDeclareArgs()));
+ }
+ else if (match)
+ {
+ // should I use the queried details to update the local data structure.
+ }
}
- else if (match)
+ catch(SessionException e)
{
- // should I use the queried details to update the local data structure.
+ if (e.getException().getErrorCode() == ExecutionErrorCode.RESOURCE_DELETED)
+ {
+ match = false;
+ }
+ else
+ {
+ throw new AMQException(AMQConstant.getConstant(e.getException().getErrorCode().getValue()),
+ "Error querying queue",e);
+ }
}
return match;
@@ -1149,6 +1173,22 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
int type = resolveAddressType(dest);
+ if (type == AMQDestination.QUEUE_TYPE &&
+ dest.getLink().getReliability() == Reliability.UNSPECIFIED)
+ {
+ dest.getLink().setReliability(Reliability.AT_LEAST_ONCE);
+ }
+ else if (type == AMQDestination.TOPIC_TYPE &&
+ dest.getLink().getReliability() == Reliability.UNSPECIFIED)
+ {
+ dest.getLink().setReliability(Reliability.UNRELIABLE);
+ }
+ else if (type == AMQDestination.TOPIC_TYPE &&
+ dest.getLink().getReliability() == Reliability.AT_LEAST_ONCE)
+ {
+ throw new AMQException("AT-LEAST-ONCE is not yet supported for Topics");
+ }
+
switch (type)
{
case AMQDestination.QUEUE_TYPE:
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
index 6217cb534a..c573da9def 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
@@ -22,6 +22,7 @@ package org.apache.qpid.client;
import java.net.URISyntaxException;
+import javax.jms.InvalidDestinationException;
import javax.jms.JMSException;
import javax.jms.Topic;
@@ -95,39 +96,47 @@ public class AMQTopic extends AMQDestination implements Topic
super(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, isDurable,bindingKeys);
}
- public static AMQTopic createDurableTopic(AMQTopic topic, String subscriptionName, AMQConnection connection)
+ public static AMQTopic createDurableTopic(Topic topic, String subscriptionName, AMQConnection connection)
throws JMSException
{
- if (topic.getDestSyntax() == DestSyntax.ADDR)
+ if (topic instanceof AMQDestination && topic instanceof javax.jms.Topic)
{
- try
+ AMQDestination qpidTopic = (AMQDestination)topic;
+ if (qpidTopic.getDestSyntax() == DestSyntax.ADDR)
{
- AMQTopic t = new AMQTopic(topic.getAddress());
- AMQShortString queueName = getDurableTopicQueueName(subscriptionName, connection);
- // link is never null if dest was created using an address string.
- t.getLink().setName(queueName.asString());
- t.getSourceNode().setAutoDelete(false);
- t.getSourceNode().setDurable(true);
-
- // The legacy fields are also populated just in case.
- t.setQueueName(queueName);
- t.setAutoDelete(false);
- t.setDurable(true);
- return t;
+ try
+ {
+ AMQTopic t = new AMQTopic(qpidTopic.getAddress());
+ AMQShortString queueName = getDurableTopicQueueName(subscriptionName, connection);
+ // link is never null if dest was created using an address string.
+ t.getLink().setName(queueName.asString());
+ t.getSourceNode().setAutoDelete(false);
+ t.getSourceNode().setDurable(true);
+
+ // The legacy fields are also populated just in case.
+ t.setQueueName(queueName);
+ t.setAutoDelete(false);
+ t.setDurable(true);
+ return t;
+ }
+ catch(Exception e)
+ {
+ JMSException ex = new JMSException("Error creating durable topic");
+ ex.initCause(e);
+ ex.setLinkedException(e);
+ throw ex;
+ }
}
- catch(Exception e)
+ else
{
- JMSException ex = new JMSException("Error creating durable topic");
- ex.initCause(e);
- ex.setLinkedException(e);
- throw ex;
+ return new AMQTopic(qpidTopic.getExchangeName(), qpidTopic.getRoutingKey(), false,
+ getDurableTopicQueueName(subscriptionName, connection),
+ true);
}
}
else
{
- return new AMQTopic(topic.getExchangeName(), topic.getRoutingKey(), false,
- getDurableTopicQueueName(subscriptionName, connection),
- true);
+ throw new InvalidDestinationException("The destination object used is not from this provider or of type javax.jms.Topic");
}
}
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 0a78403268..5d32863f2f 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
@@ -571,6 +571,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
if (!_session.isClosed() || _session.isClosing())
{
sendCancel();
+ cleanupQueue();
}
}
catch (AMQException e)
@@ -608,6 +609,8 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
}
abstract void sendCancel() throws AMQException, FailoverException;
+
+ abstract void cleanupQueue() throws AMQException, FailoverException;
/**
* Called when you need to invalidate a consumer. Used for example when failover has occurred and the client has
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
index b5f3501e5a..964c238946 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
@@ -19,8 +19,11 @@ package org.apache.qpid.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.qpid.client.AMQDestination.AddressOption;
import org.apache.qpid.client.AMQDestination.DestSyntax;
+import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.message.*;
+import org.apache.qpid.client.messaging.address.Node.QueueNode;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
@@ -509,4 +512,18 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
return _exclusive;
}
}
+
+ void cleanupQueue() throws AMQException, FailoverException
+ {
+ AMQDestination dest = this.getDestination();
+ if (dest != null && dest.getDestSyntax() == AMQDestination.DestSyntax.ADDR)
+ {
+ if (dest.getDelete() == AddressOption.ALWAYS ||
+ dest.getDelete() == AddressOption.RECEIVER )
+ {
+ ((AMQSession_0_10) getSession()).getQpidSession().queueDelete(
+ this.getDestination().getQueueName());
+ }
+ }
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
index cdbf57769d..00acd5e866 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
@@ -88,4 +88,8 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
return receive();
}
+ void cleanupQueue() throws AMQException, FailoverException
+ {
+
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
index 53c0457120..36f2dfb66f 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
@@ -19,6 +19,7 @@ package org.apache.qpid.client;
import static org.apache.qpid.transport.Option.NONE;
import static org.apache.qpid.transport.Option.SYNC;
+import static org.apache.qpid.transport.Option.UNRELIABLE;
import java.nio.ByteBuffer;
import java.util.HashMap;
@@ -30,9 +31,12 @@ import javax.jms.JMSException;
import javax.jms.Message;
import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQDestination.AddressOption;
import org.apache.qpid.client.AMQDestination.DestSyntax;
import org.apache.qpid.client.message.AMQMessageDelegate_0_10;
import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.messaging.address.Link.Reliability;
+import org.apache.qpid.client.messaging.address.Node.QueueNode;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.transport.Header;
@@ -210,6 +214,9 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
deliveryMode == DeliveryMode.PERSISTENT)
);
+ boolean unreliable = (destination.getDestSyntax() == DestSyntax.ADDR) &&
+ (destination.getLink().getReliability() == Reliability.UNRELIABLE);
+
org.apache.mina.common.ByteBuffer data = message.getData();
ByteBuffer buffer = data == null ? ByteBuffer.allocate(0) : data.buf().slice();
@@ -217,7 +224,7 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
MessageAcceptMode.NONE,
MessageAcquireMode.PRE_ACQUIRED,
new Header(deliveryProp, messageProps),
- buffer, sync ? SYNC : NONE);
+ buffer, sync ? SYNC : NONE, unreliable ? UNRELIABLE : NONE);
if (sync)
{
ssn.sync();
@@ -239,5 +246,21 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
return _session.isQueueBound(destination);
}
+
+ @Override
+ public void close()
+ {
+ super.close();
+ AMQDestination dest = _destination;
+ if (dest != null && dest.getDestSyntax() == AMQDestination.DestSyntax.ADDR)
+ {
+ if (dest.getDelete() == AddressOption.ALWAYS ||
+ dest.getDelete() == AddressOption.SENDER )
+ {
+ ((AMQSession_0_10) getSession()).getQpidSession().queueDelete(
+ _destination.getQueueName());
+ }
+ }
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java
index 27783bcacf..295c6a4091 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java
@@ -50,25 +50,25 @@ public class QueueSenderAdapter implements QueueSender
public void send(Message msg) throws JMSException
{
- checkPreConditions();
+ checkQueuePreConditions(_queue);
_delegate.send(msg);
}
public void send(Queue queue, Message msg) throws JMSException
{
- checkPreConditions(queue);
+ checkQueuePreConditions(queue);
_delegate.send(queue, msg);
}
public void publish(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
{
- checkPreConditions();
+ checkQueuePreConditions(_queue);
_delegate.send(msg, deliveryMode, priority, timeToLive);
}
public void send(Queue queue, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
{
- checkPreConditions(queue);
+ checkQueuePreConditions(queue);
_delegate.send(queue, msg, deliveryMode, priority, timeToLive);
}
@@ -122,19 +122,19 @@ public class QueueSenderAdapter implements QueueSender
public void send(Destination dest, Message msg) throws JMSException
{
- checkPreConditions((Queue) dest);
+ checkQueuePreConditions((Queue) dest);
_delegate.send(dest, msg);
}
public void send(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
{
- checkPreConditions();
+ checkQueuePreConditions(_queue);
_delegate.send(msg, deliveryMode, priority, timeToLive);
}
public void send(Destination dest, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
{
- checkPreConditions((Queue) dest);
+ checkQueuePreConditions((Queue) dest);
_delegate.send(dest, msg, deliveryMode, priority, timeToLive);
}
@@ -170,11 +170,6 @@ public class QueueSenderAdapter implements QueueSender
private void checkPreConditions() throws JMSException
{
- checkPreConditions(_queue);
- }
-
- private void checkPreConditions(Queue queue) throws JMSException
- {
if (closed)
{
throw new javax.jms.IllegalStateException("Publisher is closed");
@@ -186,39 +181,43 @@ public class QueueSenderAdapter implements QueueSender
{
throw new javax.jms.IllegalStateException("Invalid Session");
}
+ }
- if (queue == null)
- {
- throw new UnsupportedOperationException("Queue is null.");
- }
-
- if (!(queue instanceof AMQDestination))
- {
- throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue");
- }
-
- AMQDestination destination = (AMQDestination) queue;
- if (!destination.isCheckedForQueueBinding() && checkQueueBeforePublish())
- {
-
- if (_delegate.getSession().isStrictAMQP())
- {
- _delegate._logger.warn("AMQP does not support destination validation before publish, ");
- destination.setCheckedForQueueBinding(true);
- }
- else
- {
- if (_delegate.isBound(destination))
- {
- destination.setCheckedForQueueBinding(true);
- }
- else
- {
- throw new InvalidDestinationException("Queue: " + queue
- + " is not a valid destination (no bindings on server");
- }
- }
- }
+ private void checkQueuePreConditions(Queue queue) throws JMSException
+ {
+ checkPreConditions() ;
+
+ if (queue == null)
+ {
+ throw new UnsupportedOperationException("Queue is null.");
+ }
+
+ if (!(queue instanceof AMQDestination))
+ {
+ throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue");
+ }
+
+ AMQDestination destination = (AMQDestination) queue;
+ if (!destination.isCheckedForQueueBinding() && checkQueueBeforePublish())
+ {
+ if (_delegate.getSession().isStrictAMQP())
+ {
+ _delegate._logger.warn("AMQP does not support destination validation before publish, ");
+ destination.setCheckedForQueueBinding(true);
+ }
+ else
+ {
+ if (_delegate.isBound(destination))
+ {
+ destination.setCheckedForQueueBinding(true);
+ }
+ else
+ {
+ throw new InvalidDestinationException("Queue: " + queue
+ + " is not a valid destination (no bindings on server");
+ }
+ }
+ }
}
private boolean checkQueueBeforePublish()
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
index 92e61984d2..fb7b191656 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
@@ -22,10 +22,12 @@
package org.apache.qpid.client.message;
import java.lang.ref.SoftReference;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -670,7 +672,19 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate
public Enumeration getPropertyNames() throws JMSException
{
- return java.util.Collections.enumeration(getApplicationHeaders().keySet());
+ List<String> props = new ArrayList<String>();
+ Map<String, Object> propertyMap = getApplicationHeaders();
+ for (String prop: getApplicationHeaders().keySet())
+ {
+ Object value = propertyMap.get(prop);
+ if (value instanceof Boolean || value instanceof Number
+ || value instanceof String)
+ {
+ props.add(prop);
+ }
+ }
+
+ return java.util.Collections.enumeration(props);
}
public void setBooleanProperty(String propertyName, boolean b) throws JMSException
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java
index 6e22292ee0..58f108f1a4 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessage.java
@@ -23,6 +23,7 @@ package org.apache.qpid.client.message;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import javax.jms.JMSException;
import javax.jms.MessageFormatException;
@@ -65,7 +66,7 @@ public class AMQPEncodedMapMessage extends JMSMapMessage
if ((value instanceof Boolean) || (value instanceof Byte) || (value instanceof Short) || (value instanceof Integer)
|| (value instanceof Long) || (value instanceof Character) || (value instanceof Float)
|| (value instanceof Double) || (value instanceof String) || (value instanceof byte[])
- || (value instanceof List) || (value instanceof Map) || (value == null))
+ || (value instanceof List) || (value instanceof Map) || (value instanceof UUID) || (value == null))
{
_map.put(propName, value);
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java b/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
index 00503cc650..e454a8eee4 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/AddressHelper.java
@@ -27,6 +27,7 @@ import java.util.Map;
import org.apache.qpid.client.AMQDestination;
import org.apache.qpid.client.AMQDestination.Binding;
+import org.apache.qpid.client.messaging.address.Link.Reliability;
import org.apache.qpid.client.messaging.address.Link.Subscription;
import org.apache.qpid.client.messaging.address.Node.ExchangeNode;
import org.apache.qpid.client.messaging.address.Node.QueueNode;
@@ -262,7 +263,7 @@ public class AddressHelper
}
}
- public Link getLink()
+ public Link getLink() throws Exception
{
Link link = new Link();
link.setSubscription(new Subscription());
@@ -272,6 +273,25 @@ public class AddressHelper
: linkProps.getBoolean(DURABLE));
link.setName(linkProps.getString(NAME));
+ String reliability = linkProps.getString(RELIABILITY);
+ if ( reliability != null)
+ {
+ if (reliability.equalsIgnoreCase("unreliable"))
+ {
+ link.setReliability(Reliability.UNRELIABLE);
+ }
+ else if (reliability.equalsIgnoreCase("at-least-once"))
+ {
+ link.setReliability(Reliability.AT_LEAST_ONCE);
+ }
+ else
+ {
+ throw new Exception("The reliability mode '" +
+ reliability + "' is not yet supported");
+ }
+
+ }
+
if (((Map) address.getOptions().get(LINK)).get(CAPACITY) instanceof Map)
{
MapAccessor capacityProps = new MapAccessor(
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java b/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
index a7d19d1bd5..5f97d625b4 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/messaging/address/Link.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.client.messaging.address;
+import static org.apache.qpid.client.messaging.address.Link.Reliability.UNSPECIFIED;
+
import java.util.HashMap;
import java.util.Map;
@@ -29,6 +31,8 @@ public class Link
{
public enum FilterType { SQL92, XQUERY, SUBJECT }
+ public enum Reliability { UNRELIABLE, AT_MOST_ONCE, AT_LEAST_ONCE, EXACTLY_ONCE, UNSPECIFIED }
+
protected String name;
protected String _filter;
protected FilterType _filterType = FilterType.SUBJECT;
@@ -38,7 +42,18 @@ public class Link
protected int _producerCapacity = 0;
protected Node node;
protected Subscription subscription;
+ protected Reliability reliability = UNSPECIFIED;
+ public Reliability getReliability()
+ {
+ return reliability;
+ }
+
+ public void setReliability(Reliability reliability)
+ {
+ this.reliability = reliability;
+ }
+
public Node getNode()
{
return node;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties
index 1bff43142b..b903208927 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties
@@ -18,3 +18,4 @@
#
AMQPLAIN=org.apache.qpid.client.security.amqplain.AmqPlainSaslClientFactory
CRAM-MD5-HASHED=org.apache.qpid.client.security.crammd5hashed.CRAMMD5HashedSaslClientFactory
+ANONYMOUS=org.apache.qpid.client.security.anonymous.AnonymousSaslClientFactory
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java
new file mode 100644
index 0000000000..0f56b2ef6c
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClient.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.security.anonymous;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+public class AnonymousSaslClient implements SaslClient
+{
+ public String getMechanismName() {
+ return "ANONYMOUS";
+ }
+ public boolean hasInitialResponse() {
+ return true;
+ }
+ public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
+ return new byte[0];
+ }
+ public boolean isComplete() {
+ return true;
+ }
+ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
+ {
+ throw new IllegalStateException("No security layer supported");
+ }
+ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
+ {
+ throw new IllegalStateException("No security layer supported");
+ }
+ public Object getNegotiatedProperty(String propName) {
+ return null;
+ }
+ public void dispose() throws SaslException {}
+}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java
new file mode 100644
index 0000000000..de698f87c6
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/anonymous/AnonymousSaslClientFactory.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.security.anonymous;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+import javax.security.auth.callback.CallbackHandler;
+
+public class AnonymousSaslClientFactory implements SaslClientFactory
+{
+ public SaslClient createSaslClient(String[] mechanisms, String authId,
+ String protocol, String server,
+ Map props, CallbackHandler cbh) throws SaslException
+ {
+ if (Arrays.asList(mechanisms).contains("ANONYMOUS")) {
+ return new AnonymousSaslClient();
+ } else {
+ return null;
+ }
+ }
+ public String[] getMechanismNames(Map props)
+ {
+ if (props == null || props.isEmpty()) {
+ return new String[]{"ANONYMOUS"};
+ } else {
+ return new String[0];
+ }
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index 2be3720c20..2c5fa0112e 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -549,6 +549,37 @@ public class ConnectionURLTest extends TestCase
assertTrue("String representation should contain options and values", url.toString().contains("maxprefetch='12345'"));
}
+ public void testHostNamesWithUnderScore() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@clientid/test?brokerlist='tcp://under_score:6672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("under_score"));
+ assertTrue(service.getPort() == 6672);
+
+ url = "amqp://guest:guest@clientid/test?brokerlist='tcp://under_score'";
+
+ connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+ service = connectionurl.getBrokerDetails(0);
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("under_score"));
+ assertTrue(service.getPort() == 5672);
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(ConnectionURLTest.class);
diff --git a/qpid/java/common.xml b/qpid/java/common.xml
index 066859b29f..a8d9c0dea4 100644
--- a/qpid/java/common.xml
+++ b/qpid/java/common.xml
@@ -23,7 +23,7 @@
<dirname property="project.root" file="${ant.file.common}"/>
<property name="project.name" value="qpid"/>
- <property name="project.version" value="0.9"/>
+ <property name="project.version" value="0.11"/>
<property name="project.namever" value="${project.name}-${project.version}"/>
<property name="resources" location="${project.root}/resources"/>
diff --git a/qpid/java/common/src/main/java/common.bnd b/qpid/java/common/src/main/java/common.bnd
index ef56ecec9e..89c397f400 100755
--- a/qpid/java/common/src/main/java/common.bnd
+++ b/qpid/java/common/src/main/java/common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.9.0
+ver: 0.11.0
Bundle-SymbolicName: qpid-common
Bundle-Version: ${ver}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index e5e10c0e07..dc32569ee8 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -28,6 +28,7 @@ import static org.apache.qpid.transport.Connection.State.OPENING;
import static org.apache.qpid.transport.Connection.State.RESUMING;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -695,4 +696,8 @@ public class Connection extends ConnectionInvoker
return connectionLost.get();
}
+ protected Collection<Session> getChannels()
+ {
+ return channels.values();
+ }
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
index 214d4534c1..d961507382 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
@@ -422,7 +422,10 @@ public class Session extends SessionInvoker
{
return;
}
- sessionCompleted(copy, options);
+ if (copy.size() > 0)
+ {
+ sessionCompleted(copy, options);
+ }
}
}
@@ -661,7 +664,12 @@ public class Session extends SessionInvoker
{
sessionCommandPoint(0, 0);
}
- if ((!closing && !transacted && m instanceof MessageTransfer) || m.hasCompletionListener())
+
+ boolean replayTransfer = !closing && !transacted &&
+ m instanceof MessageTransfer &&
+ ! m.isUnreliable();
+
+ if ((replayTransfer) || m.hasCompletionListener())
{
commands[mod(next, commands.length)] = m;
commandBytes += m.getBodySize();
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
index 908d14a307..0ccfcfcb70 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
@@ -63,6 +63,7 @@ abstract class AbstractEncoder implements Encoder
ENCODINGS.put(Double.class, Type.DOUBLE);
ENCODINGS.put(Character.class, Type.CHAR);
ENCODINGS.put(byte[].class, Type.VBIN32);
+ ENCODINGS.put(UUID.class, Type.UUID);
}
private final Map<String,byte[]> str8cache = new LinkedHashMap<String,byte[]>()
diff --git a/qpid/java/management/common/src/main/java/management-common.bnd b/qpid/java/management/common/src/main/java/management-common.bnd
index cb28d309a6..66eb9f156b 100644
--- a/qpid/java/management/common/src/main/java/management-common.bnd
+++ b/qpid/java/management/common/src/main/java/management-common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.9.0
+ver: 0.11.0
Bundle-SymbolicName: qpid-management-common
Bundle-Version: ${ver}
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
index c0e7293611..b48ad3f856 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
@@ -36,8 +36,8 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParame
* The ManagedBroker is the management interface to expose management
* features of the Broker.
*
- * @author Bhupendra Bhardwaj
- * @version 0.1
+ * @version Qpid JMX API 2.1
+ * @since Qpid JMX API 1.3
*/
public interface ManagedBroker
{
@@ -131,4 +131,118 @@ public interface ManagedBroker
impact= MBeanOperationInfo.ACTION)
void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName)
throws IOException, JMException, MBeanException;
+
+ /**
+ * Resets all message and data statistics for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanOperation(name="resetStatistics",
+ description="Resets all message and data statistics for the virtual host",
+ impact= MBeanOperationInfo.ACTION)
+ void resetStatistics() throws Exception;
+
+ /**
+ * Peak rate of messages delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageDeliveryRate", description=TYPE + " Peak Message Delivery Rate")
+ double getPeakMessageDeliveryRate();
+
+ /**
+ * Peak rate of bytes delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataDeliveryRate", description=TYPE + " Peak Data Delivery Rate")
+ double getPeakDataDeliveryRate();
+
+ /**
+ * Rate of messages delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageDeliveryRate", description=TYPE + " Message Delivery Rate")
+ double getMessageDeliveryRate();
+
+ /**
+ * Rate of bytes delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataDeliveryRate", description=TYPE + " Data Delivery Rate")
+ double getDataDeliveryRate();
+
+ /**
+ * Total count of messages delivered for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesDelivered", description=TYPE + " Total Messages Delivered")
+ long getTotalMessagesDelivered();
+
+ /**
+ * Total count of bytes for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataDelivered", description=TYPE + " Total Data Delivered")
+ long getTotalDataDelivered();
+
+ /**
+ * Peak rate of messages received per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageReceiptRate", description=TYPE + " Peak Message Receipt Rate")
+ double getPeakMessageReceiptRate();
+
+ /**
+ * Peak rate of bytes received per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataReceiptRate", description=TYPE + " Peak Data Receipt Rate")
+ double getPeakDataReceiptRate();
+
+ /**
+ * Rate of messages received per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageReceiptRate", description=TYPE + " Message Receipt Rate")
+ double getMessageReceiptRate();
+
+ /**
+ * Rate of bytes received per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataReceiptRate", description=TYPE + " Data Receipt Rate")
+ double getDataReceiptRate();
+
+ /**
+ * Total count of messages received for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesReceived", description=TYPE + " Total Messages Received")
+ long getTotalMessagesReceived();
+
+ /**
+ * Total count of bytes received for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataReceived", description=TYPE + " Total Data Received")
+ long getTotalDataReceived();
+
+ /**
+ * Is statistics collection enabled for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="StatisticsEnabled", description=TYPE + " Statistics Enabled")
+ boolean isStatisticsEnabled();
}
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
index d6b79d1dde..6ef0fd5b19 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
@@ -37,8 +37,9 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParame
/**
* The management interface exposed to allow management of Connections.
- * @author Bhupendra Bhardwaj
- * @version 0.1
+ *
+ * @version Qpid JMX API 2.1
+ * @since Qpid JMX API 1.3
*/
public interface ManagedConnection
{
@@ -145,4 +146,120 @@ public interface ManagedConnection
description="Closes this connection and all related channels",
impact= MBeanOperationInfo.ACTION)
void closeConnection() throws Exception;
+
+ /**
+ * Resets message and data statistics for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanOperation(name="resetStatistics",
+ description="Resets message and data statistics for this connection",
+ impact= MBeanOperationInfo.ACTION)
+ void resetStatistics() throws Exception;
+
+ /**
+ * Peak rate of messages delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageDeliveryRate", description=TYPE + " Peak Message Delivery Rate")
+ double getPeakMessageDeliveryRate();
+
+ /**
+ * Peak rate of bytes delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataDeliveryRate", description=TYPE + " Peak Data Delivery Rate")
+ double getPeakDataDeliveryRate();
+
+ /**
+ * Rate of messages delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageDeliveryRate", description=TYPE + " Message Delivery Rate")
+ double getMessageDeliveryRate();
+
+ /**
+ * Rate of bytes delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataDeliveryRate", description=TYPE + " Data Delivery Rate")
+ double getDataDeliveryRate();
+
+ /**
+ * Total count of messages delivered for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesDelivered", description=TYPE + " Total Messages Delivered")
+ long getTotalMessagesDelivered();
+
+ /**
+ * Total count of bytes for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataDelivered", description=TYPE + " Total Data Delivered")
+ long getTotalDataDelivered();
+
+ /**
+ * Peak rate of messages received per second for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageReceiptRate", description=TYPE + " Peak Message Receipt Rate")
+ double getPeakMessageReceiptRate();
+
+ /**
+ * Peak rate of bytes received per second for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataReceiptRate", description=TYPE + " Peak Data Receipt Rate")
+ double getPeakDataReceiptRate();
+
+ /**
+ * Rate of messages received per second for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageReceiptRate", description=TYPE + " Message Receipt Rate")
+ double getMessageReceiptRate();
+
+ /**
+ * Rate of bytes received per second for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataReceiptRate", description=TYPE + " Data Receipt Rate")
+ double getDataReceiptRate();
+
+ /**
+ * Total count of messages received for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesReceived", description=TYPE + " Total Messages Received")
+ long getTotalMessagesReceived();
+
+ /**
+ * Total count of bytes received for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataReceived", description=TYPE + " Total Data Received")
+ long getTotalDataReceived();
+
+ /**
+ * Is statistics collection enabled for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="StatisticsEnabled", description=TYPE + " Statistics Enabled")
+ boolean isStatisticsEnabled();
+
+ void setStatisticsEnabled(boolean enabled);
}
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 618403fdca..abee6a745e 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
@@ -22,10 +22,15 @@ package org.apache.qpid.management.common.mbeans;
import java.io.IOException;
+import javax.management.MBeanOperationInfo;
+
import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
/**
* Interface for the ServerInformation MBean
+ *
+ * @version Qpid JMX API 2.1
* @since Qpid JMX API 1.3
*/
public interface ServerInformation
@@ -42,7 +47,7 @@ public interface ServerInformation
* Qpid JMX API 1.1 can be assumed.
*/
int QPID_JMX_API_MAJOR_VERSION = 2;
- int QPID_JMX_API_MINOR_VERSION = 0;
+ int QPID_JMX_API_MINOR_VERSION = 1;
/**
@@ -80,4 +85,118 @@ public interface ServerInformation
@MBeanAttribute(name="ProductVersion",
description = "The product version string")
String getProductVersion() throws IOException;
+
+ /**
+ * Resets all message and data statistics for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanOperation(name="resetStatistics",
+ description="Resets all message and data statistics for the broker",
+ impact= MBeanOperationInfo.ACTION)
+ void resetStatistics() throws Exception;
+
+ /**
+ * Peak rate of messages delivered per second for the virtual host.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageDeliveryRate", description=TYPE + " Peak Message Delivery Rate")
+ double getPeakMessageDeliveryRate();
+
+ /**
+ * Peak rate of bytes delivered per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataDeliveryRate", description=TYPE + " Peak Data Delivery Rate")
+ double getPeakDataDeliveryRate();
+
+ /**
+ * Rate of messages delivered per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageDeliveryRate", description=TYPE + " Message Delivery Rate")
+ double getMessageDeliveryRate();
+
+ /**
+ * Rate of bytes delivered per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataDeliveryRate", description=TYPE + " Data Delivery Rate")
+ double getDataDeliveryRate();
+
+ /**
+ * Total count of messages delivered for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesDelivered", description=TYPE + " Total Messages Delivered")
+ long getTotalMessagesDelivered();
+
+ /**
+ * Total count of bytes for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataDelivered", description=TYPE + " Total Data Delivered")
+ long getTotalDataDelivered();
+
+ /**
+ * Peak rate of messages received per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakMessageReceiptRate", description=TYPE + " Peak Message Receipt Rate")
+ double getPeakMessageReceiptRate();
+
+ /**
+ * Peak rate of bytes received per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="PeakDataReceiptRate", description=TYPE + " Peak Data Receipt Rate")
+ double getPeakDataReceiptRate();
+
+ /**
+ * Rate of messages received per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="MessageReceiptRate", description=TYPE + " Message Receipt Rate")
+ double getMessageReceiptRate();
+
+ /**
+ * Rate of bytes received per second for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="DataReceiptRate", description=TYPE + " Data Receipt Rate")
+ double getDataReceiptRate();
+
+ /**
+ * Total count of messages received for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalMessagesReceived", description=TYPE + " Total Messages Received")
+ long getTotalMessagesReceived();
+
+ /**
+ * Total count of bytes received for the broker.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="TotalDataReceived", description=TYPE + " Total Data Received")
+ long getTotalDataReceived();
+
+ /**
+ * Is statistics collection enabled for this connection.
+ *
+ * @since Qpid JMX API 2.1
+ */
+ @MBeanAttribute(name="StatisticsEnabled", description=TYPE + " Statistics Enabled")
+ boolean isStatisticsEnabled();
}
diff --git a/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF b/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF
index 124fe1e767..2164c5d326 100644
--- a/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF
+++ b/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: Qpid JMX Management Console Plug-in
Bundle-SymbolicName: org.apache.qpid.management.ui; singleton:=true
-Bundle-Version: 0.9.0
+Bundle-Version: 0.11.0
Bundle-Activator: org.apache.qpid.management.ui.Activator
Bundle-Vendor: Apache Software Foundation
Bundle-Localization: plugin
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 20cfec3758..8a855a6b3c 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
@@ -47,7 +47,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 = 2;
- public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 0;
+ public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 1;
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/jmx/JMXManagedObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
index 3561e16098..a8fb864cf6 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
@@ -21,6 +21,7 @@
package org.apache.qpid.management.ui.jmx;
import java.util.HashMap;
+import java.util.Map;
import javax.management.ObjectName;
@@ -31,14 +32,36 @@ public class JMXManagedObject extends ManagedBean
{
private ObjectName _objName;
- @SuppressWarnings("unchecked")
public JMXManagedObject(ObjectName objName)
{
super();
this._objName = objName;
setUniqueName(_objName.toString());
- setDomain(_objName.getDomain());
- super.setProperties(new HashMap(_objName.getKeyPropertyList()));
+ setDomain(_objName.getDomain());
+
+ HashMap<String,String> props = new HashMap<String,String>(_objName.getKeyPropertyList());
+
+ for(Map.Entry<String,String> entry : props.entrySet())
+ {
+ String value = entry.getValue();
+
+ if(value != null)
+ {
+ try
+ {
+ //if the name is quoted in the ObjectName, unquote it
+ value = ObjectName.unquote(value);
+ entry.setValue(value);
+ }
+ catch(IllegalArgumentException e)
+ {
+ //ignore, this just means the name is not quoted
+ //and can be left unchanged
+ }
+ }
+ }
+
+ super.setProperties(props);
}
public ObjectName getObjectName()
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
index e42b3c53b6..35cc9f6e27 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
@@ -61,7 +61,7 @@ public class NotificationObject
{
if (_source instanceof ObjectName)
{
- return ((ObjectName)_source).getKeyProperty("name");
+ return unquote(((ObjectName)_source).getKeyProperty("name"));
}
return null;
@@ -71,12 +71,31 @@ public class NotificationObject
{
if (_source instanceof ObjectName)
{
- return ((ObjectName)_source).getKeyProperty(VIRTUAL_HOST);
+ return unquote(((ObjectName)_source).getKeyProperty(VIRTUAL_HOST));
}
return null;
}
-
+
+ private String unquote(String value)
+ {
+ if(value != null)
+ {
+ try
+ {
+ //if the value is quoted in the ObjectName, unquote it
+ value = ObjectName.unquote(value);
+ }
+ catch(IllegalArgumentException e)
+ {
+ //ignore, this just means the value is not quoted
+ //and can be left unchanged
+ }
+ }
+
+ return value;
+ }
+
public String getMessage()
{
return _message;
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java
index 1fef89d6b5..527fc67be3 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java
@@ -131,6 +131,8 @@ public class MBeanTabFolderFactory
}
break;
case VHOST_MANAGER:
+ createAttributesTab(tabFolder, mbean);
+
tab = new TabItem(tabFolder, SWT.NONE);
tab.setText("Operations");
controller = new VHostTabControl(tabFolder, mbean, mbsc);
diff --git a/qpid/java/module.xml b/qpid/java/module.xml
index d3954a1544..80f577b018 100644
--- a/qpid/java/module.xml
+++ b/qpid/java/module.xml
@@ -401,6 +401,15 @@
</target>
+ <target name="report-module" description="generate junit reports for each module">
+ <junitreport todir="${module.results}">
+ <fileset dir="${module.results}">
+ <include name="TEST-*.xml"/>
+ </fileset>
+ <report format="frames" todir="${module.results}/report/html"/>
+ </junitreport>
+ </target>
+
<target name="touch-failed" if="test.failures">
<touch file="${module.failed}"/>
<touch file="${build.failed}"/>
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java
index 004ce5ea8f..bf96dae02e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java
@@ -27,6 +27,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import javax.jms.Connection;
import javax.jms.JMSException;
@@ -51,6 +52,7 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
private Session _session;
MessageConsumer _consumer;
MessageProducer _producer;
+ UUID myUUID = UUID.randomUUID();
public void setUp() throws Exception
{
@@ -119,7 +121,8 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
m.setFloat("Float", Integer.MAX_VALUE + 5000);
m.setInt("Int", Integer.MAX_VALUE - 5000);
m.setShort("Short", (short)58);
- m.setString("String", "Hello");
+ m.setString("String", "Hello");
+ m.setObject("uuid", myUUID);
_producer.send(m);
AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT);
@@ -140,6 +143,7 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
assertEquals(Integer.MAX_VALUE - 5000,m.getInt("Int"));
assertEquals((short)58,m.getShort("Short"));
assertEquals("Hello",m.getString("String"));
+ assertEquals(myUUID,(UUID)m.getObject("uuid"));
}
@@ -149,7 +153,11 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
List<Integer> myList = getList();
- m.setObject("List", myList);
+ m.setObject("List", myList);
+
+ List<UUID> uuidList = new ArrayList<UUID>();
+ uuidList.add(myUUID);
+ m.setObject("uuid-list", uuidList);
_producer.send(m);
AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT);
@@ -167,6 +175,10 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
assertEquals(i,j.intValue());
i++;
}
+
+ List<UUID> list2 = (List<UUID>)msg.getObject("uuid-list");
+ assertNotNull("UUID List not received",list2);
+ assertEquals(myUUID,list2.get(0));
}
public void testMessageWithMapEntries() throws JMSException
@@ -174,8 +186,12 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
MapMessage m = _session.createMapMessage();
Map<String,String> myMap = getMap();
+ m.setObject("Map", myMap);
+
+ Map<String,UUID> uuidMap = new HashMap<String,UUID>();
+ uuidMap.put("uuid", myUUID);
+ m.setObject("uuid-map", uuidMap);
- m.setObject("Map", myMap);
_producer.send(m);
AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT);
@@ -191,6 +207,10 @@ public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase
assertEquals("String" + i,map.get("Key" + i));
i++;
}
+
+ Map<String,UUID> map2 = (Map<String,UUID>)msg.getObject("uuid-map");
+ assertNotNull("Map not received",map2);
+ assertEquals(myUUID,map2.get("uuid"));
}
public void testMessageWithNestedListsAndMaps() throws JMSException
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java
new file mode 100644
index 0000000000..9839c6e475
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+/**
+ * Test enabling generation of message statistics on a per-connection basis.
+ */
+public class MessageConnectionStatisticsTest extends MessageStatisticsTestCase
+{
+ public void configureStatistics() throws Exception
+ {
+ // no statistics generation configured
+ }
+
+ /**
+ * Test statistics on a single connection
+ */
+ public void testEnablingStatisticsPerConnection() throws Exception
+ {
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ List<String> addresses = new ArrayList<String>();
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled());
+
+ addresses.add(mc.getRemoteAddress());
+ }
+ assertEquals("Incorrect vhost total", 0, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived());
+
+ Connection test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test");
+ test.start();
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ if (addresses.contains(mc.getRemoteAddress()))
+ {
+ continue;
+ }
+ mc.setStatisticsEnabled(true);
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ }
+
+ sendUsing(test, 5, 200);
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ if (addresses.contains(mc.getRemoteAddress()))
+ {
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled());
+ }
+ else
+ {
+ assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived());
+ assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled());
+ }
+ }
+ assertEquals("Incorrect vhost total", 0, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived());
+ assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled());
+
+ test.close();
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java
new file mode 100644
index 0000000000..df8c6e74cd
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java
@@ -0,0 +1,177 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.management.jmx;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+/**
+ * Test enabling generation of message statistics on a per-connection basis.
+ */
+public class MessageStatisticsConfigurationTest extends MessageStatisticsTestCase
+{
+ public void configureStatistics() throws Exception
+ {
+ setConfigurationProperty("statistics.generation.broker", Boolean.toString(getName().contains("Broker")));
+ setConfigurationProperty("statistics.generation.virtualhosts", Boolean.toString(getName().contains("Virtualhost")));
+ setConfigurationProperty("statistics.generation.connections", Boolean.toString(getName().contains("Connection")));
+ }
+
+ /**
+ * Just broker statistics.
+ */
+ public void testGenerateBrokerStatistics() throws Exception
+ {
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled());
+ }
+
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived());
+ assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived());
+ assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled());
+ }
+ }
+
+ /**
+ * Just virtualhost statistics.
+ */
+ public void testGenerateVirtualhostStatistics() throws Exception
+ {
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled());
+ }
+
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+ assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived());
+ assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 0, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 0, _jmxUtils.getServerInformation().getTotalDataReceived());
+ assertFalse("Server statistics should not be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled());
+ }
+ }
+
+ /**
+ * Just connection statistics.
+ */
+ public void testGenerateConnectionStatistics() throws Exception
+ {
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived());
+ assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled());
+ }
+
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived());
+ assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 0, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 0, _jmxUtils.getServerInformation().getTotalDataReceived());
+ assertFalse("Server statistics should not be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled());
+ }
+ }
+
+ /**
+ * Both broker and virtualhost statistics.
+ */
+ public void testGenerateBrokerAndVirtualhostStatistics() throws Exception
+ {
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived());
+ assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled());
+ }
+
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+ assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived());
+ assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived());
+ assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled());
+ }
+ }
+
+ /**
+ * Broker, virtualhost and connection statistics.
+ */
+ public void testGenerateBrokerVirtualhostAndConnectionStatistics() throws Exception
+ {
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived());
+ assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled());
+ }
+
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+ assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived());
+ assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived());
+ assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled());
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java
new file mode 100644
index 0000000000..e657856d0e
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.management.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+/**
+ * Test statistics for delivery and receipt.
+ */
+public class MessageStatisticsDeliveryTest extends MessageStatisticsTestCase
+{
+ public void configureStatistics() throws Exception
+ {
+ setConfigurationProperty("statistics.generation.broker", "true");
+ setConfigurationProperty("statistics.generation.virtualhosts", "true");
+ setConfigurationProperty("statistics.generation.connections", "true");
+ }
+
+ public void testDeliveryAndReceiptStatistics() throws Exception
+ {
+ ManagedBroker vhost = _jmxUtils.getManagedBroker("test");
+
+ sendUsing(_test, 5, 200);
+ Thread.sleep(1000);
+
+ List<String> addresses = new ArrayList<String>();
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ assertEquals("Incorrect connection delivery total", 0, mc.getTotalMessagesDelivered());
+ assertEquals("Incorrect connection delivery data", 0, mc.getTotalDataDelivered());
+ assertEquals("Incorrect connection receipt total", 5, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection receipt data", 1000, mc.getTotalDataReceived());
+
+ addresses.add(mc.getRemoteAddress());
+ }
+
+ assertEquals("Incorrect vhost delivery total", 0, vhost.getTotalMessagesDelivered());
+ assertEquals("Incorrect vhost delivery data", 0, vhost.getTotalDataDelivered());
+ assertEquals("Incorrect vhost receipt total", 5, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost receipt data", 1000, vhost.getTotalDataReceived());
+
+ Connection test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test");
+ test.start();
+ receiveUsing(test, 5);
+
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ if (addresses.contains(mc.getRemoteAddress()))
+ {
+ assertEquals("Incorrect connection delivery total", 0, mc.getTotalMessagesDelivered());
+ assertEquals("Incorrect connection delivery data", 0, mc.getTotalDataDelivered());
+ assertEquals("Incorrect connection receipt total", 5, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection receipt data", 1000, mc.getTotalDataReceived());
+ }
+ else
+ {
+ assertEquals("Incorrect connection delivery total", 5, mc.getTotalMessagesDelivered());
+ assertEquals("Incorrect connection delivery data", 1000, mc.getTotalDataDelivered());
+ assertEquals("Incorrect connection receipt total", 0, mc.getTotalMessagesReceived());
+ assertEquals("Incorrect connection receipt data", 0, mc.getTotalDataReceived());
+ }
+ }
+ assertEquals("Incorrect vhost delivery total", 5, vhost.getTotalMessagesDelivered());
+ assertEquals("Incorrect vhost delivery data", 1000, vhost.getTotalDataDelivered());
+ assertEquals("Incorrect vhost receipt total", 5, vhost.getTotalMessagesReceived());
+ assertEquals("Incorrect vhost receipt data", 1000, vhost.getTotalDataReceived());
+
+ test.close();
+ }
+
+ protected void receiveUsing(Connection con, int number) throws Exception
+ {
+ Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ createQueue(session);
+ MessageConsumer consumer = session.createConsumer(_queue);
+ for (int i = 0; i < number; i++)
+ {
+ Message msg = consumer.receive(100);
+ assertNotNull("Message " + i + " was not received", msg);
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java
new file mode 100644
index 0000000000..180440c0d6
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.jmx;
+
+import java.util.List;
+
+import org.apache.qpid.util.LogMonitor;
+
+/**
+ * Test generation of message statistics reporting.
+ */
+public class MessageStatisticsReportingTest extends MessageStatisticsTestCase
+{
+ protected LogMonitor _monitor;
+
+ public void configureStatistics() throws Exception
+ {
+ setConfigurationProperty("statistics.generation.broker", "true");
+ setConfigurationProperty("statistics.generation.virtualhosts", "true");
+
+ if (getName().equals("testEnabledStatisticsReporting"))
+ {
+ setConfigurationProperty("statistics.reporting.period", "10");
+ }
+
+ _monitor = new LogMonitor(_outputFile);
+ }
+
+ /**
+ * Test enabling reporting.
+ */
+ public void testEnabledStatisticsReporting() throws Exception
+ {
+ sendUsing(_test, 10, 100);
+ sendUsing(_dev, 20, 100);
+ sendUsing(_local, 15, 100);
+
+ Thread.sleep(10 * 1000); // 15s
+
+ List<String> brokerStatsData = _monitor.findMatches("BRK-1008");
+ List<String> brokerStatsMessages = _monitor.findMatches("BRK-1009");
+ List<String> vhostStatsData = _monitor.findMatches("VHT-1003");
+ List<String> vhostStatsMessages = _monitor.findMatches("VHT-1004");
+
+ assertEquals("Incorrect number of broker data stats log messages", 2, brokerStatsData.size());
+ assertEquals("Incorrect number of broker message stats log messages", 2, brokerStatsMessages.size());
+ assertEquals("Incorrect number of virtualhost data stats log messages", 6, vhostStatsData.size());
+ assertEquals("Incorrect number of virtualhost message stats log messages", 6, vhostStatsMessages.size());
+ }
+
+ /**
+ * Test not enabling reporting.
+ */
+ public void testNotEnabledStatisticsReporting() throws Exception
+ {
+ sendUsing(_test, 10, 100);
+ sendUsing(_dev, 20, 100);
+ sendUsing(_local, 15, 100);
+
+ Thread.sleep(10 * 1000); // 15s
+
+ List<String> brokerStatsData = _monitor.findMatches("BRK-1008");
+ List<String> brokerStatsMessages = _monitor.findMatches("BRK-1009");
+ List<String> vhostStatsData = _monitor.findMatches("VHT-1003");
+ List<String> vhostStatsMessages = _monitor.findMatches("VHT-1004");
+
+ assertEquals("Incorrect number of broker data stats log messages", 0, brokerStatsData.size());
+ assertEquals("Incorrect number of broker message stats log messages", 0, brokerStatsMessages.size());
+ assertEquals("Incorrect number of virtualhost data stats log messages", 0, vhostStatsData.size());
+ assertEquals("Incorrect number of virtualhost message stats log messages", 0, vhostStatsMessages.size());
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java
new file mode 100644
index 0000000000..50ca51b18a
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java
@@ -0,0 +1,233 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.management.jmx;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+/**
+ * Test generation of message statistics.
+ */
+public class MessageStatisticsTest extends MessageStatisticsTestCase
+{
+ public void configureStatistics() throws Exception
+ {
+ setConfigurationProperty("statistics.generation.broker", "true");
+ setConfigurationProperty("statistics.generation.virtualhosts", "true");
+ setConfigurationProperty("statistics.generation.connections", "true");
+ }
+
+ /**
+ * Test message totals.
+ */
+ public void testMessageTotals() throws Exception
+ {
+ sendUsing(_test, 10, 100);
+ sendUsing(_dev, 20, 100);
+ sendUsing(_local, 5, 100);
+ sendUsing(_local, 5, 100);
+ sendUsing(_local, 5, 100);
+ Thread.sleep(2000);
+
+ ManagedBroker test = _jmxUtils.getManagedBroker("test");
+ ManagedBroker dev = _jmxUtils.getManagedBroker("development");
+ ManagedBroker local = _jmxUtils.getManagedBroker("localhost");
+
+ if (!isBroker010())
+ {
+ long total = 0;
+ long data = 0;
+ for (ManagedConnection mc : _jmxUtils.getAllManagedConnections())
+ {
+ total += mc.getTotalMessagesReceived();
+ data += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect connection total", 45, total);
+ assertEquals("Incorrect connection data", 4500, data);
+ }
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total", 45, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server data", 4500, _jmxUtils.getServerInformation().getTotalDataReceived());
+ }
+
+ if (!isBroker010())
+ {
+ long testTotal = 0;
+ long testData = 0;
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ testTotal += mc.getTotalMessagesReceived();
+ testData += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect test connection total", 10, testTotal);
+ assertEquals("Incorrect test connection data", 1000, testData);
+ }
+ assertEquals("Incorrect test vhost total", 10, test.getTotalMessagesReceived());
+ assertEquals("Incorrect test vhost data", 1000, test.getTotalDataReceived());
+
+ if (!isBroker010())
+ {
+ long devTotal = 0;
+ long devData = 0;
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("development"))
+ {
+ devTotal += mc.getTotalMessagesReceived();
+ devData += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect test connection total", 20, devTotal);
+ assertEquals("Incorrect test connection data", 2000, devData);
+ }
+ assertEquals("Incorrect development total", 20, dev.getTotalMessagesReceived());
+ assertEquals("Incorrect development data", 2000, dev.getTotalDataReceived());
+
+ if (!isBroker010())
+ {
+ long localTotal = 0;
+ long localData = 0;
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("localhost"))
+ {
+ localTotal += mc.getTotalMessagesReceived();
+ localData += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect test connection total", 15, localTotal);
+ assertEquals("Incorrect test connection data", 1500, localData);
+ }
+ assertEquals("Incorrect localhost total", 15, local.getTotalMessagesReceived());
+ assertEquals("Incorrect localhost data", 1500, local.getTotalDataReceived());
+ }
+
+ /**
+ * Test message totals when a connection is closed.
+ */
+ public void testMessageTotalsWithClosedConnections() throws Exception
+ {
+ Connection temp = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test");
+ temp.start();
+
+ sendUsing(_test, 10, 100);
+ sendUsing(temp, 10, 100);
+ sendUsing(_test, 10, 100);
+ Thread.sleep(2000);
+
+ temp.close();
+
+ ManagedBroker test = _jmxUtils.getManagedBroker("test");
+
+ if (!isBroker010())
+ {
+ long total = 0;
+ long data = 0;
+ for (ManagedConnection mc : _jmxUtils.getAllManagedConnections())
+ {
+ total += mc.getTotalMessagesReceived();
+ data += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect active connection total", 20, total);
+ assertEquals("Incorrect active connection data", 2000, data);
+ }
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total", 30, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server data", 3000, _jmxUtils.getServerInformation().getTotalDataReceived());
+ }
+
+ if (!isBroker010())
+ {
+ long testTotal = 0;
+ long testData = 0;
+ for (ManagedConnection mc : _jmxUtils.getManagedConnections("test"))
+ {
+ testTotal += mc.getTotalMessagesReceived();
+ testData += mc.getTotalDataReceived();
+ }
+ assertEquals("Incorrect test active connection total", 20, testTotal);
+ assertEquals("Incorrect test active connection data", 20 * 100, testData);
+ }
+ assertEquals("Incorrect test vhost total", 30, test.getTotalMessagesReceived());
+ assertEquals("Incorrect test vhost data", 30 * 100, test.getTotalDataReceived());
+ }
+
+ /**
+ * Test message peak rate generation.
+ */
+ public void testMessagePeakRates() throws Exception
+ {
+ sendUsing(_test, 2, 10);
+ Thread.sleep(10000);
+ sendUsing(_dev, 4, 10);
+ Thread.sleep(10000);
+
+ ManagedBroker test = _jmxUtils.getManagedBroker("test");
+ ManagedBroker dev = _jmxUtils.getManagedBroker("development");
+
+ assertApprox("Incorrect test vhost peak messages", 0.2d, 1.0d, test.getPeakMessageReceiptRate());
+ assertApprox("Incorrect test vhost peak data", 0.2d, 10.0d, test.getPeakDataReceiptRate());
+ assertApprox("Incorrect dev vhost peak messages", 0.2d, 2.0d, dev.getPeakMessageReceiptRate());
+ assertApprox("Incorrect dev vhost peak data", 0.2d, 20.0d, dev.getPeakDataReceiptRate());
+
+ if (!_broker.equals(VM))
+ {
+ assertApprox("Incorrect server peak messages", 0.2d, 2.0d, _jmxUtils.getServerInformation().getPeakMessageReceiptRate());
+ assertApprox("Incorrect server peak data", 0.2d, 20.0d, _jmxUtils.getServerInformation().getPeakDataReceiptRate());
+ }
+ }
+
+ /**
+ * Test message totals when a vhost has its statistics reset
+ */
+ public void testMessageTotalVhostReset() throws Exception
+ {
+ sendUsing(_test, 10, 10);
+ sendUsing(_dev, 10, 10);
+ Thread.sleep(2000);
+
+ ManagedBroker test = _jmxUtils.getManagedBroker("test");
+ ManagedBroker dev = _jmxUtils.getManagedBroker("development");
+
+ assertEquals("Incorrect test vhost total messages", 10, test.getTotalMessagesReceived());
+ assertEquals("Incorrect test vhost total data", 100, test.getTotalDataReceived());
+ assertEquals("Incorrect dev vhost total messages", 10, dev.getTotalMessagesReceived());
+ assertEquals("Incorrect dev vhost total data", 100, dev.getTotalDataReceived());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 20, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 200, _jmxUtils.getServerInformation().getTotalDataReceived());
+ }
+
+ test.resetStatistics();
+
+ assertEquals("Incorrect test vhost total messages", 0, test.getTotalMessagesReceived());
+ assertEquals("Incorrect test vhost total data", 0, test.getTotalDataReceived());
+ assertEquals("Incorrect dev vhost total messages", 10, dev.getTotalMessagesReceived());
+ assertEquals("Incorrect dev vhost total data", 100, dev.getTotalDataReceived());
+
+ if (!_broker.equals(VM))
+ {
+ assertEquals("Incorrect server total messages", 20, _jmxUtils.getServerInformation().getTotalMessagesReceived());
+ assertEquals("Incorrect server total data", 200, _jmxUtils.getServerInformation().getTotalDataReceived());
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java
new file mode 100644
index 0000000000..a5b3aa283c
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.management.jmx;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+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.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Test generation of message statistics.
+ */
+public abstract class MessageStatisticsTestCase extends QpidBrokerTestCase
+{
+ protected static final String USER = "admin";
+
+ protected JMXTestUtils _jmxUtils;
+ protected Connection _test, _dev, _local;
+ protected String _queueName = "statistics";
+ protected Destination _queue;
+ protected String _brokerUrl;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils.setUp();
+
+ configureStatistics();
+
+ super.setUp();
+
+ _brokerUrl = getBroker().toString();
+ _test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test");
+ _dev = new AMQConnection(_brokerUrl, USER, USER, "clientid", "development");
+ _local = new AMQConnection(_brokerUrl, USER, USER, "clientid", "localhost");
+
+ _test.start();
+ _dev.start();
+ _local.start();
+
+ _jmxUtils.open();
+ }
+
+ protected void createQueue(Session session) throws AMQException, JMSException
+ {
+ _queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName);
+ if (!((AMQSession<?,?>) session).isQueueBound((AMQDestination) _queue))
+ {
+ ((AMQSession<?,?>) session).createQueue(new AMQShortString(_queueName), false, true, false, null);
+ ((AMQSession<?,?>) session).declareAndBind((AMQDestination) new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName));
+ }
+ }
+
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmxUtils.close();
+
+ _test.close();
+ _dev.close();
+ _local.close();
+
+ super.tearDown();
+ }
+
+ /**
+ * Configure statistics generation properties on the broker.
+ */
+ public abstract void configureStatistics() throws Exception;
+
+ protected void sendUsing(Connection con, int number, int size) throws Exception
+ {
+ Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ createQueue(session);
+ MessageProducer producer = session.createProducer(_queue);
+ String content = new String(new byte[size]);
+ TextMessage msg = session.createTextMessage(content);
+ for (int i = 0; i < number; i++)
+ {
+ producer.send(msg);
+ }
+ }
+
+ /**
+ * Asserts that the actual value is within the expected value plus or
+ * minus the given error.
+ */
+ public void assertApprox(String message, double error, double expected, double actual)
+ {
+ double min = expected * (1.0d - error);
+ double max = expected * (1.0d + error);
+ String assertion = String.format("%s: expected %f +/- %d%%, actual %f",
+ message, expected, (int) (error * 100.0d), actual);
+ assertTrue(assertion, actual > min && actual < max);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
index 51589c705f..0480ea4cab 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
@@ -31,13 +31,20 @@ import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
import javax.naming.Context;
import org.apache.qpid.client.AMQAnyDestination;
+import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQSession_0_10;
import org.apache.qpid.client.messaging.address.Node.ExchangeNode;
import org.apache.qpid.client.messaging.address.Node.QueueNode;
@@ -796,4 +803,190 @@ public class AddressBasedDestinationTest extends QpidBrokerTestCase
{
}
}
+
+ public void testQueueReceiversAndTopicSubscriber() throws Exception
+ {
+ Queue queue = new AMQAnyDestination("ADDR:my-queue; {create: always}");
+ Topic topic = new AMQAnyDestination("ADDR:amq.topic/test");
+
+ QueueSession qSession = ((AMQConnection)_connection).createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ QueueReceiver receiver = qSession.createReceiver(queue);
+
+ TopicSession tSession = ((AMQConnection)_connection).createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ TopicSubscriber sub = tSession.createSubscriber(topic);
+
+ Session ssn = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer prod1 = ssn.createProducer(ssn.createQueue("ADDR:my-queue"));
+ prod1.send(ssn.createTextMessage("test1"));
+
+ MessageProducer prod2 = ssn.createProducer(ssn.createTopic("ADDR:amq.topic/test"));
+ prod2.send(ssn.createTextMessage("test2"));
+
+ Message msg1 = receiver.receive();
+ assertNotNull(msg1);
+ assertEquals("test1",((TextMessage)msg1).getText());
+
+ Message msg2 = sub.receive();
+ assertNotNull(msg2);
+ assertEquals("test2",((TextMessage)msg2).getText());
+ }
+
+ public void testDurableSubscriber() throws Exception
+ {
+ Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ Topic topic = ssn.createTopic("news.us");
+
+ MessageConsumer cons = ssn.createDurableSubscriber(topic, "my-sub");
+ MessageProducer prod = ssn.createProducer(topic);
+
+ Message m = ssn.createTextMessage("A");
+ prod.send(m);
+ Message msg = cons.receive(1000);
+ assertNotNull(msg);
+ assertEquals("A",((TextMessage)msg).getText());
+ }
+
+ public void testDeleteOptions() throws Exception
+ {
+ Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer cons;
+
+ // default (create never, assert never) -------------------
+ // create never --------------------------------------------
+ String addr1 = "ADDR:testQueue1;{create: always, delete: always}";
+ AMQDestination dest = new AMQAnyDestination(addr1);
+ try
+ {
+ cons = jmsSession.createConsumer(dest);
+ cons.close();
+ }
+ catch(JMSException e)
+ {
+ fail("Exception should not be thrown. Exception thrown is : " + e);
+ }
+
+ assertFalse("Queue not deleted as expected",(
+ (AMQSession_0_10)jmsSession).isQueueExist(dest,(QueueNode)dest.getSourceNode(), true));
+
+
+ String addr2 = "ADDR:testQueue2;{create: always, delete: receiver}";
+ dest = new AMQAnyDestination(addr2);
+ try
+ {
+ cons = jmsSession.createConsumer(dest);
+ cons.close();
+ }
+ catch(JMSException e)
+ {
+ fail("Exception should not be thrown. Exception thrown is : " + e);
+ }
+
+ assertFalse("Queue not deleted as expected",(
+ (AMQSession_0_10)jmsSession).isQueueExist(dest,(QueueNode)dest.getSourceNode(), true));
+
+
+ String addr3 = "ADDR:testQueue3;{create: always, delete: sender}";
+ dest = new AMQAnyDestination(addr3);
+ try
+ {
+ cons = jmsSession.createConsumer(dest);
+ MessageProducer prod = jmsSession.createProducer(dest);
+ prod.close();
+ }
+ catch(JMSException e)
+ {
+ fail("Exception should not be thrown. Exception thrown is : " + e);
+ }
+
+ assertFalse("Queue not deleted as expected",(
+ (AMQSession_0_10)jmsSession).isQueueExist(dest,(QueueNode)dest.getSourceNode(), true));
+
+
+ }
+
+ /**
+ * Test Goals : 1. Test if the client sets the correct accept mode for unreliable
+ * and at-least-once.
+ * 2. Test default reliability modes for Queues and Topics.
+ * 3. Test if an exception is thrown if exactly-once is used.
+ * 4. Test if an exception is thrown if at-least-once is used with topics.
+ *
+ * Test Strategy: For goal #1 & #2
+ * For unreliable and at-least-once the test tries to receives messages
+ * in client_ack mode but does not ack the messages.
+ * It will then close the session, recreate a new session
+ * and will then try to verify the queue depth.
+ * For unreliable the messages should have been taken off the queue.
+ * For at-least-once the messages should be put back onto the queue.
+ *
+ */
+
+ public void testReliabilityOptions() throws Exception
+ {
+ String addr1 = "ADDR:testQueue1;{create: always, delete : receiver, link : {reliability : unreliable}}";
+ acceptModeTest(addr1,0);
+
+ String addr2 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : at-least-once}}";
+ acceptModeTest(addr2,2);
+
+ // Default accept-mode for topics
+ acceptModeTest("ADDR:amq.topic/test",0);
+
+ // Default accept-mode for queues
+ acceptModeTest("ADDR:testQueue1;{create: always}",2);
+
+ String addr3 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : exactly-once}}";
+ try
+ {
+ AMQAnyDestination dest = new AMQAnyDestination(addr3);
+ fail("An exception should be thrown indicating it's an unsupported type");
+ }
+ catch(Exception e)
+ {
+ assertTrue(e.getCause().getMessage().contains("The reliability mode 'exactly-once' is not yet supported"));
+ }
+
+ String addr4 = "ADDR:amq.topic/test;{link : {reliability : at-least-once}}";
+ try
+ {
+ AMQAnyDestination dest = new AMQAnyDestination(addr4);
+ Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
+ MessageConsumer cons = ssn.createConsumer(dest);
+ fail("An exception should be thrown indicating it's an unsupported combination");
+ }
+ catch(Exception e)
+ {
+ assertTrue(e.getCause().getMessage().contains("AT-LEAST-ONCE is not yet supported for Topics"));
+ }
+ }
+
+ private void acceptModeTest(String address, int expectedQueueDepth) throws Exception
+ {
+ Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
+ MessageConsumer cons;
+ MessageProducer prod;
+
+ AMQDestination dest = new AMQAnyDestination(address);
+ cons = ssn.createConsumer(dest);
+ prod = ssn.createProducer(dest);
+
+ for (int i=0; i < expectedQueueDepth; i++)
+ {
+ prod.send(ssn.createTextMessage("Msg" + i));
+ }
+
+ for (int i=0; i < expectedQueueDepth; i++)
+ {
+ Message msg = cons.receive(1000);
+ assertNotNull(msg);
+ assertEquals("Msg" + i,((TextMessage)msg).getText());
+ }
+
+ ssn.close();
+ ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
+ long queueDepth = ((AMQSession) ssn).getQueueDepth(dest);
+ assertEquals(expectedQueueDepth,queueDepth);
+ cons.close();
+ prod.close();
+ }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
index 33575b58aa..8577fb5b6a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.test.unit.client;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
import javax.jms.Connection;
@@ -32,11 +34,9 @@ import javax.jms.Session;
*
* Test to validate that setting the respective qpid.declare_queues,
* qpid.declare_exchanges system properties functions as expected.
- *
*/
public class DynamicQueueExchangeCreateTest extends QpidBrokerTestCase
{
-
public void testQueueDeclare() throws Exception
{
setSystemProperty("qpid.declare_queues", "false");
@@ -53,11 +53,8 @@ public class DynamicQueueExchangeCreateTest extends QpidBrokerTestCase
fail("JMSException should be thrown as the queue does not exist");
}
catch (JMSException e)
- {
- assertTrue("Exception should be that the queue does not exist :" +
- e.getMessage(),
- e.getMessage().contains("does not exist"));
-
+ {
+ checkExceptionErrorCode(e, AMQConstant.NOT_FOUND);
}
}
@@ -79,10 +76,15 @@ public class DynamicQueueExchangeCreateTest extends QpidBrokerTestCase
}
catch (JMSException e)
{
- assertTrue("Exception should be that the exchange does not exist :" +
- e.getMessage(),
- e.getMessage().contains("Exchange " + EXCHANGE_TYPE + " does not exist"));
+ checkExceptionErrorCode(e, AMQConstant.NOT_FOUND);
}
}
+ private void checkExceptionErrorCode(JMSException original, AMQConstant code)
+ {
+ Exception linked = original.getLinkedException();
+ assertNotNull("Linked exception should have been set", linked);
+ assertTrue("Linked exception should be an AMQException", linked instanceof AMQException);
+ assertEquals("Error code should be " + code.getCode(), code, ((AMQException) linked).getErrorCode());
+ }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
index f0794c9dab..b6232b1734 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
@@ -29,7 +29,6 @@ import org.apache.qpid.client.transport.TransportConnection;
import org.apache.qpid.framing.*;
import org.apache.qpid.jms.ConnectionListener;
import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.url.URLSyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,70 +48,67 @@ public class ChannelCloseTest extends QpidBrokerTestCase implements ExceptionLis
private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseTest.class);
Connection _connection;
- private String _brokerlist = "vm://:1";
private Session _session;
private static final long SYNC_TIMEOUT = 500;
private int TEST = 0;
- /*
- close channel, use chanel with same id ensure error.
+ /**
+ * Close channel, use chanel with same id ensure error.
+ *
+ * This test is only valid for non 0-10 connection .
*/
public void testReusingChannelAfterFullClosure() throws Exception
{
- // this is testing an inVM Connetion conneciton
- if (isJavaBroker() && !isExternalBroker())
+ _connection=newConnection();
+
+ // Create Producer
+ try
{
- _connection=newConnection();
+ _connection.start();
+
+ createChannelAndTest(1);
- // Create Producer
+ // Cause it to close
try
{
- _connection.start();
-
- createChannelAndTest(1);
-
- // Cause it to close
- try
- {
- _logger.info("Testing invalid exchange");
- declareExchange(1, "", "name_that_will_lookup_to_null", false);
- fail("Exchange name is empty so this should fail ");
- }
- catch (AMQException e)
- {
- assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode());
- }
+ _logger.info("Testing invalid exchange");
+ declareExchange(1, "", "name_that_will_lookup_to_null", false);
+ fail("Exchange name is empty so this should fail ");
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode());
+ }
- // Check that
- try
+ // Check that
+ try
+ {
+ _logger.info("Testing valid exchange should fail");
+ declareExchange(1, "topic", "amq.topic", false);
+ fail("This should not succeed as the channel should be closed ");
+ }
+ catch (AMQException e)
+ {
+ if (_logger.isInfoEnabled())
{
- _logger.info("Testing valid exchange should fail");
- declareExchange(1, "topic", "amq.topic", false);
- fail("This should not succeed as the channel should be closed ");
+ _logger.info("Exception occured was:" + e.getErrorCode());
}
- catch (AMQException e)
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Exception occured was:" + e.getErrorCode());
- }
- assertEquals("Connection should be closed", AMQConstant.CHANNEL_ERROR, e.getErrorCode());
+ assertEquals("Connection should be closed", AMQConstant.CHANNEL_ERROR, e.getErrorCode());
- _connection=newConnection();
- }
+ _connection=newConnection();
+ }
- checkSendingMessage();
+ checkSendingMessage();
- _session.close();
- _connection.close();
+ _session.close();
+ _connection.close();
- }
- catch (JMSException e)
- {
- e.printStackTrace();
- fail(e.getMessage());
- }
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
}
}
@@ -306,27 +302,19 @@ public class ChannelCloseTest extends QpidBrokerTestCase implements ExceptionLis
private Connection newConnection()
{
- AMQConnection connection = null;
+ Connection connection = null;
try
{
- connection = new AMQConnection("amqp://guest:guest@CCTTest/test?brokerlist='" + _brokerlist + "'");
+ connection = getConnection();
- connection.setConnectionListener(this);
+ ((AMQConnection) connection).setConnectionListener(this);
_session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
connection.start();
}
- catch (JMSException e)
- {
- fail("Creating new connection when:" + e.getMessage());
- }
- catch (AMQException e)
- {
- fail("Creating new connection when:" + e.getMessage());
- }
- catch (URLSyntaxException e)
+ catch (Exception e)
{
fail("Creating new connection when:" + e.getMessage());
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutConfigurationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutConfigurationTest.java
new file mode 100644
index 0000000000..36bac3b715
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutConfigurationTest.java
@@ -0,0 +1,82 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.transacted;
+
+/**
+ * This verifies that changing the {@code transactionTimeout} configuration will alter
+ * the behaviour of the transaction open and idle logging, and that when the connection
+ * will be closed.
+ */
+public class TransactionTimeoutConfigurationTest extends TransactionTimeoutTestCase
+{
+ @Override
+ protected void configure() throws Exception
+ {
+ // Setup housekeeping every second
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".housekeeping.expiredMessageCheckPeriod", "100");
+
+ // Set transaction timout properties.
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.openWarn", "200");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.openClose", "1000");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.idleWarn", "100");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.idleClose", "500");
+ }
+
+ public void testProducerIdleCommit() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(5, 0);
+
+ check(IDLE);
+ }
+
+ public void testProducerOpenCommit() throws Exception
+ {
+ try
+ {
+ send(5, 0.3f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(6, 3);
+
+ check(OPEN);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java
new file mode 100644
index 0000000000..71b89bf911
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transacted;
+
+/**
+ * This verifies that the default behaviour is not to time out transactions.
+ */
+public class TransactionTimeoutDisabledTest extends TransactionTimeoutTestCase
+{
+ @Override
+ protected void configure() throws Exception
+ {
+ // Setup housekeeping every second
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".housekeeping.expiredMessageCheckPeriod", "100");
+ }
+
+ public void testProducerIdleCommit() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testProducerOpenCommit() throws Exception
+ {
+ try
+ {
+ send(5, 0.3f);
+
+ _psession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java
new file mode 100644
index 0000000000..c912d6a323
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java
@@ -0,0 +1,335 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transacted;
+
+/**
+ * This tests the behaviour of transactional sessions when the {@code transactionTimeout} configuration
+ * is set for a virtual host.
+ *
+ * A producer that is idle for too long or open for too long will have its connection closed and
+ * any further operations will fail with a 408 resource timeout exception. Consumers will not
+ * be affected by the transaction timeout configuration.
+ */
+public class TransactionTimeoutTest extends TransactionTimeoutTestCase
+{
+ public void testProducerIdle() throws Exception
+ {
+ try
+ {
+ sleep(2.0f);
+
+ _psession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testProducerIdleCommit() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(5, 0);
+
+ check(IDLE);
+ }
+
+ public void testProducerOpenCommit() throws Exception
+ {
+ try
+ {
+ send(6, 0.5f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(0, 10);
+
+ check(OPEN);
+ }
+
+ public void testProducerIdleCommitTwice() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(1.0f);
+
+ _psession.commit();
+
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(10, 0);
+
+ check(IDLE);
+ }
+
+ public void testProducerOpenCommitTwice() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(1.0f);
+
+ _psession.commit();
+
+ send(6, 0.5f);
+
+ _psession.commit();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ // the presistent store generates more idle messages?
+ monitor(isBrokerStorePersistent() ? 10 : 5, 10);
+
+ check(OPEN);
+ }
+
+ public void testProducerIdleRollback() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.rollback();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(5, 0);
+
+ check(IDLE);
+ }
+
+ public void testProducerIdleRollbackTwice() throws Exception
+ {
+ try
+ {
+ send(5, 0);
+
+ sleep(1.0f);
+
+ _psession.rollback();
+
+ send(5, 0);
+
+ sleep(2.0f);
+
+ _psession.rollback();
+ fail("should fail");
+ }
+ catch (Exception e)
+ {
+ _exception = e;
+ }
+
+ monitor(10, 0);
+
+ check(IDLE);
+ }
+
+ public void testConsumerCommitClose() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ expect(1, 0);
+
+ _csession.commit();
+
+ sleep(3.0f);
+
+ _csession.close();
+ }
+ catch (Exception e)
+ {
+ fail("should have succeeded: " + e.getMessage());
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testConsumerIdleReceiveCommit() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ sleep(2.0f);
+
+ expect(1, 0);
+
+ sleep(2.0f);
+
+ _csession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testConsumerIdleCommit() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ expect(1, 0);
+
+ sleep(2.0f);
+
+ _csession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testConsumerIdleRollback() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ expect(1, 0);
+
+ sleep(2.0f);
+
+ _csession.rollback();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testConsumerOpenCommit() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ sleep(3.0f);
+
+ _csession.commit();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+
+ public void testConsumerOpenRollback() throws Exception
+ {
+ try
+ {
+ send(1, 0);
+
+ _psession.commit();
+
+ sleep(3.0f);
+
+ _csession.rollback();
+ }
+ catch (Exception e)
+ {
+ fail("Should have succeeded");
+ }
+
+ assertTrue("Listener should not have received exception", _caught.getCount() == 1);
+
+ monitor(0, 0);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java
new file mode 100644
index 0000000000..637f43fb2c
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java
@@ -0,0 +1,253 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transacted;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.DeliveryMode;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.TextMessage;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.Session;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.LogMonitor;
+
+/**
+ * The {@link TestCase} for transaction timeout testing.
+ */
+public class TransactionTimeoutTestCase extends QpidBrokerTestCase implements ExceptionListener
+{
+ public static final String VIRTUALHOST = "test";
+ public static final String TEXT = "0123456789abcdefghiforgettherest";
+ public static final String CHN_OPEN_TXN = "CHN-1007";
+ public static final String CHN_IDLE_TXN = "CHN-1008";
+ public static final String IDLE = "Idle";
+ public static final String OPEN = "Open";
+
+ protected LogMonitor _monitor;
+ protected AMQConnection _con;
+ protected Session _psession, _csession;
+ protected Queue _queue;
+ protected MessageConsumer _consumer;
+ protected MessageProducer _producer;
+ protected CountDownLatch _caught = new CountDownLatch(1);
+ protected String _message;
+ protected Exception _exception;
+ protected AMQConstant _code;
+
+ protected void configure() throws Exception
+ {
+ // Setup housekeeping every second
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".housekeeping.expiredMessageCheckPeriod", "100");
+
+ /*
+ * Set transaction timout properties. The XML in the virtualhosts configuration is as follows:
+ *
+ * <transactionTimeout>
+ * <openWarn>1000</openWarn>
+ * <openClose>2000</openClose>
+ * <idleWarn>500</idleWarn>
+ * <idleClose>1500</idleClose>
+ * </transactionTimeout>
+ */
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.openWarn", "1000");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.openClose", "2000");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.idleWarn", "500");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".transactionTimeout.idleClose", "1000");
+ }
+
+ protected void setUp() throws Exception
+ {
+ // Configure timeouts
+ configure();
+
+ // Monitor log file
+ _monitor = new LogMonitor(_outputFile);
+
+ // Start broker
+ super.setUp();
+
+ // Connect to broker
+ String broker = _broker.equals(VM) ? ("vm://:" + DEFAULT_VM_PORT) : ("tcp://localhost:" + DEFAULT_PORT);
+ ConnectionURL url = new AMQConnectionURL("amqp://guest:guest@clientid/test?brokerlist='" + broker + "'&maxprefetch='1'");
+ _con = (AMQConnection) getConnection(url);
+ _con.setExceptionListener(this);
+ _con.start();
+
+ // Create queue
+ Session qsession = _con.createSession(true, Session.SESSION_TRANSACTED);
+ AMQShortString queueName = new AMQShortString("test");
+ _queue = new AMQQueue(qsession.getDefaultQueueExchangeName(), queueName, queueName, false, true);
+ qsession.close();
+
+ // Create producer and consumer
+ producer();
+ consumer();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ _con.close();
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ /**
+ * Create a transacted persistent message producer session.
+ */
+ protected void producer() throws Exception
+ {
+ _psession = _con.createSession(true, Session.SESSION_TRANSACTED);
+ _producer = _psession.createProducer(_queue);
+ _producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+ }
+
+ /**
+ * Create a transacted message consumer session.
+ */
+ protected void consumer() throws Exception
+ {
+ _csession = _con.createSession(true, Session.SESSION_TRANSACTED);
+ _consumer = _csession.createConsumer(_queue);
+ }
+
+ /**
+ * Send a number of messages to the queue, optionally pausing after each.
+ */
+ protected void send(int count, float delay) throws Exception
+ {
+ for (int i = 0; i < count; i++)
+ {
+ sleep(delay);
+ Message msg = _psession.createTextMessage(TEXT);
+ msg.setIntProperty("i", i);
+ _producer.send(msg);
+ }
+ }
+
+ /**
+ * Sleep for a number of seconds.
+ */
+ protected void sleep(float seconds) throws Exception
+ {
+ try
+ {
+ Thread.sleep((long) (seconds * 1000.0f));
+ }
+ catch (InterruptedException ie)
+ {
+ throw new RuntimeException("Interrupted");
+ }
+ }
+
+ /**
+ * Check for idle and open messages.
+ *
+ * Either exactly zero messages, or +-2 error accepted around the specified number.
+ */
+ protected void monitor(int idle, int open) throws Exception
+ {
+ List<String> idleMsgs = _monitor.findMatches(CHN_IDLE_TXN);
+ List<String> openMsgs = _monitor.findMatches(CHN_OPEN_TXN);
+
+ String idleErr = "Expected " + idle + " but found " + idleMsgs.size() + " txn idle messages";
+ String openErr = "Expected " + open + " but found " + openMsgs.size() + " txn open messages";
+
+ if (idle == 0)
+ {
+ assertTrue(idleErr, idleMsgs.isEmpty());
+ }
+ else
+ {
+ assertTrue(idleErr, idleMsgs.size() >= idle - 2 && idleMsgs.size() <= idle + 2);
+ }
+
+ if (open == 0)
+ {
+ assertTrue(openErr, openMsgs.isEmpty());
+ }
+ else
+ {
+ assertTrue(openErr, openMsgs.size() >= open - 2 && openMsgs.size() <= open + 2);
+ }
+ }
+
+ /**
+ * Receive a number of messages, optionally pausing after each.
+ */
+ protected void expect(int count, float delay) throws Exception
+ {
+ for (int i = 0; i < count; i++)
+ {
+ sleep(delay);
+ Message msg = _consumer.receive(1000);
+ assertNotNull("Message should not be null", msg);
+ assertTrue("Message should be a text message", msg instanceof TextMessage);
+ assertEquals("Message content does not match expected", TEXT, ((TextMessage) msg).getText());
+ assertEquals("Message order is incorrect", i, msg.getIntProperty("i"));
+ }
+ }
+
+ /**
+ * Checks that the correct exception was thrown and was received
+ * by the listener with a 506 error code.
+ */
+ protected void check(String reason)throws InterruptedException
+ {
+ assertTrue("Should have caught exception in listener", _caught.await(1, TimeUnit.SECONDS));
+ assertNotNull("Should have thrown exception to client", _exception);
+ assertTrue("Exception message should contain '" + reason + "': " + _message, _message.contains(reason + " transaction timed out"));
+ assertNotNull("Exception should have an error code", _code);
+ assertEquals("Error code should be 506", AMQConstant.RESOURCE_ERROR, _code);
+ }
+
+ /** @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) */
+ public void onException(JMSException jmse)
+ {
+ _caught.countDown();
+ _message = jmse.getLinkedException().getMessage();
+ if (jmse.getLinkedException() instanceof AMQException)
+ {
+ _code = ((AMQException) jmse.getLinkedException()).getErrorCode();
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
index ff80c91fac..9f6963643a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -21,6 +21,8 @@
package org.apache.qpid.test.utils;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import javax.management.JMException;
@@ -31,14 +33,18 @@ import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
import javax.management.remote.JMXConnector;
+import junit.framework.TestCase;
+
import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.commands.objects.AllObjects;
import org.apache.qpid.management.common.JMXConnnectionFactory;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.management.common.mbeans.LoggingManagement;
import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
import org.apache.qpid.management.common.mbeans.UserManagement;
/**
@@ -232,7 +238,8 @@ public class JMXTestUtils
{
// Get the name of the test manager
AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + vhostName + ",*";
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost="
+ + ObjectName.quote(vhostName) + ",*";
Set<ObjectName> objectNames = allObject.returnObjects();
@@ -259,7 +266,9 @@ public class JMXTestUtils
{
// Get the name of the test manager
AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=" + virtualHostName + ",name=" + queue + ",*";
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost="
+ + ObjectName.quote(virtualHostName) + ",name="
+ + ObjectName.quote(queue) + ",*";
Set<ObjectName> objectNames = allObject.returnObjects();
@@ -287,7 +296,9 @@ public class JMXTestUtils
{
// Get the name of the test manager
AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=" + virtualHostName + ",name=" + exchange + ",*";
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost="
+ + ObjectName.quote(virtualHostName) + ",name="
+ + ObjectName.quote(exchange) + ",*";
Set<ObjectName> objectNames = allObject.returnObjects();
@@ -321,6 +332,16 @@ public class JMXTestUtils
return MBeanServerInvocationHandler.newProxyInstance(_mbsc, objectName, managedClass, false);
}
+ public <T> List<T> getManagedObjectList(Class<T> managedClass, Set<ObjectName> objectNames)
+ {
+ List<T> objects = new ArrayList<T>();
+ for (ObjectName name : objectNames)
+ {
+ objects.add(getManagedObject(managedClass, name));
+ }
+ return objects;
+ }
+
public ManagedBroker getManagedBroker(String virtualHost)
{
return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost));
@@ -355,4 +376,54 @@ public class JMXTestUtils
ObjectName objectName = new ObjectName("org.apache.qpid:type=UserManagement,name=UserManagement");
return getManagedObject(UserManagement.class, objectName);
}
+
+ /**
+ * Retrive {@link ServerInformation} JMX MBean.
+ */
+ public ServerInformation getServerInformation()
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=ServerInformation,name=ServerInformation,*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ TestCase.assertNotNull("Null ObjectName Set returned", objectNames);
+ TestCase.assertEquals("Incorrect number of objects returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return getManagedObject(ServerInformation.class, objectNames.iterator().next());
+ }
+
+ /**
+ * Retrive all {@link ManagedConnection} objects.
+ */
+ public List<ManagedConnection> getAllManagedConnections()
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Connection,VirtualHost=*,name=*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ TestCase.assertNotNull("Null ObjectName Set returned", objectNames);
+
+ return getManagedObjectList(ManagedConnection.class, objectNames);
+ }
+
+ /**
+ * Retrive all {@link ManagedConnection} objects for a particular virtual host.
+ */
+ public List<ManagedConnection> getManagedConnections(String vhost)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Connection,VirtualHost=" + ObjectName.quote(vhost) + ",name=*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ TestCase.assertNotNull("Null ObjectName Set returned", objectNames);
+
+ return getManagedObjectList(ManagedConnection.class, objectNames);
+ }
}
diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes
index e89b09cca2..4127682208 100755
--- a/qpid/java/test-profiles/CPPExcludes
+++ b/qpid/java/test-profiles/CPPExcludes
@@ -165,6 +165,11 @@ org.apache.qpid.server.security.firewall.FirewallConfigTest#*
org.apache.qpid.server.security.firewall.FirewallConfigurationTest#*
org.apache.qpid.server.plugins.PluginTest#*
+// Transacion timeouts not implemented in CPP broker
+org.apache.qpid.test.unit.transacted.TransactionTimeoutDisabledTest#*
+org.apache.qpid.test.unit.transacted.TransactionTimeoutConfigurationTest#*
+org.apache.qpid.test.unit.transacted.TransactionTimeoutTest#*
+
// Java broker only
org.apache.qpid.server.logging.management.LoggingManagementMBeanTest#*
org.apache.qpid.server.management.AMQUserManagementMBeanTest#*
diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes
index 3486d5c70c..c05aad0cb1 100755
--- a/qpid/java/test-profiles/Java010Excludes
+++ b/qpid/java/test-profiles/Java010Excludes
@@ -47,6 +47,7 @@ org.apache.qpid.server.logging.SubscriptionLoggingTest#testSubscriptionSuspend
// 0-10 Broker does not have a JMX connection MBean
org.apache.qpid.management.jmx.ManagementActorLoggingTest#testConnectionCloseViaManagement
+org.apache.qpid.management.jmx.MessageConnectionStatisticsTest#*
// 0-10 has different ideas about clientid and ownership of queues
org.apache.qpid.server.queue.ModelTest#*
@@ -54,9 +55,6 @@ org.apache.qpid.server.queue.ModelTest#*
// 0-10 is not supported by the MethodRegistry
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-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
org.apache.qpid.server.queue.ProducerFlowControlTest#*
@@ -74,6 +72,9 @@ org.apache.qpid.test.unit.publish.DirtyTransactedPublishTest#*
org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage
org.apache.qpid.test.unit.ack.RecoverTest#testRecoverInAutoAckListener
+// This test uses 0-8 channel frames
+org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
+
//Temporarily adding the following until the issues are sorted out.
//Should probably raise JIRAs for them.
org.apache.qpid.transport.network.mina.MINANetworkDriverTest#*
diff --git a/qpid/python/qpid/codec010.py b/qpid/python/qpid/codec010.py
index 0846db6bf7..94a1cd4263 100644
--- a/qpid/python/qpid/codec010.py
+++ b/qpid/python/qpid/codec010.py
@@ -17,7 +17,7 @@
# under the License.
#
-import datetime
+import datetime, string
from packer import Packer
from datatypes import serial, timestamp, RangedSet, Struct, UUID
from ops import Compound, PRIMITIVE, COMPOUND
@@ -241,15 +241,20 @@ class Codec(Packer):
v = sc.read_primitive(type)
result[k] = v
return result
+
+ def _write_map_elem(self, k, v):
+ type = self.encoding(v)
+ sc = StringCodec()
+ sc.write_str8(k)
+ sc.write_uint8(type.CODE)
+ sc.write_primitive(type, v)
+ return sc.encoded
+
def write_map(self, m):
sc = StringCodec()
if m is not None:
sc.write_uint32(len(m))
- for k, v in m.items():
- type = self.encoding(v)
- sc.write_str8(k)
- sc.write_uint8(type.CODE)
- sc.write_primitive(type, v)
+ sc.write(string.joinfields(map(self._write_map_elem, m.keys(), m.values()), ""))
self.write_vbin32(sc.encoded)
def read_array(self):
diff --git a/qpid/python/qpid/messaging/endpoints.py b/qpid/python/qpid/messaging/endpoints.py
index b8101b76e6..30c5850397 100644
--- a/qpid/python/qpid/messaging/endpoints.py
+++ b/qpid/python/qpid/messaging/endpoints.py
@@ -197,7 +197,7 @@ class Connection(Endpoint):
return result
def check_closed(self):
- if self.closed:
+ if not self._connected:
self._condition.gc()
raise ConnectionClosed()
diff --git a/qpid/python/qpid/tests/messaging/endpoints.py b/qpid/python/qpid/tests/messaging/endpoints.py
index c303ca652a..0977b2ab3a 100644
--- a/qpid/python/qpid/tests/messaging/endpoints.py
+++ b/qpid/python/qpid/tests/messaging/endpoints.py
@@ -186,6 +186,9 @@ class ConnectionTests(Base):
def setup_connection(self):
return Connection.establish(self.broker, **self.connection_options())
+ def testCheckClosed(self):
+ assert not self.conn.check_closed()
+
def testSessionAnon(self):
ssn1 = self.conn.session()
ssn2 = self.conn.session()
diff --git a/qpid/python/setup.py b/qpid/python/setup.py
index 9c04421c51..a301b3e4cc 100755
--- a/qpid/python/setup.py
+++ b/qpid/python/setup.py
@@ -298,7 +298,7 @@ class install_lib(_install_lib):
return outfiles + extra
setup(name="qpid-python",
- version="0.9",
+ version="0.11",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
packages=["mllib", "qpid", "qpid.messaging", "qpid.tests",
diff --git a/qpid/specs/management-schema.xml b/qpid/specs/management-schema.xml
index e52e3f23cf..881632c881 100644
--- a/qpid/specs/management-schema.xml
+++ b/qpid/specs/management-schema.xml
@@ -176,6 +176,7 @@
<statistic name="unackedMessages" type="hilo32" unit="message" desc="Messages consumed but not yet acked"/>
<statistic name="messageLatency" type="mmaTime" unit="nanosecond" desc="Broker latency through this queue"/>
<statistic name="flowStopped" type="bool" desc="Flow control active."/>
+ <statistic name="flowStoppedCount" type="count32" desc="Number of times flow control was activated for this queue"/>
<method name="purge" desc="Discard all or some messages on a queue">
<arg name="request" dir="I" type="uint32" desc="0 for all messages or n>0 for n messages"/>
diff --git a/qpid/tests/setup.py b/qpid/tests/setup.py
index 5438275b22..6a99fbb80f 100755
--- a/qpid/tests/setup.py
+++ b/qpid/tests/setup.py
@@ -20,7 +20,7 @@
from distutils.core import setup
setup(name="qpid-tests",
- version="0.9",
+ version="0.11",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
packages=["qpid_tests", "qpid_tests.broker_0_10", "qpid_tests.broker_0_9",
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py b/qpid/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
index 0ffeb57172..8cbb5793d9 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
@@ -18,7 +18,7 @@
#
import traceback
from qpid.queue import Empty
-from qpid.datatypes import Message
+from qpid.datatypes import Message, RangedSet
from qpid.testlib import TestBase010
from qpid.session import SessionException
@@ -77,13 +77,7 @@ class AlternateExchangeTests(TestBase010):
"""
session = self.session
#set up a 'dead letter queue':
- session.exchange_declare(exchange="dlq", type="fanout")
- session.queue_declare(queue="deleted", exclusive=True, auto_delete=True)
- session.exchange_bind(exchange="dlq", queue="deleted")
- session.message_subscribe(destination="dlq", queue="deleted")
- session.message_flow(destination="dlq", unit=session.credit_unit.message, value=0xFFFFFFFFL)
- session.message_flow(destination="dlq", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
- dlq = session.incoming("dlq")
+ dlq = self.setup_dlq()
#create a queue using the dlq as its alternate exchange:
session.queue_declare(queue="delete-me", alternate_exchange="dlq")
@@ -236,6 +230,121 @@ class AlternateExchangeTests(TestBase010):
self.assertEqual("Three", dlq.get(timeout=1).body)
self.assertEmpty(dlq)
+ def test_queue_delete_loop(self):
+ """
+ Test that if a queue is bound to its own alternate exchange,
+ then on deletion there is no infinite looping
+ """
+ session = self.session
+ dlq = self.setup_dlq()
+
+ #create a queue using the dlq as its alternate exchange:
+ session.queue_declare(queue="delete-me", alternate_exchange="dlq")
+ #bind that queue to the dlq as well:
+ session.exchange_bind(exchange="dlq", queue="delete-me")
+ #send it some messages:
+ dp=self.session.delivery_properties(routing_key="delete-me")
+ for m in ["One", "Two", "Three"]:
+ session.message_transfer(message=Message(dp, m))
+ #delete it:
+ session.queue_delete(queue="delete-me")
+ #cleanup:
+ session.exchange_delete(exchange="dlq")
+
+ #check the messages were delivered to the dlq:
+ for m in ["One", "Two", "Three"]:
+ self.assertEqual(m, dlq.get(timeout=1).body)
+ self.assertEmpty(dlq)
+
+ def test_queue_delete_no_match(self):
+ """
+ Test that on queue deletion, if the queues own alternate
+ exchange cannot find a match for the message, the
+ alternate-exchange of that exchange will be tried. Note:
+ though the spec rules out going to the alternate-exchanges
+ alternate exchange when sending to an exchange, it does not
+ cover this case.
+ """
+ session = self.session
+ dlq = self.setup_dlq()
+
+ #setu up an 'intermediary' exchange
+ session.exchange_declare(exchange="my-exchange", type="direct", alternate_exchange="dlq")
+
+ #create a queue using the intermediary as its alternate exchange:
+ session.queue_declare(queue="delete-me", alternate_exchange="my-exchange")
+ #bind that queue to the dlq as well:
+ session.exchange_bind(exchange="dlq", queue="delete-me")
+ #send it some messages:
+ dp=self.session.delivery_properties(routing_key="delete-me")
+ for m in ["One", "Two", "Three"]:
+ session.message_transfer(message=Message(dp, m))
+
+ #delete it:
+ session.queue_delete(queue="delete-me")
+ #cleanup:
+ session.exchange_delete(exchange="my-exchange")
+ session.exchange_delete(exchange="dlq")
+
+ #check the messages were delivered to the dlq:
+ for m in ["One", "Two", "Three"]:
+ self.assertEqual(m, dlq.get(timeout=1).body)
+ self.assertEmpty(dlq)
+
+ def test_reject_no_match(self):
+ """
+ Test that on rejecting a message, if the queues own alternate
+ exchange cannot find a match for the message, the
+ alternate-exchange of that exchange will be tried. Note:
+ though the spec rules out going to the alternate-exchanges
+ alternate exchange when sending to an exchange, it does not
+ cover this case.
+ """
+ session = self.session
+ dlq = self.setup_dlq()
+
+ #setu up an 'intermediary' exchange
+ session.exchange_declare(exchange="my-exchange", type="direct", alternate_exchange="dlq")
+
+ #create a queue using the intermediary as its alternate exchange:
+ session.queue_declare(queue="delivery-queue", alternate_exchange="my-exchange", auto_delete=True)
+ #bind that queue to the dlq as well:
+ session.exchange_bind(exchange="dlq", queue="delivery-queue")
+ #send it some messages:
+ dp=self.session.delivery_properties(routing_key="delivery-queue")
+ for m in ["One", "Two", "Three"]:
+ session.message_transfer(message=Message(dp, m))
+
+ #get and reject those messages:
+ session.message_subscribe(destination="a", queue="delivery-queue")
+ session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
+ incoming = session.incoming("a")
+ for m in ["One", "Two", "Three"]:
+ msg = incoming.get(timeout=1)
+ self.assertEqual(m, msg.body)
+ session.message_reject(RangedSet(msg.id))
+ session.message_cancel(destination="a")
+
+ #check the messages were delivered to the dlq:
+ for m in ["One", "Two", "Three"]:
+ self.assertEqual(m, dlq.get(timeout=1).body)
+ self.assertEmpty(dlq)
+ #cleanup:
+ session.exchange_delete(exchange="my-exchange")
+ session.exchange_delete(exchange="dlq")
+
+ def setup_dlq(self):
+ session = self.session
+ #set up 'dead-letter' handling:
+ session.exchange_declare(exchange="dlq", type="fanout")
+ session.queue_declare(queue="deleted", exclusive=True, auto_delete=True)
+ session.exchange_bind(exchange="dlq", queue="deleted")
+ session.message_subscribe(destination="dlq", queue="deleted")
+ session.message_flow(destination="dlq", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="dlq", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
+ dlq = session.incoming("dlq")
+ return dlq
def assertEmpty(self, queue):
try:
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py b/qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py
index 9a4cfd37d6..f51923fcf3 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py
@@ -448,9 +448,9 @@ class MiscellaneousErrorsTests(TestHelper):
def testTypeNotKnown(self):
try:
self.session.exchange_declare(exchange="test_type_not_known_exchange", type="invalid_type")
- self.fail("Expected 503 for declaration of unknown exchange type.")
+ self.fail("Expected 404 for declaration of unknown exchange type.")
except SessionException, e:
- self.assertEquals(503, e.args[0].error_code)
+ self.assertEquals(404, e.args[0].error_code)
def testDifferentDeclaredType(self):
self.exchange_declare(exchange="test_different_declared_type_exchange", type="direct")
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/extensions.py b/qpid/tests/src/py/qpid_tests/broker_0_10/extensions.py
index 26ea3cb0e9..11e03f8a1c 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/extensions.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/extensions.py
@@ -20,6 +20,8 @@ from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
from qpid.testlib import TestBase010
+from qpid.session import SessionException
+from qpid.datatypes import uuid4
from time import sleep
class ExtensionTests(TestBase010):
@@ -28,10 +30,57 @@ class ExtensionTests(TestBase010):
def test_timed_autodelete(self):
session = self.session
session2 = self.conn.session("another-session")
- session2.queue_declare(queue="my-queue", exclusive=True, auto_delete=True, arguments={"qpid.auto_delete_timeout":5})
+ session2.queue_declare(queue="my-queue", exclusive=True, auto_delete=True, arguments={"qpid.auto_delete_timeout":3})
session2.close()
result = session.queue_query(queue="my-queue")
self.assertEqual("my-queue", result.queue)
sleep(5)
result = session.queue_query(queue="my-queue")
self.assert_(not result.queue)
+
+ def valid_policy_args(self, args, name="test-queue"):
+ try:
+ self.session.queue_declare(queue=name, arguments=args)
+ self.session.queue_delete(queue=name) # cleanup
+ except SessionException, e:
+ self.fail("declare with valid policy args failed: %s" % (args))
+ self.session = self.conn.session("replacement", 2)
+
+ def invalid_policy_args(self, args, name="test-queue"):
+ # go through invalid declare attempts twice to make sure that
+ # the queue doesn't actually get created first time around
+ # even if exception is thrown
+ for i in range(1, 3):
+ try:
+ self.session.queue_declare(queue=name, arguments=args)
+ self.session.queue_delete(queue=name) # cleanup
+ self.fail("declare with invalid policy args suceeded: %s (iteration %d)" % (args, i))
+ except SessionException, e:
+ self.session = self.conn.session(str(uuid4()))
+
+ def test_policy_max_size_as_valid_string(self):
+ self.valid_policy_args({"qpid.max_size":"3"})
+
+ def test_policy_max_count_as_valid_string(self):
+ self.valid_policy_args({"qpid.max_count":"3"})
+
+ def test_policy_max_count_and_size_as_valid_strings(self):
+ self.valid_policy_args({"qpid.max_count":"3","qpid.max_size":"0"})
+
+ def test_policy_negative_count(self):
+ self.invalid_policy_args({"qpid.max_count":-1})
+
+ def test_policy_negative_size(self):
+ self.invalid_policy_args({"qpid.max_size":-1})
+
+ def test_policy_size_as_invalid_string(self):
+ self.invalid_policy_args({"qpid.max_size":"foo"})
+
+ def test_policy_count_as_invalid_string(self):
+ self.invalid_policy_args({"qpid.max_count":"foo"})
+
+ def test_policy_size_as_float(self):
+ self.invalid_policy_args({"qpid.max_size":3.14159})
+
+ def test_policy_count_as_float(self):
+ self.invalid_policy_args({"qpid.max_count":"2222222.22222"})
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/management.py b/qpid/tests/src/py/qpid_tests/broker_0_10/management.py
index 06f3212a6f..952878e0b7 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/management.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/management.py
@@ -242,6 +242,38 @@ class ManagementTest (TestBase010):
pq = self.qmf.getObjects(_class="queue", name="purge-queue")[0]
self.assertEqual (pq.msgDepth,0)
+ def test_reroute_priority_queue(self):
+ self.startQmf()
+ session = self.session
+
+ #setup test queue supporting multiple priority levels
+ session.queue_declare(queue="test-queue", exclusive=True, auto_delete=True, arguments={'x-qpid-priorities':10})
+
+ #send some messages of varying priority to that queue:
+ for i in range(0, 5):
+ deliveryProps = session.delivery_properties(routing_key="test-queue", priority=i+5)
+ session.message_transfer(message=Message(deliveryProps, "Message %d" % (i+1)))
+
+
+ #declare and bind a queue to amq.fanout through which rerouted
+ #messages can be verified:
+ session.queue_declare(queue="rerouted", exclusive=True, auto_delete=True, arguments={'x-qpid-priorities':10})
+ session.exchange_bind(queue="rerouted", exchange="amq.fanout")
+
+ #reroute messages from test queue to amq.fanout (and hence to
+ #rerouted queue):
+ pq = self.qmf.getObjects(_class="queue", name="test-queue")[0]
+ result = pq.reroute(0, False, "amq.fanout")
+ self.assertEqual(result.status, 0)
+
+ #verify messages are all rerouted:
+ self.subscribe(destination="incoming", queue="rerouted")
+ incoming = session.incoming("incoming")
+ for i in range(0, 5):
+ msg = incoming.get(timeout=1)
+ self.assertEqual("Message %d" % (5-i), msg.body)
+
+
def test_reroute_queue(self):
"""
Test ability to reroute messages from the head of a queue.
@@ -309,7 +341,40 @@ class ManagementTest (TestBase010):
self.assertEqual(result.status, 0)
pq.update()
self.assertEqual(pq.msgDepth,20)
-
+
+ def test_reroute_alternate_exchange(self):
+ """
+ Test that when rerouting, the alternate-exchange is considered if relevant
+ """
+ self.startQmf()
+ session = self.session
+ # 1. Create 2 exchanges A and B (fanout) where B is the
+ # alternate exchange for A
+ session.exchange_declare(exchange="B", type="fanout")
+ session.exchange_declare(exchange="A", type="fanout", alternate_exchange="B")
+
+ # 2. Bind queue X to B
+ session.queue_declare(queue="X", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="X", exchange="B")
+
+ # 3. Send 1 message to queue Y
+ session.queue_declare(queue="Y", exclusive=True, auto_delete=True)
+ props = session.delivery_properties(routing_key="Y")
+ session.message_transfer(message=Message(props, "reroute me!"))
+
+ # 4. Call reroute on queue Y and specify that messages should
+ # be sent to exchange A
+ y = self.qmf.getObjects(_class="queue", name="Y")[0]
+ result = y.reroute(1, False, "A")
+ self.assertEqual(result.status, 0)
+
+ # 5. verify that the message is rerouted through B (as A has
+ # no matching bindings) to X
+ self.subscribe(destination="x", queue="X")
+ self.assertEqual("reroute me!", session.incoming("x").get(timeout=1).body)
+
+ # Cleanup
+ for e in ["A", "B"]: session.exchange_delete(exchange=e)
def test_methods_async (self):
"""
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/message.py b/qpid/tests/src/py/qpid_tests/broker_0_10/message.py
index e80333a1e6..b46c446833 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/message.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/message.py
@@ -245,9 +245,19 @@ class MessageTests(TestBase010):
self.fail("Got message after cancellation: " + msg)
except Empty: None
- #cancellation of non-existant consumers should be handled without error
- session.message_cancel(destination="my-consumer")
- session.message_cancel(destination="this-never-existed")
+ #cancellation of non-existant consumers should be result in 404s
+ try:
+ session.message_cancel(destination="my-consumer")
+ self.fail("Expected 404 for recancellation of subscription.")
+ except SessionException, e:
+ self.assertEquals(404, e.args[0].error_code)
+
+ session = self.conn.session("alternate-session", timeout=10)
+ try:
+ session.message_cancel(destination="this-never-existed")
+ self.fail("Expected 404 for cancellation of unknown subscription.")
+ except SessionException, e:
+ self.assertEquals(404, e.args[0].error_code)
def test_ack(self):
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/priority.py b/qpid/tests/src/py/qpid_tests/broker_0_10/priority.py
index 3651a1218b..6a60add97e 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/priority.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/priority.py
@@ -33,13 +33,13 @@ class PriorityTests (Base):
def setup_session(self):
return self.conn.session()
- def prioritised_delivery(self, priorities, levels=10):
+ def prioritised_delivery(self, priorities, levels=10, key="x-qpid-priorities"):
"""
Test that message on a queue are delivered in priority order.
"""
msgs = [Message(content=str(uuid4()), priority = p) for p in priorities]
- snd = self.ssn.sender("priority-queue; {create: sender, delete: receiver, node: {x-declare:{arguments:{x-qpid-priorities:%s}}}}" % levels,
+ snd = self.ssn.sender("priority-queue; {create: sender, delete: receiver, node: {x-declare:{arguments:{'%s':%s}}}}" % (key, levels),
durable=self.durable())
for m in msgs: snd.send(m)
@@ -50,16 +50,16 @@ class PriorityTests (Base):
assert msg.content == expected.content
self.ssn.acknowledge(msg)
- def fairshare_delivery(self, priorities, default_limit=5, limits=None, levels=10):
+ def fairshare_delivery(self, priorities, default_limit=5, limits=None, levels=10, level_key="x-qpid-priorities", fairshare_key="x-qpid-fairshare"):
msgs = [Message(content=str(uuid4()), priority = p) for p in priorities]
- limit_policy = "x-qpid-fairshare:%s" % default_limit
+ limit_policy = "'%s':%s" % (fairshare_key, default_limit)
if limits:
for k, v in limits.items():
- limit_policy += ", x-qpid-fairshare-%s:%s" % (k, v)
+ limit_policy += ", '%s-%s':%s" % (fairshare_key, k, v)
- snd = self.ssn.sender("priority-queue; {create: sender, delete: receiver, node: {x-declare:{arguments:{x-qpid-priorities:%s, %s}}}}"
- % (levels, limit_policy),
+ snd = self.ssn.sender("priority-queue; {create: sender, delete: receiver, node: {x-declare:{arguments:{'%s':%s, %s}}}}"
+ % (level_key, levels, limit_policy),
durable=self.durable())
for m in msgs: snd.send(m)
@@ -79,12 +79,18 @@ class PriorityTests (Base):
def test_prioritised_delivery_1(self):
self.prioritised_delivery(priorities = [8,9,5,1,2,2,3,4,15,7,8,10,10,2], levels = 10)
+ def test_prioritised_delivery_with_alias(self):
+ self.prioritised_delivery(priorities = [8,9,5,1,2,2,3,4,15,7,8,10,10,2], levels = 10, key="qpid.priorities")
+
def test_prioritised_delivery_2(self):
self.prioritised_delivery(priorities = [8,9,5,1,2,2,3,4,15,7,8,10,10,2], levels = 5)
def test_fairshare_1(self):
self.fairshare_delivery(priorities = [4,5,3,6,10,10,2,10,2,10,10,1,10,10,10,3,3,3,10,10,3,10,3,10,10,10,10,10,10,2,3])
+ def test_fairshare_with_alias(self):
+ self.fairshare_delivery(priorities = [4,5,3,6,10,10,2,10,2,10,10,1,10,10,10,3,3,3,10,10,2,3], level_key="qpid.priorities", fairshare_key="qpid.fairshare")
+
def test_fairshare_2(self):
self.fairshare_delivery(priorities = [10 for i in range(30)])
diff --git a/qpid/tests/src/py/qpid_tests/broker_0_10/threshold.py b/qpid/tests/src/py/qpid_tests/broker_0_10/threshold.py
index bcd3c507e2..6628ae8424 100644
--- a/qpid/tests/src/py/qpid_tests/broker_0_10/threshold.py
+++ b/qpid/tests/src/py/qpid_tests/broker_0_10/threshold.py
@@ -60,3 +60,18 @@ class ThresholdTests (Base):
def test_alert_size_alias(self):
self.do_threshold_test("x-qpid-maximum-message-size", 15, [Message("msg-%s" % i) for i in range(3)])
+
+ def test_alert_on_alert_queue(self):
+ rcv = self.ssn.receiver("qmf.default.topic/agent.ind.event.org_apache_qpid_broker.queueThresholdExceeded.#; {link:{x-declare:{arguments:{'qpid.alert_count':1}}}}")
+ rcvQMFv1 = self.ssn.receiver("qpid.management/console.event.#; {link:{x-declare:{arguments:{'qpid.alert_count':1}}}}")
+ snd = self.ssn.sender("ttq; {create:always, node: {x-declare:{auto_delete:True,exclusive:True,arguments:{'qpid.alert_count':1}}}}")
+ snd.send(Message("my-message"))
+ queues = []
+ for i in range(2):
+ event = rcv.fetch()
+ schema = event.content[0]["_schema_id"]
+ assert schema["_class_name"] == "queueThresholdExceeded"
+ values = event.content[0]["_values"]
+ queues.append(values["qName"])
+ assert "ttq" in queues, "expected event for ttq (%s)" % (queues)
+
diff --git a/qpid/tools/setup.py b/qpid/tools/setup.py
index 8811e49682..58863a07d9 100755
--- a/qpid/tools/setup.py
+++ b/qpid/tools/setup.py
@@ -20,7 +20,7 @@
from distutils.core import setup
setup(name="qpid-tools",
- version="0.9",
+ version="0.11",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
scripts=["src/py/qpid-cluster",
@@ -30,7 +30,8 @@ setup(name="qpid-tools",
"src/py/qpid-queue-stats",
"src/py/qpid-route",
"src/py/qpid-stat",
- "src/py/qpid-tool"],
+ "src/py/qpid-tool",
+ "src/py/qmf-tool"],
url="http://qpid.apache.org/",
license="Apache Software License",
description="Diagnostic and management tools for Apache Qpid brokers.")
diff --git a/qpid/tools/src/py/qpid-config b/qpid/tools/src/py/qpid-config
index 9ff405541c..da490e831a 100755
--- a/qpid/tools/src/py/qpid-config
+++ b/qpid/tools/src/py/qpid-config
@@ -101,6 +101,7 @@ class Config:
self._flowResumeCount = None
self._flowStopSize = None
self._flowResumeSize = None
+ self._extra_arguments = []
config = Config()
@@ -119,6 +120,13 @@ FLOW_STOP_COUNT = "qpid.flow_stop_count"
FLOW_RESUME_COUNT = "qpid.flow_resume_count"
FLOW_STOP_SIZE = "qpid.flow_stop_size"
FLOW_RESUME_SIZE = "qpid.flow_resume_size"
+#There are various arguments to declare that have specific program
+#options in this utility. However there is now a generic mechanism for
+#passing arguments as well. The SPECIAL_ARGS list contains the
+#arguments for which there are specific program options defined
+#i.e. the arguments for which there is special processing on add and
+#list
+SPECIAL_ARGS=[FILECOUNT,FILESIZE,MAX_QUEUE_SIZE,MAX_QUEUE_COUNT,POLICY_TYPE,CLUSTER_DURABLE,LVQ,LVQNB,MSG_SEQUENCE,IVE,QUEUE_EVENT_GENERATION,FLOW_STOP_COUNT,FLOW_STOP_SIZE,FLOW_RESUME_SIZE]
class JHelpFormatter(IndentedHelpFormatter):
"""Format usage and description without stripping newlines from usage strings
@@ -178,6 +186,8 @@ def OptionsAndArguments(argv):
help="Turn on sender flow control when the number of queued messages exceeds this value.")
group3.add_option("--flow-resume-count", action="store", type="int", metavar="<n>",
help="Turn off sender flow control when the number of queued messages drops below this value.")
+ group3.add_option("--argument", dest="extra_arguments", action="append", default=[],
+ metavar="<NAME=VALUE>", help="Specify a key-value pair to add to queue arguments")
# no option for declaring an exclusive queue - which can only be used by the session that creates it.
parser.add_option_group(group3)
@@ -257,6 +267,8 @@ def OptionsAndArguments(argv):
config._flowStopCount = opts.flow_stop_count
if opts.flow_resume_count:
config._flowResumeCount = opts.flow_resume_count
+ if opts.extra_arguments:
+ config._extra_arguments = opts.extra_arguments
return args
@@ -360,6 +372,7 @@ class BrokerManager:
if self.match(ex.name, filter):
print "%-10s%-*s " % (ex.type, maxNameLen, ex.name),
args = ex.arguments
+ if not args: args = {}
if ex.durable: print "--durable",
if MSG_SEQUENCE in args and args[MSG_SEQUENCE] == 1: print "--sequence",
if IVE in args and args[IVE] == 1: print "--ive",
@@ -401,25 +414,26 @@ class BrokerManager:
if self.match(q.name, filter):
print "%-*s " % (maxNameLen, q.name),
args = q.arguments
+ if not args: args = {}
if q.durable: print "--durable",
if CLUSTER_DURABLE in args and args[CLUSTER_DURABLE] == 1: print "--cluster-durable",
if q.autoDelete: print "auto-del",
if q.exclusive: print "excl",
- if FILESIZE in args: print "--file-size=%d" % args[FILESIZE],
- if FILECOUNT in args: print "--file-count=%d" % args[FILECOUNT],
- if MAX_QUEUE_SIZE in args: print "--max-queue-size=%d" % args[MAX_QUEUE_SIZE],
- if MAX_QUEUE_COUNT in args: print "--max-queue-count=%d" % args[MAX_QUEUE_COUNT],
+ if FILESIZE in args: print "--file-size=%s" % args[FILESIZE],
+ if FILECOUNT in args: print "--file-count=%s" % args[FILECOUNT],
+ if MAX_QUEUE_SIZE in args: print "--max-queue-size=%s" % args[MAX_QUEUE_SIZE],
+ if MAX_QUEUE_COUNT in args: print "--max-queue-count=%s" % args[MAX_QUEUE_COUNT],
if POLICY_TYPE in args: print "--limit-policy=%s" % args[POLICY_TYPE].replace("_", "-"),
if LVQ in args and args[LVQ] == 1: print "--order lvq",
if LVQNB in args and args[LVQNB] == 1: print "--order lvq-no-browse",
- if QUEUE_EVENT_GENERATION in args: print "--generate-queue-events=%d" % args[QUEUE_EVENT_GENERATION],
+ if QUEUE_EVENT_GENERATION in args: print "--generate-queue-events=%s" % args[QUEUE_EVENT_GENERATION],
if q.altExchange:
print "--alternate-exchange=%s" % q._altExchange_.name,
- if FLOW_STOP_SIZE in args: print "--flow-stop-size=%d" % args[FLOW_STOP_SIZE],
- if FLOW_RESUME_SIZE in args: print "--flow-resume-size=%d" % args[FLOW_RESUME_SIZE],
- if FLOW_STOP_COUNT in args: print "--flow-stop-count=%d" % args[FLOW_STOP_COUNT],
- if FLOW_RESUME_COUNT in args: print "--flow-resume-count=%d" % args[FLOW_RESUME_COUNT],
- print
+ if FLOW_STOP_SIZE in args: print "--flow-stop-size=%s" % args[FLOW_STOP_SIZE],
+ if FLOW_RESUME_SIZE in args: print "--flow-resume-size=%s" % args[FLOW_RESUME_SIZE],
+ if FLOW_STOP_COUNT in args: print "--flow-stop-count=%s" % args[FLOW_STOP_COUNT],
+ if FLOW_RESUME_COUNT in args: print "--flow-resume-count=%s" % args[FLOW_RESUME_COUNT],
+ print " ".join(["--argument %s=%s" % (k, v) for k,v in args.iteritems() if not k in SPECIAL_ARGS])
def QueueListRecurse(self, filter):
exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent)
@@ -464,6 +478,12 @@ class BrokerManager:
Usage()
qname = args[0]
declArgs = {}
+ for a in config._extra_arguments:
+ r = a.split("=", 1)
+ if len(r) == 2: value = r[1]
+ else: value = None
+ declArgs[r[0]] = value
+
if config._durable:
declArgs[FILECOUNT] = config._fileCount
declArgs[FILESIZE] = config._fileSize
diff --git a/qpid/tools/src/py/qpid-printevents b/qpid/tools/src/py/qpid-printevents
index 2be2f0be8b..d56d2899b1 100755
--- a/qpid/tools/src/py/qpid-printevents
+++ b/qpid/tools/src/py/qpid-printevents
@@ -20,7 +20,7 @@
#
import os
-import optparse
+import optparse
from optparse import IndentedHelpFormatter
import sys
import socket
@@ -62,11 +62,11 @@ _usage = "%prog [options] [broker-addr]..."
_description = \
"""
-Collect and print events from one or more Qpid message brokers.
+Collect and print events from one or more Qpid message brokers.
If no broker-addr is supplied, %prog connects to 'localhost:5672'.
-[broker-addr] syntax:
+[broker-addr] syntax:
[username/password@] hostname
ip-address [:<port>]
@@ -91,20 +91,20 @@ def main(argv=None):
session = Session(console, rcvObjects=False, rcvHeartbeats=options.heartbeats, manageConnections=True)
brokers = []
try:
- for host in arguments:
- brokers.append(session.addBroker(host, None, options.sasl_mechanism))
+ try:
+ for host in arguments:
+ brokers.append(session.addBroker(host, None, options.sasl_mechanism))
- while (True):
- sleep(10)
+ while (True):
+ sleep(10)
- except KeyboardInterrupt:
- print
- return 0
-
- except Exception, e:
- print "Failed: %s - %s" % (e.__class__.__name__, e)
- return 1
+ except KeyboardInterrupt:
+ print
+ return 0
+ except Exception, e:
+ print "Failed: %s - %s" % (e.__class__.__name__, e)
+ return 1
finally:
while len(brokers):
b = brokers.pop()
diff --git a/qpid/tools/src/py/qpid-route b/qpid/tools/src/py/qpid-route
index 3c4de85d1e..516c02d5cd 100755
--- a/qpid/tools/src/py/qpid-route
+++ b/qpid/tools/src/py/qpid-route
@@ -27,18 +27,18 @@ import locale
from qmf.console import Session, BrokerURL
usage = """
-Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list]
+Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list] [mechanism]
qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange>
qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list] [mechanism]
qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key>
- qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue>
+ qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue> [mechanism]
qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue>
qpid-route [OPTIONS] route list [<dest-broker>]
qpid-route [OPTIONS] route flush [<dest-broker>]
qpid-route [OPTIONS] route map [<broker>]
- qpid-route [OPTIONS] link add <dest-broker> <src-broker>
+ qpid-route [OPTIONS] link add <dest-broker> <src-broker> [mechanism]
qpid-route [OPTIONS] link del <dest-broker> <src-broker>
qpid-route [OPTIONS] link list [<dest-broker>]"""
@@ -61,7 +61,7 @@ class Config:
self._transport = "tcp"
self._ack = 0
self._connTimeout = 10
- self._sasl_mechanism = None
+ self._client_sasl_mechanism = None
config = Config()
@@ -95,7 +95,7 @@ def OptionsAndArguments(argv):
parser.add_option("--ack", action="store", type="int", metavar="<n>", help="Acknowledge transfers over the bridge in batches of N")
parser.add_option("-t", "--transport", action="store", type="string", default="tcp", metavar="<transport>", help="Transport to use for links, defaults to tcp")
- parser.add_option("--sasl-mechanism", action="store", type="string", metavar="<mech>", help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD, DIGEST-MD5, GSSAPI). Used when the client connects to the destination broker (not for authentication between the source and destination brokers - that is specified using the [mechanisms] argument to 'add route'). SASL automatically picks the most secure available mechanism - use this option to override.")
+ parser.add_option("--client-sasl-mechanism", action="store", type="string", metavar="<mech>", help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD, DIGEST-MD5, GSSAPI). Used when the client connects to the destination broker (not for authentication between the source and destination brokers - that is specified using the [mechanisms] argument to 'add route'). SASL automatically picks the most secure available mechanism - use this option to override.")
opts, encArgs = parser.parse_args(args=argv)
@@ -131,8 +131,8 @@ def OptionsAndArguments(argv):
if opts.ack:
config._ack = opts.ack
- if opts.sasl_mechanism:
- config._sasl_mechanism = opts.sasl_mechanism
+ if opts.client_sasl_mechanism:
+ config._client_sasl_mechanism = opts.client_sasl_mechanism
return args
@@ -143,7 +143,7 @@ class RouteManager:
self.local = BrokerURL(localBroker)
self.remote = None
self.qmf = Session()
- self.broker = self.qmf.addBroker(localBroker, config._connTimeout, config._sasl_mechanism)
+ self.broker = self.qmf.addBroker(localBroker, config._connTimeout, config._client_sasl_mechanism)
self.broker._waitForStable()
self.agent = self.broker.getBrokerAgent()
@@ -166,7 +166,7 @@ class RouteManager:
return link
return None
- def addLink(self, remoteBroker, mech="PLAIN"):
+ def addLink(self, remoteBroker, interbroker_mechanism=""):
self.remote = BrokerURL(remoteBroker)
if self.local.match(self.remote.host, self.remote.port):
raise Exception("Linking broker to itself is not permitted")
@@ -176,7 +176,7 @@ class RouteManager:
link = self.getLink()
if link == None:
res = broker.connect(self.remote.host, self.remote.port, config._durable,
- mech, self.remote.authName or "", self.remote.authPass or "",
+ interbroker_mechanism, self.remote.authName or "", self.remote.authPass or "",
config._transport)
if config._verbose:
print "Connect method returned:", res.status, res.text
@@ -295,11 +295,11 @@ class RouteManager:
if b[0] != self.local.name():
self.qmf.delBroker(b[1])
- def addRoute(self, remoteBroker, exchange, routingKey, tag, excludes, mech="PLAIN", dynamic=False):
+ def addRoute(self, remoteBroker, exchange, routingKey, tag, excludes, interbroker_mechanism="", dynamic=False):
if dynamic and config._srclocal:
raise Exception("--src-local is not permitted on dynamic routes")
- self.addLink(remoteBroker, mech)
+ self.addLink(remoteBroker, interbroker_mechanism)
link = self.getLink()
if link == None:
raise Exception("Link failed to create")
@@ -320,8 +320,8 @@ class RouteManager:
if config._verbose:
print "Bridge method returned:", res.status, res.text
- def addQueueRoute(self, remoteBroker, exchange, queue):
- self.addLink(remoteBroker)
+ def addQueueRoute(self, remoteBroker, interbroker_mechanism, exchange, queue ):
+ self.addLink(remoteBroker, interbroker_mechanism)
link = self.getLink()
if link == None:
raise Exception("Link failed to create")
@@ -504,10 +504,12 @@ def main(argv=None):
rm = RouteManager(localBroker)
if group == "link":
if cmd == "add":
- if nargs != 4:
+ if nargs < 3 or nargs > 5:
Usage()
return(-1)
- rm.addLink(remoteBroker)
+ interbroker_mechanism = ""
+ if nargs > 4: interbroker_mechanism = args[4]
+ rm.addLink(remoteBroker, interbroker_mechanism)
elif cmd == "del":
if nargs != 4:
Usage()
@@ -518,16 +520,17 @@ def main(argv=None):
elif group == "dynamic":
if cmd == "add":
- if nargs < 5 or nargs > 7:
+ if nargs < 5 or nargs > 8:
Usage()
return(-1)
tag = ""
excludes = ""
- mech = "PLAIN"
+ interbroker_mechanism = ""
if nargs > 5: tag = args[5]
if nargs > 6: excludes = args[6]
- rm.addRoute(remoteBroker, args[4], "", tag, excludes, mech, dynamic=True)
+ if nargs > 7: interbroker_mechanism = args[7]
+ rm.addRoute(remoteBroker, args[4], "", tag, excludes, interbroker_mechanism, dynamic=True)
elif cmd == "del":
if nargs != 5:
Usage()
@@ -543,11 +546,11 @@ def main(argv=None):
tag = ""
excludes = ""
- mech = "PLAIN"
+ interbroker_mechanism = ""
if nargs > 6: tag = args[6]
if nargs > 7: excludes = args[7]
- if nargs > 8: mech = args[8]
- rm.addRoute(remoteBroker, args[4], args[5], tag, excludes, mech, dynamic=False)
+ if nargs > 8: interbroker_mechanism = args[8]
+ rm.addRoute(remoteBroker, args[4], args[5], tag, excludes, interbroker_mechanism, dynamic=False)
elif cmd == "del":
if nargs != 6:
Usage()
@@ -565,11 +568,13 @@ def main(argv=None):
return(-1)
elif group == "queue":
- if nargs != 6:
+ if nargs < 6 or nargs > 7:
Usage()
return(-1)
if cmd == "add":
- rm.addQueueRoute(remoteBroker, exchange=args[4], queue=args[5])
+ interbroker_mechanism = ""
+ if nargs > 6: interbroker_mechanism = args[6]
+ rm.addQueueRoute(remoteBroker, interbroker_mechanism, exchange=args[4], queue=args[5] )
elif cmd == "del":
rm.delQueueRoute(remoteBroker, exchange=args[4], queue=args[5])
else:
diff --git a/qpid/tools/src/py/qpid-tool b/qpid/tools/src/py/qpid-tool
index d3b0aa4097..2a06dae6ac 100755
--- a/qpid/tools/src/py/qpid-tool
+++ b/qpid/tools/src/py/qpid-tool
@@ -259,7 +259,24 @@ class QmfData(Console):
return
displayId = long(tokens[0])
methodName = tokens[1]
- args = tokens[2:]
+ args = []
+ for arg in tokens[2:]:
+ ##
+ ## If the argument is a map, list, boolean, integer, or floating (one decimal point),
+ ## run it through the Python evaluator so it is converted to the correct type.
+ ##
+ ## TODO: use a regex for this instead of this convoluted logic,
+ ## or even consider passing all args through eval() [which would
+ ## be a minor change to the nterface as string args would then
+ ## always need to be quoted as strings within a map/list would
+ ## now]
+ if arg[0] == '{' or arg[0] == '[' or arg == "True" or arg == "False" or \
+ ((arg.count('.') < 2 and (arg.count('-') == 0 or \
+ (arg.count('-') == 1 and arg[0] == '-')) and \
+ arg.replace('.','').replace('-','').isdigit())):
+ args.append(eval(arg))
+ else:
+ args.append(arg)
obj = None
try: