summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Anthony Giusti <kgiusti@apache.org>2010-03-23 18:00:49 +0000
committerKenneth Anthony Giusti <kgiusti@apache.org>2010-03-23 18:00:49 +0000
commitf7e909f3ec86b1330c74abc9014103c1201eb502 (patch)
treea064c60f5aec628f9ccf532fab5659f44c6ddf4c
parent759668f3c17006cf3f8bd13fed3003fee1e98dae (diff)
downloadqpid-python-f7e909f3ec86b1330c74abc9014103c1201eb502.tar.gz
merge r919024:926606 trunk into this branch
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qmf-devel0.7a@926686 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/QPID_VERSION.txt1
-rw-r--r--qpid/cpp/.gitignore1
-rw-r--r--qpid/cpp/BuildInstallSettings.cmake13
-rw-r--r--qpid/cpp/CMakeLists.txt31
-rw-r--r--qpid/cpp/INSTALL2
-rw-r--r--qpid/cpp/Makefile.am2
-rw-r--r--qpid/cpp/SSL20
-rw-r--r--qpid/cpp/bld-winsdk.ps1121
-rwxr-xr-xqpid/cpp/bootstrap7
-rw-r--r--qpid/cpp/configure.ac22
-rw-r--r--qpid/cpp/docs/api/CMakeLists.txt5
-rw-r--r--qpid/cpp/docs/src/CONTENTS12
-rw-r--r--qpid/cpp/docs/src/DispatchHandle.odgbin0 -> 12481 bytes
-rw-r--r--qpid/cpp/examples/README.txt22
-rw-r--r--qpid/cpp/examples/examples.sln12
-rw-r--r--qpid/cpp/examples/messaging/client.cpp3
-rw-r--r--qpid/cpp/examples/messaging/drain.cpp3
-rw-r--r--qpid/cpp/examples/messaging/map_receiver.cpp3
-rw-r--r--qpid/cpp/examples/messaging/map_sender.cpp4
-rw-r--r--qpid/cpp/examples/messaging/queue_receiver.cpp3
-rw-r--r--qpid/cpp/examples/messaging/queue_sender.cpp4
-rw-r--r--qpid/cpp/examples/messaging/server.cpp3
-rw-r--r--qpid/cpp/examples/messaging/spout.cpp3
-rw-r--r--qpid/cpp/examples/messaging/topic_receiver.cpp3
-rw-r--r--qpid/cpp/examples/messaging/topic_sender.cpp3
-rw-r--r--qpid/cpp/examples/pub-sub/verify_python_cpp.in8
-rwxr-xr-xqpid/cpp/examples/verify1
-rwxr-xr-xqpid/cpp/examples/verify_all2
-rw-r--r--qpid/cpp/include/qpid/agent/QmfAgentImportExport.h2
-rw-r--r--qpid/cpp/include/qpid/client/amqp0_10/FailoverUpdates.h55
-rw-r--r--qpid/cpp/include/qpid/framing/FieldValue.h10
-rw-r--r--qpid/cpp/include/qpid/messaging/Address.h19
-rw-r--r--qpid/cpp/include/qpid/messaging/Codec.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Connection.h47
-rw-r--r--qpid/cpp/include/qpid/messaging/Handle.h71
-rw-r--r--qpid/cpp/include/qpid/messaging/ImportExport.h33
-rw-r--r--qpid/cpp/include/qpid/messaging/ListContent.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/ListView.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/MapContent.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/MapView.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Message.h6
-rw-r--r--qpid/cpp/include/qpid/messaging/Receiver.h27
-rw-r--r--qpid/cpp/include/qpid/messaging/Sender.h15
-rw-r--r--qpid/cpp/include/qpid/messaging/Session.h40
-rw-r--r--qpid/cpp/include/qpid/messaging/Uuid.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Variant.h2
-rwxr-xr-xqpid/cpp/managementgen/qmfgen/schema.py15
-rw-r--r--qpid/cpp/src/CMakeLists.txt39
-rw-r--r--qpid/cpp/src/Makefile.am22
-rwxr-xr-xqpid/cpp/src/qpid/Version.h8
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp22
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp8
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.h11
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionFactory.cpp10
-rw-r--r--qpid/cpp/src/qpid/broker/ConnectionFactory.h5
-rw-r--r--qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp9
-rw-r--r--qpid/cpp/src/qpid/broker/HeadersExchange.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp5
-rw-r--r--qpid/cpp/src/qpid/broker/Message.cpp27
-rw-r--r--qpid/cpp/src/qpid/broker/Message.h5
-rw-r--r--qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp22
-rw-r--r--qpid/cpp/src/qpid/broker/SecureConnectionFactory.cpp10
-rw-r--r--qpid/cpp/src/qpid/broker/SecureConnectionFactory.h5
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.cpp2
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionHandler.h9
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionImpl.cpp14
-rw-r--r--qpid/cpp/src/qpid/client/Connector.h3
-rw-r--r--qpid/cpp/src/qpid/client/RdmaConnector.cpp2
-rw-r--r--qpid/cpp/src/qpid/client/Sasl.h14
-rw-r--r--qpid/cpp/src/qpid/client/SaslFactory.cpp21
-rw-r--r--qpid/cpp/src/qpid/client/SslConnector.cpp11
-rw-r--r--qpid/cpp/src/qpid/client/TCPConnector.cpp13
-rw-r--r--qpid/cpp/src/qpid/client/TCPConnector.h2
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp32
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp152
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h21
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/FailoverUpdates.cpp84
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp18
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h7
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp14
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h7
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp12
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h3
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp79
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h42
-rw-r--r--qpid/cpp/src/qpid/client/windows/SaslFactory.cpp6
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.cpp129
-rw-r--r--qpid/cpp/src/qpid/cluster/Cluster.h9
-rw-r--r--qpid/cpp/src/qpid/cluster/Connection.cpp27
-rw-r--r--qpid/cpp/src/qpid/cluster/Connection.h17
-rw-r--r--qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp14
-rw-r--r--qpid/cpp/src/qpid/cluster/ConnectionCodec.h6
-rw-r--r--qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp32
-rw-r--r--qpid/cpp/src/qpid/cluster/InitialStatusMap.h20
-rw-r--r--qpid/cpp/src/qpid/cluster/Multicaster.cpp21
-rw-r--r--qpid/cpp/src/qpid/cluster/Multicaster.h23
-rw-r--r--qpid/cpp/src/qpid/cluster/PollableQueue.h20
-rw-r--r--qpid/cpp/src/qpid/cluster/StoreStatus.cpp39
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateClient.cpp6
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.cpp15
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp105
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.h29
-rw-r--r--qpid/cpp/src/qpid/management/ManagementDirectExchange.cpp63
-rw-r--r--qpid/cpp/src/qpid/management/ManagementDirectExchange.h59
-rw-r--r--qpid/cpp/src/qpid/management/ManagementExchange.cpp72
-rw-r--r--qpid/cpp/src/qpid/management/ManagementTopicExchange.cpp76
-rw-r--r--qpid/cpp/src/qpid/management/ManagementTopicExchange.h (renamed from qpid/cpp/src/qpid/management/ManagementExchange.h)29
-rw-r--r--qpid/cpp/src/qpid/messaging/AddressParser.cpp1
-rw-r--r--qpid/cpp/src/qpid/messaging/Connection.cpp49
-rw-r--r--qpid/cpp/src/qpid/messaging/ConnectionImpl.h5
-rw-r--r--qpid/cpp/src/qpid/messaging/PrivateImplRef.h94
-rw-r--r--qpid/cpp/src/qpid/messaging/Receiver.cpp12
-rw-r--r--qpid/cpp/src/qpid/messaging/ReceiverImpl.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/Sender.cpp13
-rw-r--r--qpid/cpp/src/qpid/messaging/SenderImpl.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/Session.cpp12
-rw-r--r--qpid/cpp/src/qpid/messaging/SessionImpl.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/Variant.cpp8
-rw-r--r--qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp5
-rw-r--r--qpid/cpp/src/qpid/sys/ConnectionCodec.h17
-rw-r--r--qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp5
-rw-r--r--qpid/cpp/src/qpid/sys/SecuritySettings.h58
-rw-r--r--qpid/cpp/src/qpid/sys/SslPlugin.cpp17
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp16
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslHandler.h4
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslIo.cpp7
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslIo.h3
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp49
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslSocket.h1
-rw-r--r--qpid/cpp/src/qpid/xml/XmlExchange.cpp12
-rw-r--r--qpid/cpp/src/tests/ClusterFixture.cpp4
-rw-r--r--qpid/cpp/src/tests/InitialStatusMap.cpp22
-rw-r--r--qpid/cpp/src/tests/Makefile.am4
-rw-r--r--qpid/cpp/src/tests/MessagingSessionTests.cpp10
-rw-r--r--qpid/cpp/src/tests/Variant.cpp15
-rw-r--r--qpid/cpp/src/tests/cluster_tests.fail2
-rwxr-xr-xqpid/cpp/src/tests/cluster_tests.py94
-rw-r--r--qpid/cpp/src/tests/qpid_recv.cpp11
-rw-r--r--qpid/cpp/src/tests/qpid_send.cpp17
-rw-r--r--qpid/cpp/src/tests/qpid_stream.cpp34
-rw-r--r--qpid/cpp/src/tests/quick_topictest.ps14
-rw-r--r--qpid/cpp/src/tests/testagent.cpp (renamed from qpid/cpp/src/tests/testagent/testagent.cpp)0
-rw-r--r--qpid/cpp/src/tests/testagent.mk51
-rw-r--r--qpid/cpp/src/tests/testagent.xml (renamed from qpid/cpp/src/tests/testagent/schema.xml)0
-rw-r--r--qpid/cpp/src/tests/testagent/Makefile.am50
-rw-r--r--qpid/cpp/src/tests/topictest.ps119
-rw-r--r--qpid/cpp/xml/cluster.xml5
-rw-r--r--qpid/doc/book/Makefile42
-rw-r--r--qpid/doc/book/README.txt118
-rwxr-xr-xqpid/doc/book/build.sh22
-rw-r--r--qpid/doc/book/build.xml173
-rw-r--r--qpid/doc/book/src/SASL-Compatibility.xml14
-rw-r--r--qpid/doc/book/src/schemas.xml102
-rw-r--r--qpid/dotnet/TestClient/TestClient.csproj4
-rw-r--r--qpid/dotnet/TopicListener/TopicListener.csproj4
-rw-r--r--qpid/dotnet/TopicPublisher/TopicPublisher.csproj4
-rw-r--r--qpid/extras/qmf/.gitignore1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java50
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java9
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java31
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java25
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java109
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java172
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java70
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java70
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java24
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java30
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java33
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java41
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java19
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java48
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java127
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java16
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java23
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java15
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java126
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java16
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java86
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java8
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java102
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java21
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java34
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java143
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java80
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java38
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java56
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java15
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java120
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java8
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java10
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java12
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java185
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java80
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java (renamed from qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java)18
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java (renamed from qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java)16
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java177
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java161
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java8
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java1
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java28
-rwxr-xr-xqpid/java/test-profiles/CPPExcludes5
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/CA_db/cert8.dbbin0 -> 65536 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/CA_db/key3.dbbin0 -> 16384 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/CA_db/rootca.crt13
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/CA_db/secmod.dbbin0 -> 16384 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/app1.crt15
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/app1.req10
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/app2.crt15
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/app2.req10
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/certstore.jksbin498 -> 591 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/keystore.jksbin2186 -> 4316 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/server_db/cert8.dbbin65536 -> 65536 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/server_db/key3.dbbin16384 -> 16384 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/server_db/secmod.dbbin16384 -> 16384 bytes
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/server_db/server.crt22
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/server_db/server.req23
-rw-r--r--qpid/python/examples/pubsub/verify.in26
-rw-r--r--qpid/python/qpid/brokertest.py29
-rw-r--r--qpid/python/qpid/messaging/constants.py12
-rw-r--r--qpid/python/qpid/messaging/driver.py224
-rw-r--r--qpid/python/qpid/messaging/endpoints.py44
-rw-r--r--qpid/python/qpid/messaging/message.py15
-rw-r--r--qpid/python/qpid/tests/messaging/__init__.py51
-rw-r--r--qpid/python/qpid/tests/messaging/endpoints.py226
-rw-r--r--qpid/python/qpid/tests/messaging/message.py15
-rw-r--r--qpid/python/qpid/validator.py14
-rw-r--r--qpid/tests/src/py/qpid_tests/broker_0_10/exchange.py10
-rw-r--r--qpid/tools/.gitignore1
236 files changed, 5013 insertions, 1763 deletions
diff --git a/qpid/QPID_VERSION.txt b/qpid/QPID_VERSION.txt
new file mode 100644
index 0000000000..eb49d7c7fd
--- /dev/null
+++ b/qpid/QPID_VERSION.txt
@@ -0,0 +1 @@
+0.7
diff --git a/qpid/cpp/.gitignore b/qpid/cpp/.gitignore
new file mode 100644
index 0000000000..4e945f96db
--- /dev/null
+++ b/qpid/cpp/.gitignore
@@ -0,0 +1 @@
+/QPID_VERSION.txt
diff --git a/qpid/cpp/BuildInstallSettings.cmake b/qpid/cpp/BuildInstallSettings.cmake
index 60d6b14e11..c1cf2bcba2 100644
--- a/qpid/cpp/BuildInstallSettings.cmake
+++ b/qpid/cpp/BuildInstallSettings.cmake
@@ -20,8 +20,17 @@
# Settings related to the Qpid build and install CMake/CTest/CPack procedure.
# These are used by both the C++ and WCF components.
-set (QPID_VERSION_MAJOR 0)
-set (QPID_VERSION_MINOR 6)
+# Parse the version from QPID_VERSION.txt.
+# Use the top level qpid/ file if we're in an SVN checkout, source dir otherwise.
+if(EXISTS "${PROJECT_SOURCE_DIR}/../QPID_VERSION.txt")
+ file(READ "${PROJECT_SOURCE_DIR}/../QPID_VERSION.txt" QPID_VERSION)
+elseif (EXISTS "${PROJECT_SOURCE_DIR}/QPID_VERSION.txt")
+ file(READ "${PROJECT_SOURCE_DIR}/QPID_VERSION.txt" QPID_VERSION)
+else()
+ message(FATAL_ERROR "Cannot find QPID_VERSION.txt")
+endif(EXISTS "${PROJECT_SOURCE_DIR}/../QPID_VERSION.txt")
+string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\n" "\\1" QPID_VERSION_MAJOR "${QPID_VERSION}")
+string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\n" "\\2" QPID_VERSION_MINOR "${QPID_VERSION}")
# When doing installs, there are a number of components that the item can
# be associated with. Since there may be different sets of components desired
diff --git a/qpid/cpp/CMakeLists.txt b/qpid/cpp/CMakeLists.txt
index 8c4aa06ee2..485ead127a 100644
--- a/qpid/cpp/CMakeLists.txt
+++ b/qpid/cpp/CMakeLists.txt
@@ -43,37 +43,6 @@ if (WIN32)
set (CPACK_NSIS_URL_INFO_ABOUT "http://qpid.apache.org/")
# Needs this to correctly set up Start menu links later.
set (CPACK_PACKAGE_EXECUTABLES "")
-
- # The WCF/C++ client is built separately (it doesn't build via CMake)
- # but is installed with the C++ components on Windows.
- install (PROGRAMS
- ${CMAKE_SOURCE_DIR}/../wcf/src/Apache/Qpid/Channel/bin/Release/Apache.Qpid.Channel.dll
- ${CMAKE_SOURCE_DIR}/../wcf/src/Apache/Qpid/Channel/bin/Release/Apache.Qpid.Interop.dll
- DESTINATION ${QPID_INSTALL_LIBDIR}
- COMPONENT ${QPID_COMPONENT_CLIENT})
- install (DIRECTORY ${CMAKE_SOURCE_DIR}/../wcf/samples/Channel
- DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
- COMPONENT ${QPID_COMPONENT_EXAMPLES}
- PATTERN ".svn" EXCLUDE)
-
- # Find where gacutil is; it's not usually on the default PATH. If it can't
- # be located, the WCF assemblies can't be inserted in the GAC.
- # The gacutil stuff is disabled for now; to re-enable it, one must be able
- # to either find the gacutil somehow and specify the directory where
- # gacutil lives, add it to PATH, or use the FUSE API in a program that
- # inserts the DLLs programatically without gacutil. Or use WiX, which can
- # supposedly do this in an easier way.
- #
- # See jira QPID-2310 for more info; update that if you change this.
- #set (CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
- # ExecWait 'gacutil -I \\\"$INSTDIR\\\\${QPID_INSTALL_LIBDIR}\\\\Apache.Qpid.Channel.dll\\\"'
- # ExecWait 'gacutil -I \\\"$INSTDIR\\\\${QPID_INSTALL_LIBDIR}\\\\Apache.Qpid.Interop.dll\\\"'
- # ")
- #set (CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "
- # ExecWait 'gacutil /u \\\"Apache.Qpid.Channel\\\"'
- # ExecWait 'gacutil /u \\\"Apache.Qpid.Interop\\\"'
- # ")
-
endif (WIN32)
set (QPIDC_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidc.conf CACHE STRING
diff --git a/qpid/cpp/INSTALL b/qpid/cpp/INSTALL
index d54d2affc3..9977c13201 100644
--- a/qpid/cpp/INSTALL
+++ b/qpid/cpp/INSTALL
@@ -114,6 +114,8 @@ The optional clustering packages changed name in Fedora 10. On Fedora 9 or earli
# yum install openais-devel cman-devel
On Fedora 10 or later
# yum install corosync-devel cmanlib-devel
+On Fedora 12 they changed again:
+ # yum install corosynclib-devel clusterlib-devel
For SASL and SSL, include
# yum install cyrus-sasl-devel
diff --git a/qpid/cpp/Makefile.am b/qpid/cpp/Makefile.am
index dcbc4c10c3..5c475946a0 100644
--- a/qpid/cpp/Makefile.am
+++ b/qpid/cpp/Makefile.am
@@ -25,7 +25,7 @@ ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = \
LICENSE NOTICE README SSL RELEASE_NOTES DESIGN \
xml/cluster.xml INSTALL-WINDOWS CMakeLists.txt BuildInstallSettings.cmake \
- packaging/NSIS
+ packaging/NSIS QPID_VERSION.txt
SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf
diff --git a/qpid/cpp/SSL b/qpid/cpp/SSL
index 4f80e77479..e7f040c76c 100644
--- a/qpid/cpp/SSL
+++ b/qpid/cpp/SSL
@@ -13,16 +13,16 @@ providing the ssl.so module is loaded):
SSL Settings:
--ssl-use-export-policy Use NSS export policy
- --ssl-cert-password-file PATH File containing password to use for
- accessing certificate database
+ --ssl-cert-password-file PATH File containing password to use for accessing
+ certificate database
--ssl-cert-db PATH Path to directory containing certificate
database
- --ssl-cert-name NAME (thinkpad) Name of the certificate to use
- --ssl-port PORT (5671) Port on which to listen for SSL
- connections
- --ssl-require-client-authentication Forces clients to authenticate in order
+ --ssl-cert-name NAME (hostname) Name of the certificate to use
+ --ssl-port PORT (5671) Port on which to listen for SSL connections
+ --ssl-require-client-authentication Forces clients to authenticate in order
to establish an SSL connection
-
+ --ssl-sasl-no-dict Disables SASL mechanisms that are vulner able to
+ passive dictionary-based password attacks
The first four of these are also available as client options (where
they must either be in the client config file or set as environment
@@ -66,6 +66,12 @@ and run e.g.
./src/tests/perftest --count 10000 -P ssl --port 5671 \
--broker myhost.mydomain
+When authentication is enabled, the EXTERNAL mechanism will be
+available on client authenticated SSL connections. This allows the
+clients authorisation id to be taken from the validated client
+certificate (it will be the CN with any DCs present appended as the
+domain, e.g. CN=bob,DC=acme,DC=com would result in an identity of
+bob@acme.com).
[1] http://www.mozilla.org/projects/security/pki/nss/ref/ssl/gtstd.html
[2] http://www.mozilla.org/projects/security/pki/nss/tools/certutil.html
diff --git a/qpid/cpp/bld-winsdk.ps1 b/qpid/cpp/bld-winsdk.ps1
new file mode 100644
index 0000000000..e2fe888a3a
--- /dev/null
+++ b/qpid/cpp/bld-winsdk.ps1
@@ -0,0 +1,121 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# This script requires cmake, and 7z to be already on the path devenv should be on the path as
+# a result of installing Visual Studio
+
+# Filter to extract the included files from c style #include lines
+# TODO: Not used yet
+function extractIncludes {
+ param($includedir=".", $found=@{}, $notfound=@{})
+ process {
+ # Put original files in list if not already there
+ $file = $_.FullName
+ if (!($found.Contains($file))) {
+ $found[$file] = $true;
+ }
+ $content = Get-Content $_
+ $filebase = $_.PSParentPath
+ $content | foreach {
+ if ($_ -match '^\s*#include\s*([<"])([^">]*)([>"])\s*') {
+ $included=$matches[2]
+ # Try to find the corresponding file in the same directory
+ # as the including file then try the include dir
+ $testpathf=Join-Path $filebase $included
+ $testpathi=Join-Path $includedir $included
+ if (Test-Path $testpathf) {
+ $includedfile = Get-Item $testpathf
+ } elseif (Test-Path $testpathi) {
+ $includedfile = Get-Item $testpathi
+ } else {
+ $notfound[$included] = $file
+ continue;
+ }
+ if (!($found.Contains($includedfile.FullName))) {
+ $found[$includedfile.FullName] = $file
+ $includedfile
+ }
+ }
+ }
+ }
+}
+
+function getIncludeFiles {
+ param($base, $findall=$false)
+ if ($findall) {
+ Get-ChildItem -recurse -include *.h $base
+ } else {
+ foreach ($path in $input) {
+ $full=Join-Path $base $path
+ if (Test-Path $full) {
+ Get-Item $full
+ }
+ }
+ }
+}
+
+if ($args.length -lt 1) {
+ Write-Host 'Need to specify location of qpid src tree'
+ exit
+}
+
+$qpid_src=$args[0]
+$ver=$args[1]
+if ($ver -eq $null) {
+ $qpid_version_file="$qpid_src\QPID_VERSION.txt"
+
+ if ( !(Test-Path $qpid_version_file)) {
+ Write-Host "Path doesn't seem to be a qpid src tree (no QPID_VERSION.txt)"
+ exit
+ }
+ $ver=Get-Content $qpid_version_file
+}
+
+$qpid_cpp_src="$qpid_src\cpp"
+$install_dir="install_$([System.IO.Path]::GetRandomFileName())"
+$zipfile="qpid-cpp-$ver.zip"
+
+# This assumes Visual Studio 2008
+cmake -G "Visual Studio 9 2008" "-DCMAKE_INSTALL_PREFIX=$install_dir" $qpid_cpp_src
+
+# Need to build doxygen api docs separately as nothing depends on them
+devenv qpid-cpp.sln /build "Release|Win32" /project docs-user-api
+
+# Build both debug and release so we can ship both sets of libs
+devenv qpid-cpp.sln /build "Release|Win32" /project INSTALL
+devenv qpid-cpp.sln /build "Debug|Win32" /project INSTALL
+
+# Cut down the files to put in the zip
+$removable=@(
+ 'bin/qpidd.exe', 'bin/qpidbroker*.*', 'plugins',
+ 'bin/qmfengine*.*', 'bin/qpidxarm*.*',
+ 'bin/boost_regex*.*')
+foreach ($pattern in $removable) {
+ Remove-Item -recurse "$install_dir/$pattern"
+}
+
+# It would be very good to cut down on the shipped boost include files too, ideally by
+# starting with the qpid files and recursively noting all boost headers actually needed
+
+# Create a new zip
+if (Test-Path $zipfile) {Remove-Item $zipfile}
+&'7z' a $zipfile ".\$install_dir\*"
+
+# Remove temporary install area
+# Remove-Item -recurse $install_dir
diff --git a/qpid/cpp/bootstrap b/qpid/cpp/bootstrap
index 5f33fec63f..925344acf7 100755
--- a/qpid/cpp/bootstrap
+++ b/qpid/cpp/bootstrap
@@ -1,5 +1,8 @@
#!/bin/sh
-set -e
+
+# Copy the global QPID_VERSION.txt file into the source tree.
+cp ../QPID_VERSION.txt .
+
aclocal -I m4
autoheader
libtoolize --automake
@@ -15,10 +18,10 @@ cat > src/managementgen.mk <<EOF
\$(mgen_cmd)
EOF
-
automake
autoconf
+# Optionally do the build as well.
if [ "$1" = "-build" -o "$1" = "--build" ] ; then
shift
./configure "$@"
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
index 8c8efc1917..adcf4c5dd2 100644
--- a/qpid/cpp/configure.ac
+++ b/qpid/cpp/configure.ac
@@ -8,10 +8,13 @@ dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dnl
-dnl When updating the name/version number here, also update it in
-dnl src/qpid/Version.h
-AC_INIT([qpidc], [0.7], [dev@qpid.apache.org])
+# Pick up the version from QPID_VERSION.txt in the qpid/cpp source tree.
+# NB. You need to re-run bootstrap if the global qpid/QPID_VERSION.txt changes.
+AC_INIT([qpidc],
+ [m4_esyscmd([cat QPID_VERSION.txt | tr -d '\n'])],
+ [dev@qpid.apache.org])
+
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
@@ -232,8 +235,7 @@ if test -n "$PYTHON" ; then
fi
AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test -f $PYTHON_INC/Python.h && test -n "$SWIG"])
-
-specdir=`pwd`/$srcdir/../specs
+specdir=`pwd`/$srcdir/../specs
AMQP_FINAL_XML=$specdir/amqp.0-10-qpid-errata.xml
AC_SUBST(AMQP_FINAL_XML)
AM_CONDITIONAL([GENERATE], [test -f $AMQP_FINAL_XML])
@@ -346,6 +348,8 @@ esac
test $want_xml = no && use_xml=no
+
+
# If the user doesn't say not to use XML, see if it's available.
if test $use_xml != no; then
# Then see if XQilla is available
@@ -364,6 +368,13 @@ if test $use_xml != no; then
# Else XQilla is available - use it to build
test $use_xml = yes &&
AC_DEFINE([HAVE_XML], [1], [Compile-in XML Exchange support.])
+
+ # Check to see if we need to use legacy calls for effective boolean value
+ xqilla_has_ebv=yes
+ AC_CHECK_HEADER([xqilla/ast/XQEffectiveBooleanValue.hpp], , [xqilla_has_ebv=no])
+ test $xqilla_has_ebv = yes &&
+ AC_DEFINE([XQ_EFFECTIVE_BOOLEAN_VALUE_HPP], [1], [XQilla version has xqilla/ast/XQEffectiveBooleanValue.hpp.])
+
fi
AM_CONDITIONAL([HAVE_XML], [test $use_xml = yes])
@@ -525,7 +536,6 @@ AC_CONFIG_FILES([
src/Makefile
src/tests/Makefile
src/tests/test_env.sh
- src/tests/testagent/Makefile
docs/man/Makefile
docs/api/Makefile
docs/api/user.doxygen
diff --git a/qpid/cpp/docs/api/CMakeLists.txt b/qpid/cpp/docs/api/CMakeLists.txt
index 1f9573b98a..5d04f85128 100644
--- a/qpid/cpp/docs/api/CMakeLists.txt
+++ b/qpid/cpp/docs/api/CMakeLists.txt
@@ -26,7 +26,10 @@ if (GEN_DOXYGEN)
set (srcdir ${CMAKE_CURRENT_SOURCE_DIR})
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in
${CMAKE_CURRENT_BINARY_DIR}/user.doxygen)
- add_custom_target (user-api-docs COMMAND ${DOXYGEN_EXECUTABLE} user.doxygen)
+ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/developer.doxygen.in
+ ${CMAKE_CURRENT_BINARY_DIR}/develeoper.doxygen)
+ add_custom_target (docs-user-api COMMAND ${DOXYGEN_EXECUTABLE} user.doxygen)
+ add_custom_target (docs-developer COMMAND ${DOXYGEN_EXECUTABLE} developer.doxygen)
# HTML files are generated to ./html - put those in the install.
install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
diff --git a/qpid/cpp/docs/src/CONTENTS b/qpid/cpp/docs/src/CONTENTS
new file mode 100644
index 0000000000..b7a9d411ac
--- /dev/null
+++ b/qpid/cpp/docs/src/CONTENTS
@@ -0,0 +1,12 @@
+This directory contains documentation about the C++ source
+that is expressed in formats that does not fit comfortably
+within C++ source files.
+
+As with all documentation, including comments, it may become
+outmoded with respect to the code.
+
+If you find external code doco useful in your work -- if it
+helps you save some time -- please return some of that time
+in the form of effort to keep the documentation updated.
+
+
diff --git a/qpid/cpp/docs/src/DispatchHandle.odg b/qpid/cpp/docs/src/DispatchHandle.odg
new file mode 100644
index 0000000000..c08b3a4e1a
--- /dev/null
+++ b/qpid/cpp/docs/src/DispatchHandle.odg
Binary files differ
diff --git a/qpid/cpp/examples/README.txt b/qpid/cpp/examples/README.txt
index 0663286664..bfad478c63 100644
--- a/qpid/cpp/examples/README.txt
+++ b/qpid/cpp/examples/README.txt
@@ -16,12 +16,12 @@ On Linux:
# ./declare_queues host1 9999
On Windows:
- C:\Program Files\qpidc-0.6\examples\direct> declare_queues host1 9999
+ C:\Program Files\qpidc-0.7\examples\direct> declare_queues host1 9999
The qpid C++ broker executable is named qpidd on Linux and qpidd.exe
on Windows. The default install locations are:
- Linux: /usr/sbin
-- Windows: C:\Program Files\qpidc-0.6\bin
+- Windows: C:\Program Files\qpidc-0.7\bin
In a C++ source distribution the broker is located in the src subdirectory
(generally, from this examples directory, ../src).
@@ -52,9 +52,9 @@ On Linux:
# ./listener
On Windows:
- C:\Program Files\qpidc-0.6\examples\direct> declare_queues
- C:\Program Files\qpidc-0.6\examples\direct> direct_producer
- C:\Program Files\qpidc-0.6\examples\direct> listener
+ C:\Program Files\qpidc-0.7\examples\direct> declare_queues
+ C:\Program Files\qpidc-0.7\examples\direct> direct_producer
+ C:\Program Files\qpidc-0.7\examples\direct> listener
Note that there is no requirement for the listener to be running before the
messages are published. The messages are stored in the queue until consumed
@@ -86,9 +86,9 @@ On Linux:
# ./fanout_producer
On Windows:
- C:\Program Files\qpidc-0.6\examples\fanout> listener
+ C:\Program Files\qpidc-0.7\examples\fanout> listener
- C:\Program Files\qpidc-0.6\examples\direct> fanout_producer
+ C:\Program Files\qpidc-0.7\examples\direct> fanout_producer
== Publisher/Subscriber ==
@@ -122,9 +122,9 @@ On Linux:
# ./topic_publisher
On Windows:
- C:\Program Files\qpidc-0.6\examples\pub-sub> topic_listener
+ C:\Program Files\qpidc-0.7\examples\pub-sub> topic_listener
- C:\Program Files\qpidc-0.6\examples\pub-sub> topic_publisher
+ C:\Program Files\qpidc-0.7\examples\pub-sub> topic_publisher
== Request/Response ==
@@ -147,8 +147,8 @@ On Linux:
# ./client
On Windows:
- C:\Program Files\qpidc-0.6\examples\request-response> server
- C:\Program Files\qpidc-0.6\examples\request-response> client
+ C:\Program Files\qpidc-0.7\examples\request-response> server
+ C:\Program Files\qpidc-0.7\examples\request-response> client
== QMF Agent ==
diff --git a/qpid/cpp/examples/examples.sln b/qpid/cpp/examples/examples.sln
index 18077f9efa..0d5ddd6bfe 100644
--- a/qpid/cpp/examples/examples.sln
+++ b/qpid/cpp/examples/examples.sln
@@ -295,6 +295,18 @@ Global
{E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.Build.0 = Release|Win32
{E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.ActiveCfg = Release|x64
{E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.Build.0 = Release|x64
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Debug|Win32.Build.0 = Debug|Win32
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Debug|x64.ActiveCfg = Debug|Win32
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Release|Win32.ActiveCfg = Release|Win32
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Release|Win32.Build.0 = Release|Win32
+ {D79791E5-C593-4F23-B545-0CE72D181F2A}.Release|x64.ActiveCfg = Release|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Debug|Win32.Build.0 = Debug|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Debug|x64.ActiveCfg = Debug|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|Win32.ActiveCfg = Release|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|Win32.Build.0 = Release|Win32
+ {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/qpid/cpp/examples/messaging/client.cpp b/qpid/cpp/examples/messaging/client.cpp
index 4d68d7c575..3f7afb5e3e 100644
--- a/qpid/cpp/examples/messaging/client.cpp
+++ b/qpid/cpp/examples/messaging/client.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";
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
@@ -70,6 +70,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/drain.cpp b/qpid/cpp/examples/messaging/drain.cpp
index bd18fd3884..38f6bdbb98 100644
--- a/qpid/cpp/examples/messaging/drain.cpp
+++ b/qpid/cpp/examples/messaging/drain.cpp
@@ -93,8 +93,8 @@ int main(int argc, char** argv)
{
Options options(argv[0]);
if (options.parse(argc, argv)) {
+ Connection connection(options.connectionOptions);
try {
- Connection connection(options.connectionOptions);
connection.open(options.url);
Session session = connection.newSession();
Receiver receiver = session.createReceiver(options.address);
@@ -116,6 +116,7 @@ int main(int argc, char** argv)
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
}
return 1;
diff --git a/qpid/cpp/examples/messaging/map_receiver.cpp b/qpid/cpp/examples/messaging/map_receiver.cpp
index 05be4090d2..cdbae6007e 100644
--- a/qpid/cpp/examples/messaging/map_receiver.cpp
+++ b/qpid/cpp/examples/messaging/map_receiver.cpp
@@ -38,8 +38,8 @@ using std::string;
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Receiver receiver = session.createReceiver("message_queue");
@@ -52,6 +52,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/map_sender.cpp b/qpid/cpp/examples/messaging/map_sender.cpp
index b6e0621844..037bb55201 100644
--- a/qpid/cpp/examples/messaging/map_sender.cpp
+++ b/qpid/cpp/examples/messaging/map_sender.cpp
@@ -37,9 +37,8 @@ using std::string;
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
-
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Sender sender = session.createSender("message_queue");
@@ -64,6 +63,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/queue_receiver.cpp b/qpid/cpp/examples/messaging/queue_receiver.cpp
index 192b90088d..95756a9a3d 100644
--- a/qpid/cpp/examples/messaging/queue_receiver.cpp
+++ b/qpid/cpp/examples/messaging/queue_receiver.cpp
@@ -31,8 +31,8 @@ using namespace qpid::messaging;
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Receiver receiver = session.createReceiver("message_queue");
@@ -51,6 +51,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/queue_sender.cpp b/qpid/cpp/examples/messaging/queue_sender.cpp
index b2535d90bf..439e1dffaf 100644
--- a/qpid/cpp/examples/messaging/queue_sender.cpp
+++ b/qpid/cpp/examples/messaging/queue_sender.cpp
@@ -34,8 +34,8 @@ int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
int count = argc>2 ? atoi(argv[2]) : 10;
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Sender sender = session.createSender("message_queue");
@@ -50,10 +50,10 @@ int main(int argc, char** argv) {
// And send a final message to indicate termination.
sender.send(Message("That's all, folks!"));
session.sync();
- connection.close();
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp
index 0a80a5fb02..046a209e2f 100644
--- a/qpid/cpp/examples/messaging/server.cpp
+++ b/qpid/cpp/examples/messaging/server.cpp
@@ -41,8 +41,8 @@ using std::string;
int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Receiver receiver = session.createReceiver("service_queue; {create: always}");
@@ -70,6 +70,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/spout.cpp b/qpid/cpp/examples/messaging/spout.cpp
index cbb6b52b34..4819c6bc00 100644
--- a/qpid/cpp/examples/messaging/spout.cpp
+++ b/qpid/cpp/examples/messaging/spout.cpp
@@ -156,8 +156,8 @@ int main(int argc, char** argv)
{
Options options(argv[0]);
if (options.parse(argc, argv)) {
+ Connection connection(options.connectionOptions);
try {
- Connection connection(options.connectionOptions);
connection.open(options.url);
Session session = connection.newSession();
Sender sender = session.createSender(options.address);
@@ -183,6 +183,7 @@ int main(int argc, char** argv)
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
}
return 1;
diff --git a/qpid/cpp/examples/messaging/topic_receiver.cpp b/qpid/cpp/examples/messaging/topic_receiver.cpp
index 13f881e574..9e0264a4c3 100644
--- a/qpid/cpp/examples/messaging/topic_receiver.cpp
+++ b/qpid/cpp/examples/messaging/topic_receiver.cpp
@@ -34,8 +34,8 @@ int main(int argc, char** argv) {
const std::string url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
const std::string pattern = argc>2 ? argv[2] : "#.#";
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Receiver receiver = session.createReceiver("news_service; {filter:[control, " + pattern + "]}");
@@ -53,6 +53,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/messaging/topic_sender.cpp b/qpid/cpp/examples/messaging/topic_sender.cpp
index d1ada45864..a37d4b5371 100644
--- a/qpid/cpp/examples/messaging/topic_sender.cpp
+++ b/qpid/cpp/examples/messaging/topic_sender.cpp
@@ -51,8 +51,8 @@ int main(int argc, char** argv) {
const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
int count = argc>2 ? atoi(argv[2]) : 10;
+ Connection connection;
try {
- Connection connection;
connection.open(url);
Session session = connection.newSession();
Sender sender = session.createSender("news_service");
@@ -72,6 +72,7 @@ int main(int argc, char** argv) {
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
return 1;
}
diff --git a/qpid/cpp/examples/pub-sub/verify_python_cpp.in b/qpid/cpp/examples/pub-sub/verify_python_cpp.in
index 52e8db9d72..f2871eb743 100644
--- a/qpid/cpp/examples/pub-sub/verify_python_cpp.in
+++ b/qpid/cpp/examples/pub-sub/verify_python_cpp.in
@@ -5,6 +5,10 @@ Declaring queue: news
Declaring queue: usa
Declaring queue: weather
Listening for messages ...
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
Message: europe.news 0 from europe
Message: europe.news 0 from news
Message: europe.news 1 from europe
@@ -25,10 +29,6 @@ Message: europe.weather 3 from europe
Message: europe.weather 3 from weather
Message: europe.weather 4 from europe
Message: europe.weather 4 from weather
-Message: That's all, folks! from europe
-Message: That's all, folks! from news
-Message: That's all, folks! from usa
-Message: That's all, folks! from weather
Message: usa.news 0 from news
Message: usa.news 0 from usa
Message: usa.news 1 from news
diff --git a/qpid/cpp/examples/verify b/qpid/cpp/examples/verify
index 43e1206a0c..9a1ed078d6 100755
--- a/qpid/cpp/examples/verify
+++ b/qpid/cpp/examples/verify
@@ -19,6 +19,7 @@
# under the License.
#
+export LC_ALL=C
# Driver script to verify installed examples (also used for build tests.)
#
diff --git a/qpid/cpp/examples/verify_all b/qpid/cpp/examples/verify_all
index baffd422ad..9d71c7498a 100755
--- a/qpid/cpp/examples/verify_all
+++ b/qpid/cpp/examples/verify_all
@@ -48,7 +48,7 @@ if test -z "$exclude_regexp"; then
run_examples=$all_examples
else
for f in $all_examples; do
- { cat $f | grep $exclude_regexp > /dev/null ; } || run_examples="$run_examples $f"
+ { echo $f | grep $exclude_regexp > /dev/null ; } || run_examples="$run_examples $f"
done
fi
$verify $topsrcdir $topbuilddir $run_examples
diff --git a/qpid/cpp/include/qpid/agent/QmfAgentImportExport.h b/qpid/cpp/include/qpid/agent/QmfAgentImportExport.h
index 9eee4a18fd..e41425a7ba 100644
--- a/qpid/cpp/include/qpid/agent/QmfAgentImportExport.h
+++ b/qpid/cpp/include/qpid/agent/QmfAgentImportExport.h
@@ -21,7 +21,7 @@
*/
#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
-#if defined(QMF_AGENT_EXPORT) || defined (qmfagent_EXPORTS)
+#if defined (qmf_EXPORTS)
#define QMF_AGENT_EXTERN __declspec(dllexport)
#else
#define QMF_AGENT_EXTERN __declspec(dllimport)
diff --git a/qpid/cpp/include/qpid/client/amqp0_10/FailoverUpdates.h b/qpid/cpp/include/qpid/client/amqp0_10/FailoverUpdates.h
new file mode 100644
index 0000000000..159745e67c
--- /dev/null
+++ b/qpid/cpp/include/qpid/client/amqp0_10/FailoverUpdates.h
@@ -0,0 +1,55 @@
+#ifndef QPID_CLIENT_AMQP0_10_FAILOVERUPDATES_H
+#define QPID_CLIENT_AMQP0_10_FAILOVERUPDATES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+
+namespace messaging {
+class Connection;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+struct FailoverUpdatesImpl;
+/**
+ * A utility to listen for updates on cluster membership - published
+ * via the amq.failover exchange - and update the list of known urls
+ * for a connection accordingly.
+ */
+class FailoverUpdates
+{
+ public:
+ QPID_CLIENT_EXTERN FailoverUpdates(qpid::messaging::Connection& connection);
+ QPID_CLIENT_EXTERN ~FailoverUpdates();
+ private:
+ FailoverUpdatesImpl* impl;
+
+ //no need to copy instances of this class
+ FailoverUpdates(const FailoverUpdates&);
+ FailoverUpdates& operator=(const FailoverUpdates&);
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_FAILOVERUPDATES_H*/
diff --git a/qpid/cpp/include/qpid/framing/FieldValue.h b/qpid/cpp/include/qpid/framing/FieldValue.h
index f413d5a552..8af1f8dedd 100644
--- a/qpid/cpp/include/qpid/framing/FieldValue.h
+++ b/qpid/cpp/include/qpid/framing/FieldValue.h
@@ -335,6 +335,16 @@ class Str16Value : public FieldValue {
QPID_COMMON_EXTERN Str16Value(const std::string& v);
};
+class Var16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Var16Value(const std::string& v, uint8_t code);
+};
+
+class Var32Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Var32Value(const std::string& v, uint8_t code);
+};
+
class Struct32Value : public FieldValue {
public:
QPID_COMMON_EXTERN Struct32Value(const std::string& v);
diff --git a/qpid/cpp/include/qpid/messaging/Address.h b/qpid/cpp/include/qpid/messaging/Address.h
index 745949792d..55befd2d6d 100644
--- a/qpid/cpp/include/qpid/messaging/Address.h
+++ b/qpid/cpp/include/qpid/messaging/Address.h
@@ -24,7 +24,7 @@
#include <string>
#include "qpid/Exception.h"
#include "qpid/messaging/Variant.h"
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include <ostream>
namespace qpid {
@@ -79,6 +79,11 @@ class AddressImpl;
* nide when a sender or receiver is cancelled. Can be one of <i>always</i>,
* <i>never</i>, <i>sender</i> or <i>receiver</i>.</td></tr>
*
+ * <tr valign=top><td>reliability</td><td>indicates the level of
+ * reliability expected. Can be one of unreliable, at-most-once,
+ * at-least-once or exactly-once (the latter is not yet correctly
+ * supported).</td></tr>
+ *
* <tr valign=top><td>node-properties</td><td>A nested map of properties of the addressed
* entity or 'node'. These can be used when automatically creating it,
* or to assert certain properties.
@@ -109,16 +114,14 @@ class AddressImpl;
* receiver does not want to receiver messages published to the topic
* that originate from a sender on the same connection</td></tr>
*
- * <tr valign=top><td>browse</td><td>(only relevant for queues) specifies that the receiver
- * does not wish to consume the messages, but merely browse them</td></tr>
+ * <tr valign=top><td>mode</td><td>(only relevant for queues)
+ * indicates whether the subscribe should consume (the default) or
+ * merely browse the messages. Valid values are 'consume' and
+ * 'browse'</td></tr>
*
* <tr valign=top><td>durable</td><td>(only relevant for topics at present) specifies that a
* durable subscription is required</td></tr>
*
- * <tr valign=top><td>reliability</td><td>indicates the level of reliability that the receiver
- * expects. Can be one of unreliable, at-most-once, at-least-once or
- * exactly-once (the latter is not yet correctly supported).</td></tr>
- *
* <tr valign=top><td>filter</td><td>(only relevant for topics at present) allows bindings to
* be created for the queue that match the given criteria (or list of
* criteria).</td></tr>
@@ -133,7 +136,7 @@ class AddressImpl;
* <li>exclusive, which requests an exclusive subscription and
* is only relevant for queues</li>
*
- * <li>x-queue-arguments, which ais only relevant for topics and
+ * <li>x-queue-arguments, which is only relevant for topics and
* allows arguments to the queue-declare for the subscription
* queue to be specified</li>
* </ul>
diff --git a/qpid/cpp/include/qpid/messaging/Codec.h b/qpid/cpp/include/qpid/messaging/Codec.h
index bacec5c786..b9b1cc862a 100644
--- a/qpid/cpp/include/qpid/messaging/Codec.h
+++ b/qpid/cpp/include/qpid/messaging/Codec.h
@@ -22,7 +22,7 @@
*
*/
#include <string>
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
namespace qpid {
namespace messaging {
diff --git a/qpid/cpp/include/qpid/messaging/Connection.h b/qpid/cpp/include/qpid/messaging/Connection.h
index 36392da0b2..b5eeeb2980 100644
--- a/qpid/cpp/include/qpid/messaging/Connection.h
+++ b/qpid/cpp/include/qpid/messaging/Connection.h
@@ -22,19 +22,14 @@
*
*/
#include <string>
-#include "qpid/client/ClientImportExport.h"
-#include "qpid/client/Handle.h"
+#include "qpid/messaging/ImportExport.h"
+#include "qpid/messaging/Handle.h"
#include "qpid/messaging/Variant.h"
namespace qpid {
-namespace client {
-
-template <class> class PrivateImplRef;
-
-}
-
namespace messaging {
+template <class> class PrivateImplRef;
class ConnectionImpl;
class Session;
@@ -43,7 +38,7 @@ struct InvalidOptionString : public qpid::Exception
InvalidOptionString(const std::string& msg);
};
-class Connection : public qpid::client::Handle<ConnectionImpl>
+class Connection : public qpid::messaging::Handle<ConnectionImpl>
{
public:
QPID_CLIENT_EXTERN Connection(ConnectionImpl* impl);
@@ -58,30 +53,38 @@ class Connection : public qpid::client::Handle<ConnectionImpl>
* sasl-mechanism
* sasl-min-ssf
* sasl-max-ssf
+ * protocol
+ * urls
*
- * (note also bounds, locale, max-channels and max-framesize, but not sure whether those should be docuemented here)
+ * (note also bounds, locale, max-channels and max-framesize, but
+ * not sure whether those should be documented here)
*
- * Retry behaviour can be controlled through the following options:
- *
- * reconnection-timeout - determines how long it will try to
- * reconnect for -1 means forever, 0
- * means don't try to reconnect
- * min-retry-interval
- * max-retry-interval
+ * Reconnect behaviour can be controlled through the following options:
*
- * The retry-interval is the time that the client waits for
- * after a failed attempt to reconnect before retrying. It
+ * reconnect: true/false (enables/disables reconnect entirely)
+ * reconnect-timeout: number of seconds (give up and report failure after specified time)
+ * reconnect-limit: n (give up and report failure after specified number of attempts)
+ * reconnect-interval-min: number of seconds (initial delay between failed reconnection attempts)
+ * reconnect-interval-max: number of seconds (maximum delay between failed reconnection attempts)
+ * reconnect-interval: shorthand for setting the same reconnect_interval_min/max
+ *
+ * The reconnect-interval is the time that the client waits
+ * for after a failed attempt to reconnect before retrying. It
* starts at the value of the min-retry-interval and is
* doubled every failure until the value of max-retry-interval
* is reached.
- *
- *
*/
QPID_CLIENT_EXTERN Connection(const Variant::Map& options = Variant::Map());
QPID_CLIENT_EXTERN Connection(const std::string& options);
QPID_CLIENT_EXTERN ~Connection();
QPID_CLIENT_EXTERN Connection& operator=(const Connection&);
+ QPID_CLIENT_EXTERN void setOption(const std::string& name, const Variant& value);
QPID_CLIENT_EXTERN void open(const std::string& url);
+ /**
+ * Closes a connection and all sessions associated with it. An
+ * opened connection must be closed before the last handle is
+ * allowed to go out of scope.
+ */
QPID_CLIENT_EXTERN void close();
QPID_CLIENT_EXTERN Session newSession(bool transactional, const std::string& name = std::string());
QPID_CLIENT_EXTERN Session newSession(const std::string& name = std::string());
@@ -89,7 +92,7 @@ class Connection : public qpid::client::Handle<ConnectionImpl>
QPID_CLIENT_EXTERN Session getSession(const std::string& name) const;
private:
- friend class qpid::client::PrivateImplRef<Connection>;
+ friend class qpid::messaging::PrivateImplRef<Connection>;
};
diff --git a/qpid/cpp/include/qpid/messaging/Handle.h b/qpid/cpp/include/qpid/messaging/Handle.h
new file mode 100644
index 0000000000..c528c39e19
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Handle.h
@@ -0,0 +1,71 @@
+#ifndef QPID_MESSAGING_HANDLE_H
+#define QPID_MESSAGING_HANDLE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/messaging/ImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+template <class> class PrivateImplRef;
+
+/**
+ * A handle is like a pointer: refers to an underlying implementation object.
+ * Copying the handle does not copy the object.
+ *
+ * Handles can be null, like a 0 pointer. Use isValid(), isNull() or the
+ * conversion to bool to test for a null handle.
+ */
+template <class T> class Handle {
+ public:
+
+ /**@return true if handle is valid, i.e. not null. */
+ QPID_CLIENT_EXTERN bool isValid() const { return impl; }
+
+ /**@return true if handle is null. It is an error to call any function on a null handle. */
+ QPID_CLIENT_EXTERN bool isNull() const { return !impl; }
+
+ /** Conversion to bool supports idiom if (handle) { handle->... } */
+ QPID_CLIENT_EXTERN operator bool() const { return impl; }
+
+ /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */
+ QPID_CLIENT_EXTERN bool operator !() const { return !impl; }
+
+ void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; }
+
+ protected:
+ typedef T Impl;
+ QPID_CLIENT_EXTERN Handle() :impl() {}
+
+ // Not implemented,subclasses must implement.
+ QPID_CLIENT_EXTERN Handle(const Handle&);
+ QPID_CLIENT_EXTERN Handle& operator=(const Handle&);
+
+ Impl* impl;
+
+ friend class PrivateImplRef<T>;
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_HANDLE_H*/
diff --git a/qpid/cpp/include/qpid/messaging/ImportExport.h b/qpid/cpp/include/qpid/messaging/ImportExport.h
new file mode 100644
index 0000000000..7113b437be
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/ImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QPID_MESSAGING_IMPORTEXPORT_H
+#define QPID_MESSAGING_IMPORTEXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+#if defined(CLIENT_EXPORT) || defined (qpidclient_EXPORTS)
+#define QPID_CLIENT_EXTERN __declspec(dllexport)
+#else
+#define QPID_CLIENT_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QPID_CLIENT_EXTERN
+#endif
+
+#endif /*!QPID_MESSAGING_IMPORTEXPORT_H*/
diff --git a/qpid/cpp/include/qpid/messaging/ListContent.h b/qpid/cpp/include/qpid/messaging/ListContent.h
index f57a920a88..3db8a8eac6 100644
--- a/qpid/cpp/include/qpid/messaging/ListContent.h
+++ b/qpid/cpp/include/qpid/messaging/ListContent.h
@@ -21,7 +21,7 @@
* under the License.
*
*/
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include "Variant.h"
namespace qpid {
diff --git a/qpid/cpp/include/qpid/messaging/ListView.h b/qpid/cpp/include/qpid/messaging/ListView.h
index 4970a20072..d7c3536a9c 100644
--- a/qpid/cpp/include/qpid/messaging/ListView.h
+++ b/qpid/cpp/include/qpid/messaging/ListView.h
@@ -22,7 +22,7 @@
*
*/
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include "Variant.h"
namespace qpid {
diff --git a/qpid/cpp/include/qpid/messaging/MapContent.h b/qpid/cpp/include/qpid/messaging/MapContent.h
index 3a80a38732..78ef51e593 100644
--- a/qpid/cpp/include/qpid/messaging/MapContent.h
+++ b/qpid/cpp/include/qpid/messaging/MapContent.h
@@ -22,7 +22,7 @@
*
*/
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include "Variant.h"
#include <map>
#include <string>
diff --git a/qpid/cpp/include/qpid/messaging/MapView.h b/qpid/cpp/include/qpid/messaging/MapView.h
index 910dfca5c2..baa999b4ad 100644
--- a/qpid/cpp/include/qpid/messaging/MapView.h
+++ b/qpid/cpp/include/qpid/messaging/MapView.h
@@ -21,7 +21,7 @@
* under the License.
*
*/
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include "Variant.h"
#include <map>
#include <string>
diff --git a/qpid/cpp/include/qpid/messaging/Message.h b/qpid/cpp/include/qpid/messaging/Message.h
index 30e15d79a3..21404d482b 100644
--- a/qpid/cpp/include/qpid/messaging/Message.h
+++ b/qpid/cpp/include/qpid/messaging/Message.h
@@ -25,12 +25,9 @@
#include <string>
#include "qpid/messaging/Duration.h"
#include "qpid/messaging/Variant.h"
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
class Address;
@@ -87,6 +84,7 @@ class Message
QPID_CLIENT_EXTERN const std::string& getContent() const;
QPID_CLIENT_EXTERN std::string& getContent();
+
QPID_CLIENT_EXTERN void setContent(const std::string&);
QPID_CLIENT_EXTERN void setContent(const char* chars, size_t count);
QPID_CLIENT_EXTERN void getContent(std::pair<const char*, size_t>& content) const;
diff --git a/qpid/cpp/include/qpid/messaging/Receiver.h b/qpid/cpp/include/qpid/messaging/Receiver.h
index bc1f39bfc1..80b58106d7 100644
--- a/qpid/cpp/include/qpid/messaging/Receiver.h
+++ b/qpid/cpp/include/qpid/messaging/Receiver.h
@@ -22,19 +22,15 @@
*
*/
#include "qpid/Exception.h"
-#include "qpid/client/ClientImportExport.h"
-#include "qpid/client/Handle.h"
+#include "qpid/messaging/ImportExport.h"
+#include "qpid/messaging/Handle.h"
#include "qpid/messaging/Duration.h"
namespace qpid {
-namespace client {
+namespace messaging {
template <class> class PrivateImplRef;
-}
-
-namespace messaging {
-
class Message;
class ReceiverImpl;
class Session;
@@ -42,7 +38,7 @@ class Session;
/**
* Interface through which messages are received.
*/
-class Receiver : public qpid::client::Handle<ReceiverImpl>
+class Receiver : public qpid::messaging::Handle<ReceiverImpl>
{
public:
struct NoMessageAvailable : qpid::Exception {};
@@ -60,14 +56,16 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
QPID_CLIENT_EXTERN bool get(Message& message, Duration timeout=INFINITE_DURATION);
/**
* Retrieves a message from this receivers local queue, or waits
- * for upto the specified timeout for a message to become
- * available. Throws NoMessageAvailable if there is no
- * message to give after waiting for the specified timeout.
+ * for up to the specified timeout for a message to become
+ * available.
+ *
+ *@exception NoMessageAvailable if there is no message to give
+ * after waiting for the specified timeout.
*/
QPID_CLIENT_EXTERN Message get(Duration timeout=INFINITE_DURATION);
/**
* Retrieves a message for this receivers subscription or waits
- * for upto the specified timeout for one to become
+ * for up to the specified timeout for one to become
* available. Unlike get() this method will check with the server
* that there is no message for the subscription this receiver is
* serving before returning false.
@@ -79,6 +77,9 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
* available. Unlike get() this method will check with the server
* that there is no message for the subscription this receiver is
* serving before throwing an exception.
+ *
+ *@exception NoMessageAvailable if there is no message to give
+ * after waiting for the specified timeout.
*/
QPID_CLIENT_EXTERN Message fetch(Duration timeout=INFINITE_DURATION);
/**
@@ -123,7 +124,7 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
QPID_CLIENT_EXTERN Session getSession() const;
private:
- friend class qpid::client::PrivateImplRef<Receiver>;
+ friend class qpid::messaging::PrivateImplRef<Receiver>;
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/include/qpid/messaging/Sender.h b/qpid/cpp/include/qpid/messaging/Sender.h
index eb8ccc2f84..b7dd015a55 100644
--- a/qpid/cpp/include/qpid/messaging/Sender.h
+++ b/qpid/cpp/include/qpid/messaging/Sender.h
@@ -21,27 +21,22 @@
* under the License.
*
*/
-#include "qpid/client/ClientImportExport.h"
-#include "qpid/client/Handle.h"
+#include "qpid/messaging/ImportExport.h"
+#include "qpid/messaging/Handle.h"
#include "qpid/sys/IntegerTypes.h"
#include <string>
namespace qpid {
-namespace client {
-
-template <class> class PrivateImplRef;
-
-}
-
namespace messaging {
+template <class> class PrivateImplRef;
class Message;
class SenderImpl;
class Session;
/**
* Interface through which messages are sent.
*/
-class Sender : public qpid::client::Handle<SenderImpl>
+class Sender : public qpid::messaging::Handle<SenderImpl>
{
public:
QPID_CLIENT_EXTERN Sender(SenderImpl* impl = 0);
@@ -79,7 +74,7 @@ class Sender : public qpid::client::Handle<SenderImpl>
*/
QPID_CLIENT_EXTERN Session getSession() const;
private:
- friend class qpid::client::PrivateImplRef<Sender>;
+ friend class qpid::messaging::PrivateImplRef<Sender>;
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/include/qpid/messaging/Session.h b/qpid/cpp/include/qpid/messaging/Session.h
index 87f69f268a..032b678c5c 100644
--- a/qpid/cpp/include/qpid/messaging/Session.h
+++ b/qpid/cpp/include/qpid/messaging/Session.h
@@ -23,20 +23,15 @@
*/
#include "qpid/Exception.h"
#include "qpid/messaging/Duration.h"
-#include "qpid/client/ClientImportExport.h"
-#include "qpid/client/Handle.h"
+#include "qpid/messaging/ImportExport.h"
+#include "qpid/messaging/Handle.h"
#include "qpid/sys/Time.h"
#include <string>
namespace qpid {
-namespace client {
-
-template <class> class PrivateImplRef;
-
-}
-
namespace messaging {
+template <class> class PrivateImplRef;
class Address;
class Connection;
class Message;
@@ -55,7 +50,7 @@ struct KeyError : qpid::Exception
* A session represents a distinct 'conversation' which can involve
* sending and receiving messages to and from different addresses.
*/
-class Session : public qpid::client::Handle<SessionImpl>
+class Session : public qpid::messaging::Handle<SessionImpl>
{
public:
QPID_CLIENT_EXTERN Session(SessionImpl* impl = 0);
@@ -63,6 +58,12 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN ~Session();
QPID_CLIENT_EXTERN Session& operator=(const Session&);
+ /**
+ * Closes a session and all associated senders and receivers. An
+ * opened session should be closed before the last handle to it
+ * goes out of scope. All a connections sessions can be closed by
+ * a call to Connection::close().
+ */
QPID_CLIENT_EXTERN void close();
QPID_CLIENT_EXTERN void commit();
@@ -83,8 +84,8 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN void flush();
/**
- * Returns the number of messages received and waiting to be
- * fetched.
+ * Returns the total number of messages received and waiting to be
+ * fetched by all Receivers belonging to this session.
*/
QPID_CLIENT_EXTERN uint32_t available();
/**
@@ -99,14 +100,15 @@ class Session : public qpid::client::Handle<SessionImpl>
* to the specified timeout waiting for one to arrive. Returns
* true if a message was available at the point of return, in
* which case the passed in receiver reference will be set to the
- * receiver for that message or fals if no message was available.
+ * receiver for that message or false if no message was available.
*/
QPID_CLIENT_EXTERN bool nextReceiver(Receiver&, Duration timeout=INFINITE_DURATION);
/**
* Returns the receiver for the next available message. If there
* are no available messages at present the call will block for up
- * to the specified timeout waiting for one to arrive. Will throw
- * Receiver::NoMessageAvailable if no message became available in
+ * to the specified timeout waiting for one to arrive.
+ *
+ *@exception Receiver::NoMessageAvailable if no message became available in
* time.
*/
QPID_CLIENT_EXTERN Receiver nextReceiver(Duration timeout=INFINITE_DURATION);
@@ -126,13 +128,13 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN Receiver createReceiver(const std::string& address);
/**
- * Returns the sender with the specified name or throws KeyError
- * if there is none for that name.
+ * Returns the sender with the specified name.
+ *@exception KeyError if there is none for that name.
*/
QPID_CLIENT_EXTERN Sender getSender(const std::string& name) const;
/**
- * Returns the receiver with the specified name or throws KeyError
- * if there is none for that name.
+ * Returns the receiver with the specified name.
+ *@exception KeyError if there is none for that name.
*/
QPID_CLIENT_EXTERN Receiver getReceiver(const std::string& name) const;
/**
@@ -142,7 +144,7 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN Connection getConnection() const;
private:
- friend class qpid::client::PrivateImplRef<Session>;
+ friend class qpid::messaging::PrivateImplRef<Session>;
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/include/qpid/messaging/Uuid.h b/qpid/cpp/include/qpid/messaging/Uuid.h
index bbc9bd7a97..d83f8495b7 100644
--- a/qpid/cpp/include/qpid/messaging/Uuid.h
+++ b/qpid/cpp/include/qpid/messaging/Uuid.h
@@ -22,7 +22,7 @@
*
*/
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
#include <iosfwd>
#include <string>
diff --git a/qpid/cpp/include/qpid/messaging/Variant.h b/qpid/cpp/include/qpid/messaging/Variant.h
index 0bf62a9909..51c6bd98fe 100644
--- a/qpid/cpp/include/qpid/messaging/Variant.h
+++ b/qpid/cpp/include/qpid/messaging/Variant.h
@@ -28,7 +28,7 @@
#include "Uuid.h"
#include "qpid/Exception.h"
#include "qpid/sys/IntegerTypes.h"
-#include "qpid/client/ClientImportExport.h"
+#include "qpid/messaging/ImportExport.h"
namespace qpid {
namespace messaging {
diff --git a/qpid/cpp/managementgen/qmfgen/schema.py b/qpid/cpp/managementgen/qmfgen/schema.py
index 5ce57bc268..ca6628c366 100755
--- a/qpid/cpp/managementgen/qmfgen/schema.py
+++ b/qpid/cpp/managementgen/qmfgen/schema.py
@@ -1315,13 +1315,14 @@ class SchemaClass:
def genPrimaryKey (self, stream, variables):
first = 1
for prop in self.properties:
- if prop.isIndex == 1:
- if first:
- first = None
- else:
- stream.write(" << \",\";\n")
- var = prop.type.type.stream.replace("#", prop.getName())
- stream.write(" key << %s" % var)
+ if prop.getName() != "vhostRef": # Limit how deep the v2Key strings get
+ if prop.isIndex == 1:
+ if first:
+ first = None
+ else:
+ stream.write(" << \",\";\n")
+ var = prop.type.type.stream.replace("#", prop.getName())
+ stream.write(" key << %s" % var)
if not first:
stream.write(";")
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index a7078bea47..b09309cb9c 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -589,19 +589,6 @@ set_target_properties (qpidcommon PROPERTIES
install (TARGETS qpidcommon
DESTINATION ${QPID_INSTALL_LIBDIR}
COMPONENT ${QPID_COMPONENT_COMMON})
-# When the client programming component is installed, Windows also needs
-# the debug variant of qpidcommon and qpidclient, and the PDBs for those
-# as well. It would be nice to figure out a way to put some sanity checking
-# here... as it is, success relies on the packager building the debug then
-# the release, then packaging the release build.
-if (WIN32)
- install (PROGRAMS
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.dll
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.lib
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.pdb
- DESTINATION ${QPID_INSTALL_LIBDIR}
- COMPONENT ${QPID_COMPONENT_CLIENT})
-endif (WIN32)
set (qpidclient_SOURCES
${rgen_client_srcs}
@@ -667,6 +654,7 @@ set (qpidclient_SOURCES
qpid/client/amqp0_10/CodecsInternal.h
qpid/client/amqp0_10/ConnectionImpl.h
qpid/client/amqp0_10/ConnectionImpl.cpp
+ qpid/client/amqp0_10/FailoverUpdates.cpp
qpid/client/amqp0_10/IncomingMessages.h
qpid/client/amqp0_10/IncomingMessages.cpp
qpid/client/amqp0_10/MessageSink.h
@@ -679,6 +667,8 @@ set (qpidclient_SOURCES
qpid/client/amqp0_10/SessionImpl.cpp
qpid/client/amqp0_10/SenderImpl.h
qpid/client/amqp0_10/SenderImpl.cpp
+ qpid/client/amqp0_10/SimpleUrlParser.h
+ qpid/client/amqp0_10/SimpleUrlParser.cpp
)
add_library (qpidclient SHARED ${qpidclient_SOURCES})
@@ -699,14 +689,6 @@ if (NOT QPID_GENERATED_HEADERS_IN_SOURCE)
DESTINATION ${QPID_INSTALL_INCLUDEDIR}
COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE})
endif (NOT QPID_GENERATED_HEADERS_IN_SOURCE)
-if (WIN32)
- install (PROGRAMS
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.dll
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.lib
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.pdb
- DESTINATION ${QPID_INSTALL_LIBDIR}
- COMPONENT ${QPID_COMPONENT_CLIENT})
-endif (WIN32)
if (WIN32)
set(AMQP_WCF_DIR ${qpid-cpp_SOURCE_DIR}/../wcf)
@@ -784,7 +766,8 @@ set (qpidbroker_SOURCES
qpid/broker/TxPublish.cpp
qpid/broker/Vhost.cpp
qpid/management/ManagementAgent.cpp
- qpid/management/ManagementExchange.cpp
+ qpid/management/ManagementDirectExchange.cpp
+ qpid/management/ManagementTopicExchange.cpp
qpid/sys/TCPIOPlugin.cpp
)
add_library (qpidbroker SHARED ${qpidbroker_SOURCES})
@@ -828,7 +811,7 @@ set (qmf_SOURCES
qpid/agent/ManagementAgentImpl.h
)
add_library (qmf SHARED ${qmf_SOURCES})
-target_link_libraries (qmf qmfengine)
+target_link_libraries (qmf qpidclient)
set_target_properties (qmf PROPERTIES
VERSION ${qmf_version})
install (TARGETS qmf OPTIONAL
@@ -922,15 +905,6 @@ set_target_properties (qmfconsole PROPERTIES
install (TARGETS qmfconsole
DESTINATION ${QPID_INSTALL_LIBDIR}
COMPONENT ${QPID_COMPONENT_QMF})
-# On Windows, also grab the debug version of qmfconsole.
-if (WIN32)
- install (PROGRAMS
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qmfconsoled.dll
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qmfconsoled.lib
- ${CMAKE_CURRENT_BINARY_DIR}/Debug/qmfconsoled.pdb
- DESTINATION ${QPID_INSTALL_LIBDIR}
- COMPONENT ${QPID_COMPONENT_QMF})
-endif (WIN32)
# A queue event listener plugin that creates messages on a replication
# queue corresponding to enqueue and dequeue events:
@@ -976,6 +950,5 @@ add_definitions(-DHAVE_CONFIG_H)
# Now create the config file from all the info learned above.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config.h)
-
add_subdirectory(qpid/store)
add_subdirectory(tests)
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 3a3f23056a..c66263b42a 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -465,6 +465,7 @@ libqpidcommon_la_SOURCES += \
qpid/sys/Runnable.cpp \
qpid/sys/ScopedIncrement.h \
qpid/sys/SecurityLayer.h \
+ qpid/sys/SecuritySettings.h \
qpid/sys/Semaphore.h \
qpid/sys/Shlib.cpp \
qpid/sys/Shlib.h \
@@ -637,8 +638,10 @@ libqpidbroker_la_SOURCES = \
qpid/management/IdAllocator.h \
qpid/management/ManagementAgent.cpp \
qpid/management/ManagementAgent.h \
- qpid/management/ManagementExchange.cpp \
- qpid/management/ManagementExchange.h \
+ qpid/management/ManagementDirectExchange.cpp \
+ qpid/management/ManagementDirectExchange.h \
+ qpid/management/ManagementTopicExchange.cpp \
+ qpid/management/ManagementTopicExchange.h \
qpid/sys/TCPIOPlugin.cpp
@@ -711,6 +714,7 @@ libqpidclient_la_SOURCES = \
qpid/messaging/Message.cpp \
qpid/messaging/MessageImpl.h \
qpid/messaging/MessageImpl.cpp \
+ qpid/messaging/PrivateImplRef.h \
qpid/messaging/Sender.cpp \
qpid/messaging/Receiver.cpp \
qpid/messaging/Session.cpp \
@@ -728,6 +732,7 @@ libqpidclient_la_SOURCES = \
qpid/client/amqp0_10/CodecsInternal.h \
qpid/client/amqp0_10/ConnectionImpl.h \
qpid/client/amqp0_10/ConnectionImpl.cpp \
+ qpid/client/amqp0_10/FailoverUpdates.cpp \
qpid/client/amqp0_10/IncomingMessages.h \
qpid/client/amqp0_10/IncomingMessages.cpp \
qpid/client/amqp0_10/MessageSink.h \
@@ -739,7 +744,9 @@ libqpidclient_la_SOURCES = \
qpid/client/amqp0_10/SessionImpl.h \
qpid/client/amqp0_10/SessionImpl.cpp \
qpid/client/amqp0_10/SenderImpl.h \
- qpid/client/amqp0_10/SenderImpl.cpp
+ qpid/client/amqp0_10/SenderImpl.cpp \
+ qpid/client/amqp0_10/SimpleUrlParser.h \
+ qpid/client/amqp0_10/SimpleUrlParser.cpp
# NOTE: only public header files (which should be in ../include)
# should go in this list. Private headers should go in the SOURCES
@@ -812,20 +819,23 @@ nobase_include_HEADERS += \
../include/qpid/sys/Thread.h \
../include/qpid/sys/Time.h \
../include/qpid/messaging/Address.h \
- ../include/qpid/messaging/Connection.h \
../include/qpid/messaging/Codec.h \
+ ../include/qpid/messaging/Connection.h \
../include/qpid/messaging/Duration.h \
+ ../include/qpid/messaging/Handle.h \
+ ../include/qpid/messaging/ImportExport.h \
../include/qpid/messaging/ListContent.h \
../include/qpid/messaging/ListView.h \
../include/qpid/messaging/MapContent.h \
../include/qpid/messaging/MapView.h \
../include/qpid/messaging/Message.h \
- ../include/qpid/messaging/Sender.h \
../include/qpid/messaging/Receiver.h \
+ ../include/qpid/messaging/Sender.h \
../include/qpid/messaging/Session.h \
../include/qpid/messaging/Uuid.h \
../include/qpid/messaging/Variant.h \
- ../include/qpid/client/amqp0_10/Codecs.h
+ ../include/qpid/client/amqp0_10/Codecs.h \
+ ../include/qpid/client/amqp0_10/FailoverUpdates.h
# Force build of qpidd during dist phase so help2man will work.
dist-hook: $(BUILT_SOURCES)
diff --git a/qpid/cpp/src/qpid/Version.h b/qpid/cpp/src/qpid/Version.h
index c8add11112..b4805a3757 100755
--- a/qpid/cpp/src/qpid/Version.h
+++ b/qpid/cpp/src/qpid/Version.h
@@ -23,10 +23,11 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
+#else
+# error "config.h not generated"
#endif
namespace qpid {
-#ifdef HAVE_CONFIG_H
const std::string product = PACKAGE_NAME;
const std::string version = PACKAGE_VERSION;
# if HAVE_SASL
@@ -34,11 +35,6 @@ namespace qpid {
# else
const std::string saslName = "qpidd-no-sasl";
# endif
-#else
- const std::string product = "qpidc";
- const std::string version = "0.7";
- const std::string saslName = "qpid-broker";
-#endif
}
#endif /*!QPID_VERSION_H*/
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index cbccca6eea..d94f228734 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -35,7 +35,8 @@
#include "qmf/org/apache/qpid/broker/Package.h"
#include "qmf/org/apache/qpid/broker/ArgsBrokerEcho.h"
#include "qmf/org/apache/qpid/broker/ArgsBrokerQueueMoveMessages.h"
-#include "qpid/management/ManagementExchange.h"
+#include "qpid/management/ManagementDirectExchange.h"
+#include "qpid/management/ManagementTopicExchange.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/ProtocolInitiation.h"
@@ -234,11 +235,22 @@ Broker::Broker(const Broker::Options& conf) :
declareStandardExchange(amq_match, HeadersExchange::typeName);
if(conf.enableMgmt) {
- exchanges.declare(qpid_management, ManagementExchange::typeName);
- Exchange::shared_ptr mExchange = exchanges.get (qpid_management);
- Exchange::shared_ptr dExchange = exchanges.get (amq_direct);
+ exchanges.declare(qpid_management, ManagementTopicExchange::typeName);
+ Exchange::shared_ptr mExchange = exchanges.get(qpid_management);
+ Exchange::shared_ptr dExchange = exchanges.get(amq_direct);
managementAgent->setExchange(mExchange, dExchange);
- boost::dynamic_pointer_cast<ManagementExchange>(mExchange)->setManagmentAgent(managementAgent.get());
+ boost::dynamic_pointer_cast<ManagementTopicExchange>(mExchange)->setManagmentAgent(managementAgent.get(), 1);
+
+ std::string qmfTopic("qmf.default.topic");
+ std::string qmfDirect("qmf.default.direct");
+
+ std::pair<Exchange::shared_ptr, bool> topicPair(exchanges.declare(qmfTopic, ManagementTopicExchange::typeName));
+ std::pair<Exchange::shared_ptr, bool> directPair(exchanges.declare(qmfDirect, ManagementDirectExchange::typeName));
+
+ boost::dynamic_pointer_cast<ManagementDirectExchange>(directPair.first)->setManagmentAgent(managementAgent.get(), 2);
+ boost::dynamic_pointer_cast<ManagementTopicExchange>(topicPair.first)->setManagmentAgent(managementAgent.get(), 2);
+
+ managementAgent->setExchangeV2(topicPair.first, directPair.first);
}
else
QPID_LOG(info, "Management not enabled");
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
index 532666ad76..2bb68b9f2d 100644
--- a/qpid/cpp/src/qpid/broker/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -23,6 +23,7 @@
#include "qpid/broker/SessionState.h"
#include "qpid/broker/Bridge.h"
#include "qpid/broker/Broker.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/log/Statement.h"
#include "qpid/ptr_map.h"
@@ -72,9 +73,10 @@ struct ConnectionTimeoutTask : public sys::TimerTask {
}
};
-Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_, unsigned int ssf, bool isLink_, uint64_t objectId, bool shadow_) :
+Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_,
+ const qpid::sys::SecuritySettings& external, bool isLink_, uint64_t objectId, bool shadow_) :
ConnectionState(out_, broker_),
- ssf(ssf),
+ securitySettings(external),
adapter(*this, isLink_),
isLink(isLink_),
mgmtClosing(false),
@@ -99,7 +101,7 @@ Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std
if (agent != 0) {
mgmtObject = new _qmf::Connection(agent, this, parent, mgmtId, !isLink, false);
mgmtObject->set_shadow(shadow);
- agent->addObject(mgmtObject, objectId, true);
+ agent->addObject(mgmtObject, objectId);
}
ConnectionState::setUrl(mgmtId);
}
diff --git a/qpid/cpp/src/qpid/broker/Connection.h b/qpid/cpp/src/qpid/broker/Connection.h
index d49d9f4d75..30a763411f 100644
--- a/qpid/cpp/src/qpid/broker/Connection.h
+++ b/qpid/cpp/src/qpid/broker/Connection.h
@@ -45,6 +45,7 @@
#include "qpid/sys/AggregateOutput.h"
#include "qpid/sys/ConnectionInputHandler.h"
#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/sys/Socket.h"
#include "qpid/sys/TimeoutHandler.h"
#include "qpid/sys/Mutex.h"
@@ -78,7 +79,8 @@ class Connection : public sys::ConnectionInputHandler,
virtual void connectionError(const std::string&) = 0;
};
- Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId, unsigned int ssf,
+ Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId,
+ const qpid::sys::SecuritySettings&,
bool isLink = false, uint64_t objectId = 0, bool shadow=false);
~Connection ();
@@ -136,14 +138,17 @@ class Connection : public sys::ConnectionInputHandler,
// Used by cluster to update connection status
sys::AggregateOutput& getOutputTasks() { return outputTasks; }
- unsigned int getSSF() { return ssf; }
+ const qpid::sys::SecuritySettings& getExternalSecuritySettings() const
+ {
+ return securitySettings;
+ }
private:
typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap;
typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
ChannelMap channels;
- unsigned int ssf;
+ qpid::sys::SecuritySettings securitySettings;
ConnectionHandler adapter;
const bool isLink;
bool mgmtClosing;
diff --git a/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp b/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
index ffb0b34b95..9e0020812b 100644
--- a/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
+++ b/qpid/cpp/src/qpid/broker/ConnectionFactory.cpp
@@ -22,12 +22,14 @@
#include "qpid/framing/ProtocolVersion.h"
#include "qpid/amqp_0_10/Connection.h"
#include "qpid/broker/Connection.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/log/Statement.h"
namespace qpid {
namespace broker {
using framing::ProtocolVersion;
+using qpid::sys::SecuritySettings;
typedef std::auto_ptr<amqp_0_10::Connection> ConnectionPtr;
typedef std::auto_ptr<sys::ConnectionInputHandler> InputPtr;
@@ -37,7 +39,7 @@ ConnectionFactory::~ConnectionFactory() {}
sys::ConnectionCodec*
ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
- unsigned int ) {
+ const SecuritySettings& external) {
if (broker.getConnectionCounter().allowConnection())
{
QPID_LOG(error, "Client max connection count limit exceeded: " << broker.getOptions().maxConnections << " connection refused");
@@ -45,7 +47,7 @@ ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std:
}
if (v == ProtocolVersion(0, 10)) {
ConnectionPtr c(new amqp_0_10::Connection(out, id, false));
- c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, false)));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, external, false)));
return c.release();
}
return 0;
@@ -53,10 +55,10 @@ ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std:
sys::ConnectionCodec*
ConnectionFactory::create(sys::OutputControl& out, const std::string& id,
- unsigned int) {
+ const SecuritySettings& external) {
// used to create connections from one broker to another
ConnectionPtr c(new amqp_0_10::Connection(out, id, true));
- c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, true)));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, external, true)));
return c.release();
}
diff --git a/qpid/cpp/src/qpid/broker/ConnectionFactory.h b/qpid/cpp/src/qpid/broker/ConnectionFactory.h
index d812292ad1..7c1a9a08e1 100644
--- a/qpid/cpp/src/qpid/broker/ConnectionFactory.h
+++ b/qpid/cpp/src/qpid/broker/ConnectionFactory.h
@@ -36,11 +36,10 @@ class ConnectionFactory : public sys::ConnectionCodec::Factory
sys::ConnectionCodec*
create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ const qpid::sys::SecuritySettings&);
sys::ConnectionCodec*
- create(sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ create(sys::OutputControl&, const std::string& id, const qpid::sys::SecuritySettings&);
private:
Broker& broker;
diff --git a/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
index f4a860fa1e..20fdc4164a 100644
--- a/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
+++ b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp
@@ -24,7 +24,8 @@
#include "qpid/broker/FanOutExchange.h"
#include "qpid/broker/HeadersExchange.h"
#include "qpid/broker/TopicExchange.h"
-#include "qpid/management/ManagementExchange.h"
+#include "qpid/management/ManagementDirectExchange.h"
+#include "qpid/management/ManagementTopicExchange.h"
#include "qpid/framing/reply_exceptions.h"
using namespace qpid::broker;
@@ -52,8 +53,10 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, c
exchange = Exchange::shared_ptr(new FanOutExchange(name, durable, args, parent, broker));
}else if (type == HeadersExchange::typeName) {
exchange = Exchange::shared_ptr(new HeadersExchange(name, durable, args, parent, broker));
- }else if (type == ManagementExchange::typeName) {
- exchange = Exchange::shared_ptr(new ManagementExchange(name, durable, args, parent, broker));
+ }else if (type == ManagementDirectExchange::typeName) {
+ exchange = Exchange::shared_ptr(new ManagementDirectExchange(name, durable, args, parent, broker));
+ }else if (type == ManagementTopicExchange::typeName) {
+ exchange = Exchange::shared_ptr(new ManagementTopicExchange(name, durable, args, parent, broker));
}else{
FunctionMap::iterator i = factory.find(type);
if (i == factory.end()) {
diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
index 640036e741..daf53085bf 100644
--- a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
+++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -252,7 +252,7 @@ namespace
{
bool match_values(const FieldValue& bind, const FieldValue& msg) {
- return bind.empty() || bind == msg;
+ return bind.getType() == 0xf0 || bind == msg;
}
}
diff --git a/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp b/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
index 02265ab85c..34d92fa752 100644
--- a/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
+++ b/qpid/cpp/src/qpid/broker/IncompleteMessageList.cpp
@@ -30,7 +30,8 @@ IncompleteMessageList::IncompleteMessageList() :
IncompleteMessageList::~IncompleteMessageList()
{
- sys::Mutex::ScopedLock l(lock);
+ // No lock here. We are relying on Messsag::reset*CompleteCallback
+ // to ensure no callbacks are in progress before they return.
for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); ++i) {
(*i)->resetEnqueueCompleteCallback();
(*i)->resetDequeueCompleteCallback();
@@ -78,7 +79,7 @@ void IncompleteMessageList::each(const CompletionListener& listen) {
sys::Mutex::ScopedLock l(lock);
snapshot = incomplete;
}
- std::for_each(incomplete.begin(), incomplete.end(), listen); // FIXME aconway 2008-11-07: passed by ref or value?
+ std::for_each(incomplete.begin(), incomplete.end(), listen);
}
}}
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index ff4a37c88f..329451d64e 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -49,7 +49,8 @@ TransferAdapter Message::TRANSFER;
Message::Message(const framing::SequenceNumber& id) :
frames(id), persistenceId(0), redelivered(false), loaded(false),
staged(false), forcePersistentPolicy(false), publisher(0), adapter(0),
- expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0), requiredCredit(0) {}
+ expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0),
+ inCallback(false), requiredCredit(0) {}
Message::~Message()
{
@@ -398,35 +399,55 @@ void Message::setReplacementMessage(boost::intrusive_ptr<Message> msg, const Que
replacement[qfor] = msg;
}
+namespace {
+struct ScopedSet {
+ sys::Monitor& lock;
+ bool& flag;
+ ScopedSet(sys::Monitor& l, bool& f) : lock(l), flag(f) {
+ sys::Monitor::ScopedLock sl(lock);
+ flag = true;
+ }
+ ~ScopedSet(){
+ sys::Monitor::ScopedLock sl(lock);
+ flag = false;
+ lock.notifyAll();
+ }
+};
+}
+
void Message::allEnqueuesComplete() {
- sys::Mutex::ScopedLock l(callbackLock);
+ ScopedSet ss(callbackLock, inCallback);
MessageCallback* cb = enqueueCallback;
if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
}
void Message::allDequeuesComplete() {
- sys::Mutex::ScopedLock l(callbackLock);
+ ScopedSet ss(callbackLock, inCallback);
MessageCallback* cb = dequeueCallback;
if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
}
void Message::setEnqueueCompleteCallback(MessageCallback& cb) {
sys::Mutex::ScopedLock l(callbackLock);
+ while (inCallback) callbackLock.wait();
enqueueCallback = &cb;
}
void Message::resetEnqueueCompleteCallback() {
sys::Mutex::ScopedLock l(callbackLock);
+ while (inCallback) callbackLock.wait();
enqueueCallback = 0;
}
void Message::setDequeueCompleteCallback(MessageCallback& cb) {
sys::Mutex::ScopedLock l(callbackLock);
+ while (inCallback) callbackLock.wait();
dequeueCallback = &cb;
}
void Message::resetDequeueCompleteCallback() {
sys::Mutex::ScopedLock l(callbackLock);
+ while (inCallback) callbackLock.wait();
dequeueCallback = 0;
}
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index 0a7772040b..353044c577 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -26,7 +26,7 @@
#include "qpid/broker/PersistableMessage.h"
#include "qpid/broker/MessageAdapter.h"
#include "qpid/framing/amqp_types.h"
-#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Monitor.h"
#include "qpid/sys/Time.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -189,9 +189,10 @@ public:
mutable Replacement replacement;
mutable boost::intrusive_ptr<Message> empty;
- sys::Mutex callbackLock;
+ sys::Monitor callbackLock;
MessageCallback* enqueueCallback;
MessageCallback* dequeueCallback;
+ bool inCallback;
uint32_t requiredCredit;
};
diff --git a/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp b/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
index 5611e3ec06..0f72f9643d 100644
--- a/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
+++ b/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
@@ -26,6 +26,7 @@
#include "qpid/broker/Connection.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/SecuritySettings.h"
#include <boost/format.hpp>
#if HAVE_SASL
@@ -36,6 +37,7 @@ using qpid::sys::cyrus::CyrusSecurityLayer;
using namespace qpid::framing;
using qpid::sys::SecurityLayer;
+using qpid::sys::SecuritySettings;
using boost::format;
using boost::str;
@@ -152,7 +154,8 @@ void NullAuthenticator::start(const string& mechanism, const string& response)
#if HAVE_SASL
// encryption required - check to see if we are running over an
// encrypted SSL connection.
- sasl_ssf_t external_ssf = (sasl_ssf_t) connection.getSSF();
+ SecuritySettings external = connection.getExternalSecuritySettings();
+ sasl_ssf_t external_ssf = (sasl_ssf_t) external.ssf;
if (external_ssf < 1) // < 1 == unencrypted
#endif
{
@@ -244,7 +247,9 @@ void CyrusAuthenticator::init()
// If the transport provides encryption, notify the SASL library of
// the key length and set the ssf range to prevent double encryption.
- sasl_ssf_t external_ssf = (sasl_ssf_t) connection.getSSF();
+ SecuritySettings external = connection.getExternalSecuritySettings();
+ QPID_LOG(debug, "External ssf=" << external.ssf << " and auth=" << external.authid);
+ sasl_ssf_t external_ssf = (sasl_ssf_t) external.ssf;
if (external_ssf) {
int result = sasl_setprop(sasl_conn, SASL_SSF_EXTERNAL, &external_ssf);
if (result != SASL_OK) {
@@ -258,16 +263,25 @@ void CyrusAuthenticator::init()
", max_ssf: " << secprops.max_ssf <<
", external_ssf: " << external_ssf );
+ if (!external.authid.empty()) {
+ const char* external_authid = external.authid.c_str();
+ int result = sasl_setprop(sasl_conn, SASL_AUTH_EXTERNAL, external_authid);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external auth: " << result));
+ }
+
+ QPID_LOG(debug, "external auth detected and set to " << external_authid);
+ }
+
secprops.maxbufsize = 65535;
secprops.property_names = 0;
secprops.property_values = 0;
secprops.security_flags = 0; /* or SASL_SEC_NOANONYMOUS etc as appropriate */
-
+ if (external.nodict) secprops.security_flags |= SASL_SEC_NODICTIONARY;
int result = sasl_setprop(sasl_conn, SASL_SEC_PROPS, &secprops);
if (result != SASL_OK) {
throw framing::InternalErrorException(QPID_MSG("SASL error: " << result));
}
-
}
CyrusAuthenticator::~CyrusAuthenticator()
diff --git a/qpid/cpp/src/qpid/broker/SecureConnectionFactory.cpp b/qpid/cpp/src/qpid/broker/SecureConnectionFactory.cpp
index 5a31dbceeb..754b443c22 100644
--- a/qpid/cpp/src/qpid/broker/SecureConnectionFactory.cpp
+++ b/qpid/cpp/src/qpid/broker/SecureConnectionFactory.cpp
@@ -23,12 +23,14 @@
#include "qpid/amqp_0_10/Connection.h"
#include "qpid/broker/Connection.h"
#include "qpid/broker/SecureConnection.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/log/Statement.h"
namespace qpid {
namespace broker {
using framing::ProtocolVersion;
+using qpid::sys::SecuritySettings;
typedef std::auto_ptr<amqp_0_10::Connection> CodecPtr;
typedef std::auto_ptr<SecureConnection> SecureConnectionPtr;
typedef std::auto_ptr<Connection> ConnectionPtr;
@@ -38,7 +40,7 @@ SecureConnectionFactory::SecureConnectionFactory(Broker& b) : broker(b) {}
sys::ConnectionCodec*
SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
- unsigned int conn_ssf ) {
+ const SecuritySettings& external) {
if (broker.getConnectionCounter().allowConnection())
{
QPID_LOG(error, "Client max connection count limit exceeded: " << broker.getOptions().maxConnections << " connection refused");
@@ -47,7 +49,7 @@ SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, cons
if (v == ProtocolVersion(0, 10)) {
SecureConnectionPtr sc(new SecureConnection());
CodecPtr c(new amqp_0_10::Connection(out, id, false));
- ConnectionPtr i(new broker::Connection(c.get(), broker, id, conn_ssf, false));
+ ConnectionPtr i(new broker::Connection(c.get(), broker, id, external, false));
i->setSecureConnection(sc.get());
c->setInputHandler(InputPtr(i.release()));
sc->setCodec(std::auto_ptr<sys::ConnectionCodec>(c));
@@ -58,11 +60,11 @@ SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, cons
sys::ConnectionCodec*
SecureConnectionFactory::create(sys::OutputControl& out, const std::string& id,
- unsigned int conn_ssf) {
+ const SecuritySettings& external) {
// used to create connections from one broker to another
SecureConnectionPtr sc(new SecureConnection());
CodecPtr c(new amqp_0_10::Connection(out, id, true));
- ConnectionPtr i(new broker::Connection(c.get(), broker, id, conn_ssf, true ));
+ ConnectionPtr i(new broker::Connection(c.get(), broker, id, external, true ));
i->setSecureConnection(sc.get());
c->setInputHandler(InputPtr(i.release()));
sc->setCodec(std::auto_ptr<sys::ConnectionCodec>(c));
diff --git a/qpid/cpp/src/qpid/broker/SecureConnectionFactory.h b/qpid/cpp/src/qpid/broker/SecureConnectionFactory.h
index b1af6d4a0f..8a04dfcb15 100644
--- a/qpid/cpp/src/qpid/broker/SecureConnectionFactory.h
+++ b/qpid/cpp/src/qpid/broker/SecureConnectionFactory.h
@@ -34,11 +34,10 @@ class SecureConnectionFactory : public sys::ConnectionCodec::Factory
sys::ConnectionCodec*
create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ const qpid::sys::SecuritySettings&);
sys::ConnectionCodec*
- create(sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ create(sys::OutputControl&, const std::string& id, const qpid::sys::SecuritySettings&);
private:
Broker& broker;
diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
index 8f1cc7b03f..9d68448d9d 100644
--- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -213,7 +213,7 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me
if (sasl.get()) {
string response = sasl->start(mechanism.empty() ? mechlist : mechanism,
- getSSF ? getSSF() : 0);
+ 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/ConnectionHandler.h b/qpid/cpp/src/qpid/client/ConnectionHandler.h
index ed1e385dcf..5f4b454f53 100644
--- a/qpid/cpp/src/qpid/client/ConnectionHandler.h
+++ b/qpid/cpp/src/qpid/client/ConnectionHandler.h
@@ -40,6 +40,11 @@
#include <memory>
namespace qpid {
+
+namespace sys {
+struct SecuritySettings;
+}
+
namespace client {
class ConnectionHandler : private StateManager,
@@ -95,7 +100,7 @@ public:
using InputHandler::handle;
typedef boost::function<void()> CloseListener;
typedef boost::function<void(uint16_t, const std::string&)> ErrorListener;
- typedef boost::function<unsigned int()> GetConnSSF;
+ typedef boost::function<const qpid::sys::SecuritySettings*()> GetSecuritySettings;
ConnectionHandler(const ConnectionSettings&, framing::ProtocolVersion&);
@@ -123,7 +128,7 @@ public:
static framing::connection::CloseCode convert(uint16_t replyCode);
const std::string& getUserId() const { return operUserId; }
- GetConnSSF getSSF; /** query the connection for its security strength factor */
+ GetSecuritySettings getSecuritySettings; /** query the transport for its security details */
};
}}
diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
index 80cd510886..ec1f4584db 100644
--- a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -134,6 +134,15 @@ IOThread& theIO() {
return io;
}
+// Bring theIO into existence on library load rather than first use.
+// This avoids it being destroyed whilst something in the main program
+// still exists
+struct InitAtLoad {
+ InitAtLoad() {
+ (void) theIO();
+ }
+} init;
+
class HeartbeatTask : public TimerTask {
TimeoutHandler& timeout;
@@ -165,7 +174,7 @@ ConnectionImpl::ConnectionImpl(framing::ProtocolVersion v, const ConnectionSetti
CLOSE_CODE_NORMAL, std::string());
//only set error handler once open
handler.onError = boost::bind(&ConnectionImpl::closed, this, _1, _2);
- handler.getSSF = boost::bind(&Connector::getSSF, boost::ref(connector));
+ handler.getSecuritySettings = boost::bind(&Connector::getSecuritySettings, boost::ref(connector));
}
const uint16_t ConnectionImpl::NEXT_CHANNEL = std::numeric_limits<uint16_t>::max();
@@ -195,7 +204,8 @@ void ConnectionImpl::addSession(const boost::shared_ptr<SessionImpl>& session, u
throw SessionBusyException(QPID_MSG("Channel " << ss->getChannel() << " attached to " << ss->getId()));
} //else channel is busy, but we can keep looking for a free one
}
-
+ // If we get here, we didn't find any available channel.
+ throw ResourceLimitExceededException("There are no channels available");
}
void ConnectionImpl::handle(framing::AMQFrame& frame)
diff --git a/qpid/cpp/src/qpid/client/Connector.h b/qpid/cpp/src/qpid/client/Connector.h
index 0203895b00..586012f9d6 100644
--- a/qpid/cpp/src/qpid/client/Connector.h
+++ b/qpid/cpp/src/qpid/client/Connector.h
@@ -35,6 +35,7 @@ namespace sys {
class ShutdownHandler;
class SecurityLayer;
class Poller;
+struct SecuritySettings;
}
namespace framing {
@@ -74,7 +75,7 @@ class Connector : public framing::OutputHandler
virtual void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
- virtual unsigned int getSSF() = 0;
+ virtual const qpid::sys::SecuritySettings* getSecuritySettings() = 0;
};
}}
diff --git a/qpid/cpp/src/qpid/client/RdmaConnector.cpp b/qpid/cpp/src/qpid/client/RdmaConnector.cpp
index 2bdfb8d68f..42b4649203 100644
--- a/qpid/cpp/src/qpid/client/RdmaConnector.cpp
+++ b/qpid/cpp/src/qpid/client/RdmaConnector.cpp
@@ -109,7 +109,7 @@ class RdmaConnector : public Connector, public sys::Codec
framing::OutputHandler* getOutputHandler();
const std::string& getIdentifier() const;
void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
- unsigned int getSSF() { return 0; }
+ const qpid::sys::SecuritySettings* getSecuritySettings() { return 0; }
size_t decode(const char* buffer, size_t size);
size_t encode(const char* buffer, size_t size);
diff --git a/qpid/cpp/src/qpid/client/Sasl.h b/qpid/cpp/src/qpid/client/Sasl.h
index 63da37fcb1..56735a5fc3 100644
--- a/qpid/cpp/src/qpid/client/Sasl.h
+++ b/qpid/cpp/src/qpid/client/Sasl.h
@@ -30,6 +30,7 @@ namespace qpid {
namespace sys {
class SecurityLayer;
+struct SecuritySettings;
}
namespace client {
@@ -48,17 +49,10 @@ class Sasl
*
* @param mechanisms Comma-separated list of the SASL mechanism the
* client supports.
- * @param ssf Security Strength Factor (SSF). SSF is used to negotiate
- * a SASL security layer on top of the connection should both
- * parties require and support it. The value indicates the
- * required level of security for communication. Possible
- * values are:
- * @li 0 No security
- * @li 1 Integrity checking only
- * @li >1 Integrity and confidentiality with the number
- * giving the encryption key length.
+ * @param externalSecuritySettings security related details from the underlying transport
*/
- virtual std::string start(const std::string& mechanisms, unsigned int ssf) = 0;
+ virtual std::string start(const std::string& mechanisms,
+ const qpid::sys::SecuritySettings* externalSecuritySettings = 0) = 0;
virtual std::string step(const std::string& challenge) = 0;
virtual std::string getMechanism() = 0;
virtual std::string getUserId() = 0;
diff --git a/qpid/cpp/src/qpid/client/SaslFactory.cpp b/qpid/cpp/src/qpid/client/SaslFactory.cpp
index 5012b75c94..ec5680c8d8 100644
--- a/qpid/cpp/src/qpid/client/SaslFactory.cpp
+++ b/qpid/cpp/src/qpid/client/SaslFactory.cpp
@@ -61,6 +61,7 @@ std::auto_ptr<SaslFactory> SaslFactory::instance;
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/sys/SecurityLayer.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/sys/cyrus/CyrusSecurityLayer.h"
#include "qpid/log/Statement.h"
#include <sasl/sasl.h>
@@ -70,6 +71,7 @@ namespace qpid {
namespace client {
using qpid::sys::SecurityLayer;
+using qpid::sys::SecuritySettings;
using qpid::sys::cyrus::CyrusSecurityLayer;
using qpid::framing::InternalErrorException;
@@ -80,7 +82,7 @@ class CyrusSasl : public Sasl
public:
CyrusSasl(const ConnectionSettings&);
~CyrusSasl();
- std::string start(const std::string& mechanisms, unsigned int ssf);
+ std::string start(const std::string& mechanisms, const SecuritySettings* externalSettings);
std::string step(const std::string& challenge);
std::string getMechanism();
std::string getUserId();
@@ -176,7 +178,7 @@ namespace {
const std::string SSL("ssl");
}
-std::string CyrusSasl::start(const std::string& mechanisms, unsigned int ssf)
+std::string CyrusSasl::start(const std::string& mechanisms, const SecuritySettings* externalSettings)
{
QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << ")");
int result = sasl_client_new(settings.service.c_str(),
@@ -190,14 +192,22 @@ std::string CyrusSasl::start(const std::string& mechanisms, unsigned int ssf)
sasl_security_properties_t secprops;
- if (ssf) {
- sasl_ssf_t external_ssf = (sasl_ssf_t) ssf;
+ if (externalSettings) {
+ sasl_ssf_t external_ssf = (sasl_ssf_t) externalSettings->ssf;
if (external_ssf) {
int result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &external_ssf);
if (result != SASL_OK) {
throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external SSF: " << result));
}
- QPID_LOG(debug, "external SSF detected and set to " << ssf);
+ QPID_LOG(debug, "external SSF detected and set to " << external_ssf);
+ }
+ if (externalSettings->authid.size()) {
+ const char* external_authid = externalSettings->authid.c_str();
+ result = sasl_setprop(conn, SASL_AUTH_EXTERNAL, external_authid);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external auth: " << result));
+ }
+ QPID_LOG(debug, "external auth detected and set to " << external_authid);
}
}
@@ -216,7 +226,6 @@ std::string CyrusSasl::start(const std::string& mechanisms, unsigned int ssf)
throw framing::InternalErrorException(QPID_MSG("SASL error: " << sasl_errdetail(conn)));
}
-
sasl_interact_t* client_interact = 0;
const char *out = 0;
unsigned outlen = 0;
diff --git a/qpid/cpp/src/qpid/client/SslConnector.cpp b/qpid/cpp/src/qpid/client/SslConnector.cpp
index cf6d54d261..0c794145db 100644
--- a/qpid/cpp/src/qpid/client/SslConnector.cpp
+++ b/qpid/cpp/src/qpid/client/SslConnector.cpp
@@ -34,6 +34,7 @@
#include "qpid/sys/ssl/SslSocket.h"
#include "qpid/sys/Dispatcher.h"
#include "qpid/sys/Poller.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/Msg.h"
#include <iostream>
@@ -86,6 +87,7 @@ class SslConnector : public Connector
const uint16_t maxFrameSize;
framing::ProtocolVersion version;
bool initiated;
+ SecuritySettings securitySettings;
sys::Mutex closedLock;
bool closed;
@@ -125,7 +127,7 @@ class SslConnector : public Connector
sys::ShutdownHandler* getShutdownHandler() const;
framing::OutputHandler* getOutputHandler();
const std::string& getIdentifier() const;
- unsigned int getSSF() { return socket.getKeyLen(); }
+ const SecuritySettings* getSecuritySettings();
public:
SslConnector(Poller::shared_ptr p, framing::ProtocolVersion pVersion,
@@ -366,4 +368,11 @@ void SslConnector::eof(SslIO&) {
handleClosed();
}
+const SecuritySettings* SslConnector::getSecuritySettings()
+{
+ securitySettings.ssf = socket.getKeyLen();
+ securitySettings.authid = "dummy";//set to non-empty string to enable external authentication
+ return &securitySettings;
+}
+
}} // namespace qpid::client
diff --git a/qpid/cpp/src/qpid/client/TCPConnector.cpp b/qpid/cpp/src/qpid/client/TCPConnector.cpp
index 78c9b32069..1a245fe2c8 100644
--- a/qpid/cpp/src/qpid/client/TCPConnector.cpp
+++ b/qpid/cpp/src/qpid/client/TCPConnector.cpp
@@ -199,8 +199,19 @@ void TCPConnector::send(AMQFrame& frame) {
} else {
notifyWrite = (currentSize >= maxFrameSize);
}
- }
+ /*
+ NOTE: Moving the following line into this mutex block
+ is a workaround for BZ 570168, in which the test
+ testConcurrentSenders causes a hang about 1.5%
+ of the time. ( To see the hang much more frequently
+ leave this line out of the mutex block, and put a
+ small usleep just before it.)
+
+ TODO mgoulish - fix the underlying cause and then
+ move this call back outside the mutex.
+ */
if (notifyWrite && !closed) aio->notifyPendingWrite();
+ }
}
void TCPConnector::handleClosed() {
diff --git a/qpid/cpp/src/qpid/client/TCPConnector.h b/qpid/cpp/src/qpid/client/TCPConnector.h
index 6ca750f52f..6d447def2e 100644
--- a/qpid/cpp/src/qpid/client/TCPConnector.h
+++ b/qpid/cpp/src/qpid/client/TCPConnector.h
@@ -92,7 +92,7 @@ class TCPConnector : public Connector, public sys::Codec
framing::OutputHandler* getOutputHandler();
const std::string& getIdentifier() const;
void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
- unsigned int getSSF() { return 0; }
+ const qpid::sys::SecuritySettings* getSecuritySettings() { return 0; }
size_t decode(const char* buffer, size_t size);
size_t encode(const char* buffer, size_t size);
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
index 835d80185a..3e17fc968b 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
@@ -25,8 +25,10 @@
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/List.h"
+#include "qpid/log/Statement.h"
#include <algorithm>
#include <functional>
+#include <limits>
using namespace qpid::framing;
using namespace qpid::messaging;
@@ -39,6 +41,7 @@ namespace {
const std::string iso885915("iso-8859-15");
const std::string utf8("utf8");
const std::string utf16("utf16");
+const std::string binary("binary");
const std::string amqp0_10_binary("amqp0-10:binary");
const std::string amqp0_10_bit("amqp0-10:bit");
const std::string amqp0_10_datetime("amqp0-10:datetime");
@@ -129,7 +132,7 @@ Variant toVariant(boost::shared_ptr<FieldValue> in)
case 0x02: out = in->getIntegerValue<int8_t, 1>(); break;
case 0x03: out = in->getIntegerValue<uint8_t, 1>(); break;
case 0x04: break; //TODO: iso-8859-15 char
- case 0x08: out = in->getIntegerValue<bool, 1>(); break;
+ case 0x08: out = static_cast<bool>(in->getIntegerValue<uint8_t, 1>()); break;
case 0x10: out.setEncoding(amqp0_10_binary);
case 0x11: out = in->getIntegerValue<int16_t, 2>(); break;
case 0x12: out = in->getIntegerValue<uint16_t, 2>(); break;
@@ -163,8 +166,8 @@ Variant toVariant(boost::shared_ptr<FieldValue> in)
case 0x96:
case 0xa0:
case 0xab:
- setEncodingFor(out, in->getType());
out = in->get<std::string>();
+ setEncodingFor(out, in->getType());
break;
case 0xa8:
@@ -188,6 +191,28 @@ Variant toVariant(boost::shared_ptr<FieldValue> in)
return out;
}
+boost::shared_ptr<FieldValue> convertString(const std::string& value, const std::string& encoding)
+{
+ bool large = value.size() > std::numeric_limits<uint16_t>::max();
+ if (encoding.empty() || encoding == amqp0_10_binary || encoding == binary) {
+ if (large) {
+ return boost::shared_ptr<FieldValue>(new Var32Value(value, 0xa0));
+ } else {
+ return boost::shared_ptr<FieldValue>(new Var16Value(value, 0x90));
+ }
+ } else if (encoding == utf8 && !large) {
+ return boost::shared_ptr<FieldValue>(new Str16Value(value));
+ } else if (encoding == utf16 && !large) {
+ return boost::shared_ptr<FieldValue>(new Var16Value(value, 0x96));
+ } else if (encoding == iso885915 && !large) {
+ return boost::shared_ptr<FieldValue>(new Var16Value(value, 0x94));
+ } else {
+ //either the string is too large for the encoding in amqp 0-10, or the encoding was not recognised
+ QPID_LOG(warning, "Could not encode " << value.size() << " byte value as " << encoding << ", encoding as vbin32.");
+ return boost::shared_ptr<FieldValue>(new Var32Value(value, 0xa0));
+ }
+}
+
boost::shared_ptr<FieldValue> toFieldValue(const Variant& in)
{
boost::shared_ptr<FieldValue> out;
@@ -204,8 +229,7 @@ boost::shared_ptr<FieldValue> toFieldValue(const Variant& in)
case VAR_INT64: out = boost::shared_ptr<FieldValue>(new Integer64Value(in.asInt64())); break;
case VAR_FLOAT: out = boost::shared_ptr<FieldValue>(new FloatValue(in.asFloat())); break;
case VAR_DOUBLE: out = boost::shared_ptr<FieldValue>(new DoubleValue(in.asDouble())); break;
- //TODO: check encoding (and length?) when deciding what AMQP type to treat string as
- case VAR_STRING: out = boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); break;
+ case VAR_STRING: out = convertString(in.asString(), in.getEncoding()); break;
case VAR_UUID: out = boost::shared_ptr<FieldValue>(new UuidValue(in.asUuid().data())); break;
case VAR_MAP:
out = boost::shared_ptr<FieldValue>(toFieldTableValue(in.asMap()));
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
index 4242850192..ce4e1ecc2a 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,8 +20,9 @@
*/
#include "ConnectionImpl.h"
#include "SessionImpl.h"
+#include "SimpleUrlParser.h"
#include "qpid/messaging/Session.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
#include "qpid/framing/Uuid.h"
#include "qpid/log/Statement.h"
#include <boost/intrusive_ptr.hpp>
@@ -33,13 +34,42 @@ namespace amqp0_10 {
using qpid::messaging::Variant;
using qpid::framing::Uuid;
-using namespace qpid::sys;
-template <class T> void setIfFound(const Variant::Map& map, const std::string& key, T& value)
+void convert(const Variant::List& from, std::vector<std::string>& to)
+{
+ for (Variant::List::const_iterator i = from.begin(); i != from.end(); ++i) {
+ to.push_back(i->asString());
+ }
+}
+
+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 {
+ QPID_LOG(debug, "option " << key << " not specified");
+ return false;
+ }
+}
+
+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()) {
+ if (i->second.getType() == qpid::messaging::VAR_LIST) {
+ convert(i->second.asList(), value);
+ } else {
+ value.push_back(i->second.asString());
+ }
+ return true;
+ } else {
+ return false;
}
}
@@ -59,24 +89,47 @@ void convert(const Variant::Map& from, ConnectionSettings& to)
setIfFound(from, "max-channels", to.maxChannels);
setIfFound(from, "max-frame-size", to.maxFrameSize);
setIfFound(from, "bounds", to.bounds);
+
+ setIfFound(from, "protocol", to.protocol);
}
ConnectionImpl::ConnectionImpl(const Variant::Map& options) :
- reconnectionEnabled(true), timeout(-1),
- minRetryInterval(1), maxRetryInterval(30)
+ reconnect(true), timeout(-1), limit(-1),
+ minReconnectInterval(3), maxReconnectInterval(60),
+ retries(0)
+{
+ QPID_LOG(debug, "Created connection with " << options);
+ setOptions(options);
+}
+
+void ConnectionImpl::setOptions(const Variant::Map& options)
{
- QPID_LOG(debug, "Opening connection to " << url << " with " << options);
convert(options, settings);
- setIfFound(options, "reconnection-enabled", reconnectionEnabled);
- setIfFound(options, "reconnection-timeout", timeout);
- setIfFound(options, "min-retry-interval", minRetryInterval);
- setIfFound(options, "max-retry-interval", maxRetryInterval);
+ 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, "min-reconnect-interval", minReconnectInterval);
+ setIfFound(options, "max-reconnect-interval", maxReconnectInterval);
+ }
+ setIfFound(options, "urls", urls);
+}
+
+void ConnectionImpl::setOption(const std::string& name, const Variant& value)
+{
+ Variant::Map options;
+ options[name] = value;
+ setOptions(options);
+ QPID_LOG(debug, "Set " << name << " to " << value);
}
void ConnectionImpl::open(const std::string& u)
{
- url = u;
- connection.open(url, settings);
+ urls.push_back(u);
+ connect();
}
void ConnectionImpl::close()
@@ -97,7 +150,7 @@ void ConnectionImpl::close()
boost::intrusive_ptr<SessionImpl> getImplPtr(qpid::messaging::Session& session)
{
return boost::dynamic_pointer_cast<SessionImpl>(
- qpid::client::PrivateImplRef<qpid::messaging::Session>::get(session)
+ qpid::messaging::PrivateImplRef<qpid::messaging::Session>::get(session)
);
}
@@ -134,64 +187,65 @@ qpid::messaging::Session ConnectionImpl::newSession(bool transactional, const st
try {
getImplPtr(impl)->setSession(connection.newSession(name));
} catch (const TransportFailure&) {
- reconnect();
+ connect();
}
return impl;
}
-void ConnectionImpl::reconnect()
+void ConnectionImpl::connect()
{
- AbsTime start = now();
- ScopedLock<Semaphore> l(semaphore);
+ qpid::sys::AbsTime start = qpid::sys::now();
+ qpid::sys::ScopedLock<qpid::sys::Semaphore> l(semaphore);
if (!connection.isOpen()) connect(start);
}
-bool expired(const AbsTime& start, int timeout)
+bool expired(const qpid::sys::AbsTime& start, int64_t timeout)
{
if (timeout == 0) return true;
if (timeout < 0) return false;
- Duration used(start, now());
- Duration allowed = timeout * TIME_SEC;
- return allowed > used;
+ qpid::sys::Duration used(start, qpid::sys::now());
+ qpid::sys::Duration allowed = timeout * qpid::sys::TIME_SEC;
+ return allowed < used;
}
-void ConnectionImpl::connect(const AbsTime& started)
+void ConnectionImpl::connect(const qpid::sys::AbsTime& started)
{
- for (int i = minRetryInterval; !tryConnect(); i = std::min(i * 2, maxRetryInterval)) {
- if (expired(started, timeout)) throw TransportFailure();
+ for (int64_t i = minReconnectInterval; !tryConnect(); i = std::min(i * 2, maxReconnectInterval)) {
+ if (!reconnect) throw TransportFailure("Failed to connect (reconnect disabled)");
+ if (limit >= 0 && retries++ >= limit) throw TransportFailure("Failed to connect within reconnect limit");
+ if (expired(started, timeout)) throw TransportFailure("Failed to connect within reconnect timeout");
else qpid::sys::sleep(i);
}
+ retries = 0;
}
bool ConnectionImpl::tryConnect()
{
- if (tryConnect(url) ||
- (failoverListener.get() && tryConnect(failoverListener->getKnownBrokers())))
- {
- return resetSessions();
- } else {
- return false;
- }
+ if (tryConnect(urls)) return resetSessions();
+ else return false;
}
-bool ConnectionImpl::tryConnect(const Url& u)
+bool ConnectionImpl::tryConnect(const std::vector<std::string>& urls)
{
- try {
- QPID_LOG(info, "Trying to connect to " << url << "...");
- connection.open(u, settings);
- failoverListener.reset(new FailoverListener(connection));
- return true;
- } catch (const Exception& e) {
- //TODO: need to fix timeout on open so that it throws TransportFailure
- QPID_LOG(info, "Failed to connect to " << u << ": " << e.what());
- }
- return false;
-}
-
-bool ConnectionImpl::tryConnect(const std::vector<Url>& urls)
-{
- for (std::vector<Url>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
- if (tryConnect(*i)) return true;
+ for (std::vector<std::string>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
+ try {
+ QPID_LOG(info, "Trying to connect to " << *i << "...");
+ //TODO: when url support is more complete can avoid this test here
+ if (i->find("amqp:") == 0) {
+ Url url(*i);
+ connection.open(url, settings);
+ } else {
+ SimpleUrlParser::parse(*i, settings);
+ connection.open(settings);
+ }
+ QPID_LOG(info, "Connected to " << *i);
+ return true;
+ } catch (const Exception& e) {
+ //TODO: need to fix timeout on
+ //qpid::client::Connection::open() so that it throws
+ //TransportFailure rather than a ConnectionException
+ QPID_LOG(info, "Failed to connect to " << *i << ": " << e.what());
+ }
}
return false;
}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
index d9d0d1e065..37a78b2373 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
@@ -25,7 +25,6 @@
#include "qpid/messaging/Variant.h"
#include "qpid/Url.h"
#include "qpid/client/Connection.h"
-#include "qpid/client/FailoverListener.h"
#include "qpid/client/ConnectionSettings.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/Semaphore.h"
@@ -46,7 +45,8 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl
qpid::messaging::Session newSession(bool transactional, const std::string& name);
qpid::messaging::Session getSession(const std::string& name) const;
void closed(SessionImpl&);
- void reconnect();
+ void connect();
+ void setOption(const std::string& name, const qpid::messaging::Variant& value);
private:
typedef std::map<std::string, qpid::messaging::Session> Sessions;
@@ -54,18 +54,19 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl
qpid::sys::Semaphore semaphore;//used to coordinate reconnection
Sessions sessions;
qpid::client::Connection connection;
- std::auto_ptr<FailoverListener> failoverListener;
- qpid::Url url;
+ std::vector<std::string> urls;
qpid::client::ConnectionSettings settings;
- bool reconnectionEnabled;
- int timeout;
- int minRetryInterval;
- int maxRetryInterval;
+ bool reconnect;
+ int64_t timeout;
+ int32_t limit;
+ int64_t minReconnectInterval;
+ int64_t maxReconnectInterval;
+ int32_t retries;
+ void setOptions(const qpid::messaging::Variant::Map& options);
void connect(const qpid::sys::AbsTime& started);
bool tryConnect();
- bool tryConnect(const std::vector<Url>& urls);
- bool tryConnect(const Url&);
+ bool tryConnect(const std::vector<std::string>& urls);
bool resetSessions();
};
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/FailoverUpdates.cpp b/qpid/cpp/src/qpid/client/amqp0_10/FailoverUpdates.cpp
new file mode 100644
index 0000000000..8ef62e4d41
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/FailoverUpdates.cpp
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/amqp0_10/FailoverUpdates.h"
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+#include "qpid/Url.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using namespace qpid::messaging;
+
+struct FailoverUpdatesImpl : qpid::sys::Runnable
+{
+ Connection connection;
+ Session session;
+ Receiver receiver;
+ qpid::sys::Thread thread;
+ volatile bool quit;
+
+ FailoverUpdatesImpl(Connection& c) : connection(c), quit(false)
+ {
+ session = connection.newSession("failover-updates");
+ receiver = session.createReceiver("amq.failover");
+ thread = qpid::sys::Thread(*this);
+ }
+
+ void run()
+ {
+ try {
+ Message message;
+ while (!quit && receiver.fetch(message)) {
+ connection.setOption("urls", message.getHeaders()["amq.failover"]);
+ session.acknowledge();
+ }
+ } catch (const qpid::TransportFailure& e) {
+ QPID_LOG(warning, "Failover updates stopped on loss of connection. " << e.what());
+ } catch (const std::exception& e) {
+ QPID_LOG(warning, "Failover updates stopped due to exception: " << e.what());
+ }
+ receiver.close();
+ session.close();
+ }
+
+ void wait()
+ {
+ quit = true;
+ thread.join();
+ }
+};
+
+FailoverUpdates::FailoverUpdates(Connection& connection) : impl(new FailoverUpdatesImpl(connection)) {}
+FailoverUpdates::~FailoverUpdates() { if (impl) { impl->wait(); delete impl; } }
+FailoverUpdates::FailoverUpdates(const FailoverUpdates&) : impl(0) {}
+FailoverUpdates& FailoverUpdates::operator=(const FailoverUpdates&) { return *this; }
+
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
index e24f2ba5b4..2f52efbceb 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
@@ -57,14 +57,14 @@ qpid::messaging::Message ReceiverImpl::fetch(qpid::messaging::Duration timeout)
bool ReceiverImpl::get(qpid::messaging::Message& message, qpid::messaging::Duration timeout)
{
Get f(*this, message, timeout);
- while (!parent.execute(f)) {}
+ while (!parent->execute(f)) {}
return f.result;
}
bool ReceiverImpl::fetch(qpid::messaging::Message& message, qpid::messaging::Duration timeout)
{
Fetch f(*this, message, timeout);
- while (!parent.execute(f)) {}
+ while (!parent->execute(f)) {}
return f.result;
}
@@ -112,7 +112,7 @@ void ReceiverImpl::init(qpid::client::AsyncSession s, AddressResolution& resolve
}
if (state == CANCELLED) {
source->cancel(session, destination);
- parent.receiverCancelled(destination);
+ parent->receiverCancelled(destination);
} else {
source->subscribe(session, destination);
start();
@@ -129,23 +129,23 @@ uint32_t ReceiverImpl::getCapacity()
uint32_t ReceiverImpl::available()
{
- return parent.available(destination);
+ return parent->available(destination);
}
uint32_t ReceiverImpl::pendingAck()
{
- return parent.pendingAck(destination);
+ return parent->pendingAck(destination);
}
ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name,
const qpid::messaging::Address& a) :
- parent(p), destination(name), address(a), byteCredit(0xFFFFFFFF),
+ parent(&p), destination(name), address(a), byteCredit(0xFFFFFFFF),
state(UNRESOLVED), capacity(0), window(0) {}
bool ReceiverImpl::getImpl(qpid::messaging::Message& message, qpid::messaging::Duration timeout)
{
- return parent.get(*this, message, timeout);
+ return parent->get(*this, message, timeout);
}
bool ReceiverImpl::fetchImpl(qpid::messaging::Message& message, qpid::messaging::Duration timeout)
@@ -172,7 +172,7 @@ void ReceiverImpl::closeImpl()
if (state != CANCELLED) {
state = CANCELLED;
source->cancel(session, destination);
- parent.receiverCancelled(destination);
+ parent->receiverCancelled(destination);
}
}
@@ -188,7 +188,7 @@ void ReceiverImpl::setCapacityImpl(uint32_t c)
}
qpid::messaging::Session ReceiverImpl::getSession() const
{
- return qpid::messaging::Session(&parent);
+ return qpid::messaging::Session(parent.get());
}
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
index 38aa125ec6..689a7f6f25 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
@@ -28,6 +28,7 @@
#include "qpid/client/AsyncSession.h"
#include "qpid/client/amqp0_10/SessionImpl.h"
#include "qpid/messaging/Duration.h"
+#include <boost/intrusive_ptr.hpp>
#include <memory>
namespace qpid {
@@ -65,7 +66,7 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl
void received(qpid::messaging::Message& message);
qpid::messaging::Session getSession() const;
private:
- SessionImpl& parent;
+ boost::intrusive_ptr<SessionImpl> parent;
const std::string destination;
const qpid::messaging::Address address;
const uint32_t byteCredit;
@@ -133,13 +134,13 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl
template <class F> void execute()
{
F f(*this);
- parent.execute(f);
+ parent->execute(f);
}
template <class F, class P> void execute1(P p)
{
F f(*this, p);
- parent.execute(f);
+ parent->execute(f);
}
};
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
index 8782e6e813..9bb785e13f 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -31,17 +31,17 @@ namespace amqp0_10 {
SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name,
const qpid::messaging::Address& _address) :
- parent(_parent), name(_name), address(_address), state(UNRESOLVED),
+ parent(&_parent), name(_name), address(_address), state(UNRESOLVED),
capacity(50), window(0), flushed(false), unreliable(AddressResolution::is_unreliable(address)) {}
void SenderImpl::send(const qpid::messaging::Message& message)
{
if (unreliable) {
UnreliableSend f(*this, &message);
- parent.execute(f);
+ parent->execute(f);
} else {
Send f(*this, &message);
- while (f.repeat) parent.execute(f);
+ while (f.repeat) parent->execute(f);
}
}
@@ -60,7 +60,7 @@ uint32_t SenderImpl::getCapacity() { return capacity; }
uint32_t SenderImpl::pending()
{
CheckPendingSends f(*this, false);
- parent.execute(f);
+ parent->execute(f);
return f.pending;
}
@@ -73,7 +73,7 @@ void SenderImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
}
if (state == CANCELLED) {
sink->cancel(session, name);
- parent.senderCancelled(name);
+ parent->senderCancelled(name);
} else {
sink->declare(session, name);
replay();
@@ -140,7 +140,7 @@ void SenderImpl::closeImpl()
{
state = CANCELLED;
sink->cancel(session, name);
- parent.senderCancelled(name);
+ parent->senderCancelled(name);
}
const std::string& SenderImpl::getName() const
@@ -150,7 +150,7 @@ const std::string& SenderImpl::getName() const
qpid::messaging::Session SenderImpl::getSession() const
{
- return qpid::messaging::Session(&parent);
+ return qpid::messaging::Session(parent.get());
}
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
index b65f8cf8cc..9e4181f42f 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
@@ -28,6 +28,7 @@
#include "qpid/client/AsyncSession.h"
#include "qpid/client/amqp0_10/SessionImpl.h"
#include <memory>
+#include <boost/intrusive_ptr.hpp>
#include <boost/ptr_container/ptr_deque.hpp>
namespace qpid {
@@ -58,7 +59,7 @@ class SenderImpl : public qpid::messaging::SenderImpl
qpid::messaging::Session getSession() const;
private:
- SessionImpl& parent;
+ boost::intrusive_ptr<SessionImpl> parent;
const std::string name;
const qpid::messaging::Address address;
State state;
@@ -143,13 +144,13 @@ class SenderImpl : public qpid::messaging::SenderImpl
template <class F> void execute()
{
F f(*this);
- parent.execute(f);
+ parent->execute(f);
}
template <class F, class P> bool execute1(P p)
{
F f(*this, p);
- return parent.execute(f);
+ return parent->execute(f);
}
};
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
index 9823dba6e1..65308dd0be 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
@@ -24,7 +24,7 @@
#include "qpid/client/amqp0_10/SenderImpl.h"
#include "qpid/client/amqp0_10/MessageSource.h"
#include "qpid/client/amqp0_10/MessageSink.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
#include "qpid/Exception.h"
#include "qpid/log/Statement.h"
#include "qpid/messaging/Address.h"
@@ -49,7 +49,7 @@ namespace qpid {
namespace client {
namespace amqp0_10 {
-SessionImpl::SessionImpl(ConnectionImpl& c, bool t) : connection(c), transactional(t) {}
+SessionImpl::SessionImpl(ConnectionImpl& c, bool t) : connection(&c), transactional(t) {}
void SessionImpl::sync()
@@ -108,13 +108,13 @@ void SessionImpl::close()
for (std::vector<std::string>::const_iterator i = r.begin(); i != r.end(); ++i) getReceiver(*i).close();
- connection.closed(*this);
+ connection->closed(*this);
session.close();
}
template <class T, class S> boost::intrusive_ptr<S> getImplPtr(T& t)
{
- return boost::dynamic_pointer_cast<S>(qpid::client::PrivateImplRef<T>::get(t));
+ return boost::dynamic_pointer_cast<S>(qpid::messaging::PrivateImplRef<T>::get(t));
}
template <class T> void getFreeKey(std::string& key, T& map)
@@ -431,12 +431,12 @@ void SessionImpl::senderCancelled(const std::string& name)
void SessionImpl::reconnect()
{
- connection.reconnect();
+ connection->connect();
}
qpid::messaging::Connection SessionImpl::getConnection() const
{
- return qpid::messaging::Connection(&connection);
+ return qpid::messaging::Connection(connection.get());
}
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
index 285c8f031b..a7eaae3cdd 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
@@ -29,6 +29,7 @@
#include "qpid/client/amqp0_10/AddressResolution.h"
#include "qpid/client/amqp0_10/IncomingMessages.h"
#include "qpid/sys/Mutex.h"
+#include <boost/intrusive_ptr.hpp>
namespace qpid {
@@ -106,7 +107,7 @@ class SessionImpl : public qpid::messaging::SessionImpl
typedef std::map<std::string, qpid::messaging::Sender> Senders;
mutable qpid::sys::Mutex lock;
- ConnectionImpl& connection;
+ boost::intrusive_ptr<ConnectionImpl> connection;
qpid::client::Session session;
AddressResolution resolver;
IncomingMessages incoming;
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp
new file mode 100644
index 0000000000..327c2274a6
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "SimpleUrlParser.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/Exception.h"
+#include <boost/lexical_cast.hpp>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+bool split(const std::string& in, char delim, std::pair<std::string, std::string>& result)
+{
+ std::string::size_type i = in.find(delim);
+ if (i != std::string::npos) {
+ result.first = in.substr(0, i);
+ if (i+1 < in.size()) {
+ result.second = in.substr(i+1);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void parseUsernameAndPassword(const std::string& in, qpid::client::ConnectionSettings& result)
+{
+ std::pair<std::string, std::string> parts;
+ if (!split(in, '/', parts)) {
+ result.username = in;
+ } else {
+ result.username = parts.first;
+ result.password = parts.second;
+ }
+}
+
+void parseHostAndPort(const std::string& in, qpid::client::ConnectionSettings& result)
+{
+ std::pair<std::string, std::string> parts;
+ if (!split(in, ':', parts)) {
+ result.host = in;
+ } else {
+ result.host = parts.first;
+ if (parts.second.size()) {
+ result.port = boost::lexical_cast<uint16_t>(parts.second);
+ }
+ }
+}
+
+void SimpleUrlParser::parse(const std::string& url, qpid::client::ConnectionSettings& result)
+{
+ std::pair<std::string, std::string> parts;
+ if (!split(url, '@', parts)) {
+ parseHostAndPort(url, result);
+ } else {
+ parseUsernameAndPassword(parts.first, result);
+ parseHostAndPort(parts.second, result);
+ }
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h b/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h
new file mode 100644
index 0000000000..24f90ca9d6
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h
@@ -0,0 +1,42 @@
+#ifndef QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H
+#define QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+
+namespace qpid {
+namespace client {
+
+struct ConnectionSettings;
+
+namespace amqp0_10 {
+
+/**
+ * Parses a simple url of the form user/password@hostname:port
+ */
+struct SimpleUrlParser
+{
+ static void parse(const std::string& url, qpid::client::ConnectionSettings& result);
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H*/
diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
index 87df187ab2..40c112f534 100644
--- a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
+++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp
@@ -25,6 +25,7 @@
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/sys/SecurityLayer.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/log/Statement.h"
#include "boost/tokenizer.hpp"
@@ -33,6 +34,7 @@ namespace qpid {
namespace client {
using qpid::sys::SecurityLayer;
+using qpid::sys::SecuritySettings;
using qpid::framing::InternalErrorException;
class WindowsSasl : public Sasl
@@ -40,7 +42,7 @@ class WindowsSasl : public Sasl
public:
WindowsSasl(const ConnectionSettings&);
~WindowsSasl();
- std::string start(const std::string& mechanisms, unsigned int ssf);
+ std::string start(const std::string& mechanisms, const SecuritySettings* externalSettings);
std::string step(const std::string& challenge);
std::string getMechanism();
std::string getUserId();
@@ -91,7 +93,7 @@ WindowsSasl::~WindowsSasl()
}
std::string WindowsSasl::start(const std::string& mechanisms,
- unsigned int /*ssf*/)
+ const SecuritySettings* /*externalSettings*/)
{
QPID_LOG(debug, "WindowsSasl::start(" << mechanisms << ")");
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp
index 460f974b36..f8a875a30c 100644
--- a/qpid/cpp/src/qpid/cluster/Cluster.cpp
+++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp
@@ -16,7 +16,8 @@
*
*/
-/** CLUSTER IMPLEMENTATION OVERVIEW
+/**
+ * <h1>CLUSTER IMPLEMENTATION OVERVIEW</h1>
*
* The cluster works on the principle that if all members of the
* cluster receive identical input, they will all produce identical
@@ -41,12 +42,15 @@
*
* The following are the current areas where broker uses timers or timestamps:
*
- * - Producer flow control: broker::SemanticState uses connection::getClusterOrderOutput.
- * a FrameHandler that sends frames to the client via the cluster. Used by broker::SessionState
+ * - Producer flow control: broker::SemanticState uses
+ * connection::getClusterOrderOutput. a FrameHandler that sends
+ * frames to the client via the cluster. Used by broker::SessionState
*
- * - QueueCleaner, Message TTL: uses ExpiryPolicy, which is implemented by cluster::ExpiryPolicy.
+ * - QueueCleaner, Message TTL: uses ExpiryPolicy, which is
+ * implemented by cluster::ExpiryPolicy.
*
- * - Connection heartbeat: sends connection controls, not part of session command counting so OK to ignore.
+ * - Connection heartbeat: sends connection controls, not part of
+ * session command counting so OK to ignore.
*
* - LinkRegistry: only cluster elder is ever active for links.
*
@@ -57,7 +61,10 @@
*
* cluster::ExpiryPolicy implements the strategy for message expiry.
*
- * CLUSTER PROTOCOL OVERVIEW
+ * ClusterTimer implements periodic timed events in the cluster context.
+ * Used for periodic management events.
+ *
+ * <h1>CLUSTER PROTOCOL OVERVIEW</h1>
*
* Messages sent to/from CPG are called Events.
*
@@ -84,12 +91,16 @@
* - Connection control events carrying non-cluster frames: frames sent to the client.
* e.g. flow-control frames generated on a timer.
*
- * CLUSTER INITIALIZATION OVERVIEW
+ * <h1>CLUSTER INITIALIZATION OVERVIEW</h1>
+ *
+ * @see InitialStatusMap
*
* When a new member joins the CPG group, all members (including the
* new one) multicast their "initial status." The new member is in
- * INIT mode until it gets a complete set of initial status messages
- * from all cluster members.
+ * PRE_INIT mode until it gets a complete set of initial status
+ * messages from all cluster members. In a newly-forming cluster is
+ * then in INIT mode until the configured cluster-size members have
+ * joined.
*
* The newcomer uses initial status to determine
* - The cluster UUID
@@ -97,11 +108,16 @@
* - Do I need to get an update from an existing active member?
* - Can I recover from my own store?
*
- * Initialization happens in the Cluster constructor (plugin
- * early-init phase) because it needs to be done before the store
- * initializes. In INIT mode sending & receiving from the cluster are
- * done single-threaded, bypassing the normal PollableQueues because
- * the Poller is not active at this point to service them.
+ * Pre-initialization happens in the Cluster constructor (plugin
+ * early-init phase) because it needs to set the recovery flag before
+ * the store initializes. This phase lasts until inital-status is
+ * received for all active members. The PollableQueues and Multicaster
+ * are in "bypass" mode during this phase since the poller has not
+ * started so there are no threads to serve pollable queues.
+ *
+ * The remaining initialization happens in Cluster::initialize() or,
+ * if cluster-size=N is specified, in the deliver thread when an
+ * initial-status control is delivered that brings the total to N.
*/
#include "qpid/Exception.h"
#include "qpid/cluster/Cluster.h"
@@ -191,16 +207,19 @@ struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
void initialStatus(uint32_t version, bool active, const Uuid& clusterId,
uint8_t storeState, const Uuid& shutdownId,
- const framing::SequenceNumber& configSeq,
const std::string& firstConfig)
{
cluster.initialStatus(
member, version, active, clusterId,
- framing::cluster::StoreState(storeState), shutdownId, configSeq,
+ framing::cluster::StoreState(storeState), shutdownId,
firstConfig, l);
}
- void ready(const std::string& url) { cluster.ready(member, url, l); }
- void configChange(const std::string& current) { cluster.configChange(member, current, l); }
+ void ready(const std::string& url) {
+ cluster.ready(member, url, l);
+ }
+ void configChange(const std::string& current) {
+ cluster.configChange(member, current, l);
+ }
void updateOffer(uint64_t updatee) {
cluster.updateOffer(member, updatee, l);
}
@@ -241,7 +260,7 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
quorum(boost::bind(&Cluster::leave, this)),
decoder(boost::bind(&Cluster::deliverFrame, this, _1)),
discarding(true),
- state(INIT),
+ state(PRE_INIT),
initMap(self, settings.size),
store(broker.getDataDir().getPath()),
elder(false),
@@ -271,17 +290,18 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
// without modifying delivery-properties.exchange.
broker.getExchanges().registerExchange(
boost::shared_ptr<broker::Exchange>(new UpdateExchange(this)));
+
// Load my store status before we go into initialization
if (! broker::NullMessageStore::isNullStore(&broker.getStore())) {
store.load();
- if (store.getState() == STORE_STATE_DIRTY_STORE)
- broker.setRecovery(false); // Ditch my current store.
if (store.getClusterId())
clusterId = store.getClusterId(); // Use stored ID if there is one.
QPID_LOG(notice, "Cluster store state: " << store)
}
-
cpg.join(name);
+ // pump the CPG dispatch manually till we get past PRE_INIT.
+ while (state == PRE_INIT)
+ cpg.dispatchOne();
}
Cluster::~Cluster() {
@@ -298,9 +318,14 @@ void Cluster::initialize() {
dispatcher.start();
deliverEventQueue.start();
deliverFrameQueue.start();
+ mcast.start();
+
+ // Run initMapCompleted immediately to process the initial configuration.
+ assert(state == INIT);
+ initMapCompleted(*(Mutex::ScopedLock*)0); // Fake lock, single-threaded context.
// Add finalizer last for exception safety.
- broker.addFinalizer(boost::bind(&Cluster::brokerShutdown, this));
+ broker.addFinalizer(boost::bind(&Cluster::brokerShutdown, this));
}
// Called in connection thread to insert a client connection.
@@ -510,8 +535,13 @@ ConnectionPtr Cluster::getConnection(const EventFrame& e, Lock&) {
assert(cp);
}
else { // New remote connection, create a shadow.
- unsigned int ssf = (announce && announce->hasSsf()) ? announce->getSsf() : 0;
- cp = new Connection(*this, shadowOut, announce->getManagementId(), id, ssf);
+ qpid::sys::SecuritySettings secSettings;
+ if (announce) {
+ secSettings.ssf = announce->getSsf();
+ secSettings.authid = announce->getAuthid();
+ secSettings.nodict = announce->getNodict();
+ }
+ cp = new Connection(*this, shadowOut, announce->getManagementId(), id, secSettings);
}
connections.insert(ConnectionMap::value_type(id, cp));
}
@@ -571,9 +601,27 @@ void Cluster::setReady(Lock&) {
void Cluster::initMapCompleted(Lock& l) {
// Called on completion of the initial status map.
QPID_LOG(debug, *this << " initial status map complete. ");
- if (state == INIT) {
- // We have status for all members so we can make join descisions.
+ if (state == PRE_INIT) {
+ // PRE_INIT means we're still in the earlyInitialize phase, in the constructor.
+ // We decide here whether we want to recover from our store.
+ // We won't recover if we are joining an active cluster or our store is dirty.
+ if (store.hasStore() &&
+ (initMap.isActive() || store.getState() == STORE_STATE_DIRTY_STORE))
+ broker.setRecovery(false); // Ditch my current store.
+ state = INIT;
+ }
+ else if (state == INIT) {
+ // INIT means we are past Cluster::initialize().
+
+ // If we're forming an initial cluster (no active members)
+ // then we wait to reach the configured cluster-size
+ if (!initMap.isActive() && initMap.getActualSize() < initMap.getRequiredSize()) {
+ QPID_LOG(info, *this << initMap.getActualSize()
+ << " members, waiting for at least " << initMap.getRequiredSize());
+ return;
+ }
initMap.checkConsistent();
+
elders = initMap.getElders();
QPID_LOG(debug, *this << " elders: " << elders);
if (elders.empty())
@@ -626,7 +674,7 @@ void Cluster::configChange(const MemberId&, const std::string& configStr, Lock&
mcast.mcastControl(
ClusterInitialStatusBody(
ProtocolVersion(), CLUSTER_VERSION, state > INIT, clusterId,
- store.getState(), store.getShutdownId(), store.getConfigSeq(),
+ store.getState(), store.getShutdownId(),
initMap.getFirstConfigStr()
),
self);
@@ -668,15 +716,13 @@ struct AppendQueue {
// Log a snapshot of broker state, used for debugging inconsistency problems.
// May only be called in deliver thread.
-void Cluster::debugSnapshot(const char* prefix, Connection* connection) {
+std::string Cluster::debugSnapshot() {
assertClusterSafe();
std::ostringstream msg;
- msg << prefix;
- if (connection) msg << " " << connection->getId();
- msg << " snapshot " << map.getFrameSeq() << ":";
+ msg << "queue snapshot at " << map.getFrameSeq() << ":";
AppendQueue append(msg);
broker.getQueues().eachQueue(append);
- QPID_LOG(trace, msg.str());
+ return msg.str();
}
// Called from Broker::~Broker when broker is shut down. At this
@@ -702,7 +748,6 @@ void Cluster::initialStatus(const MemberId& member, uint32_t version, bool activ
const framing::Uuid& id,
framing::cluster::StoreState store,
const framing::Uuid& shutdownId,
- const framing::SequenceNumber& configSeq,
const std::string& firstConfig,
Lock& l)
{
@@ -715,7 +760,7 @@ void Cluster::initialStatus(const MemberId& member, uint32_t version, bool activ
initMap.received(
member,
ClusterInitialStatusBody(ProtocolVersion(), version, active, id,
- store, shutdownId, configSeq, firstConfig)
+ store, shutdownId, firstConfig)
);
if (initMap.transitionToComplete()) initMapCompleted(l);
}
@@ -762,8 +807,9 @@ void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, Lock& l)
deliverEventQueue.start(); // Not involved in update.
}
if (updatee != self && url) {
- debugSnapshot("join");
+ QPID_LOG(debug, debugSnapshot());
if (mAgent) mAgent->clusterUpdate();
+ // Updatee will call clusterUpdate when update completes
}
}
@@ -836,7 +882,7 @@ void Cluster::checkUpdateIn(Lock& l) {
if (mAgent) mAgent->suppress(false); // Enable management output.
discarding = false; // ok to set, we're stalled for update.
QPID_LOG(notice, *this << " update complete, starting catch-up.");
- debugSnapshot("initial");
+ QPID_LOG(debug, debugSnapshot());
if (mAgent) mAgent->clusterUpdate();
deliverEventQueue.start();
}
@@ -963,7 +1009,8 @@ void Cluster::memberUpdate(Lock& l) {
std::ostream& operator<<(std::ostream& o, const Cluster& cluster) {
static const char* STATE[] = {
- "INIT", "JOINER", "UPDATEE", "CATCHUP", "READY", "OFFER", "UPDATER", "LEFT"
+ "PRE_INIT", "INIT", "JOINER", "UPDATEE", "CATCHUP",
+ "READY", "OFFER", "UPDATER", "LEFT"
};
assert(sizeof(STATE)/sizeof(*STATE) == Cluster::LEFT+1);
o << "cluster(" << cluster.self << " " << STATE[cluster.state];
@@ -1003,12 +1050,14 @@ void Cluster::errorCheck(const MemberId& from, uint8_t type, framing::SequenceNu
}
void Cluster::timerWakeup(const MemberId& , const std::string& name, Lock&) {
- timer->deliverWakeup(name);
+ if (state >= CATCHUP) // Pre catchup our timer isn't set up.
+ timer->deliverWakeup(name);
}
void Cluster::timerDrop(const MemberId& , const std::string& name, Lock&) {
QPID_LOG(debug, "Cluster timer drop " << map.getFrameSeq() << ": " << name)
- timer->deliverDrop(name);
+ if (state >= CATCHUP) // Pre catchup our timer isn't set up.
+ timer->deliverDrop(name);
}
bool Cluster::isElder() const {
diff --git a/qpid/cpp/src/qpid/cluster/Cluster.h b/qpid/cpp/src/qpid/cluster/Cluster.h
index ffb870606a..4a64ad73d6 100644
--- a/qpid/cpp/src/qpid/cluster/Cluster.h
+++ b/qpid/cpp/src/qpid/cluster/Cluster.h
@@ -120,8 +120,8 @@ class Cluster : private Cpg::Handler, public management::Manageable {
bool isElder() const;
- // For debugging only. Can only be called in deliver thread.
- void debugSnapshot(const char*, Connection* =0);
+ // Generates a log message for debugging purposes.
+ std::string debugSnapshot();
private:
typedef sys::Monitor::ScopedLock Lock;
@@ -160,7 +160,6 @@ class Cluster : private Cpg::Handler, public management::Manageable {
const framing::Uuid& clusterId,
framing::cluster::StoreState,
const framing::Uuid& shutdownId,
- const framing::SequenceNumber& configSeq,
const std::string& firstConfig,
Lock&);
void ready(const MemberId&, const std::string&, Lock&);
@@ -181,6 +180,7 @@ class Cluster : private Cpg::Handler, public management::Manageable {
void memberUpdate(Lock&);
void setClusterId(const framing::Uuid&, Lock&);
void erase(const ConnectionId&, Lock&);
+ void requestUpdate(Lock& );
void initMapCompleted(Lock&);
void becomeElder(Lock&);
@@ -252,7 +252,8 @@ class Cluster : private Cpg::Handler, public management::Manageable {
// Local cluster state, cluster map
enum {
- INIT, ///< Establishing inital cluster stattus.
+ PRE_INIT,///< Have not yet received complete initial status map.
+ INIT, ///< Waiting to reach cluster-size.
JOINER, ///< Sent update request, waiting for update offer.
UPDATEE, ///< Stalled receive queue at update offer, waiting for update to complete.
CATCHUP, ///< Update complete, unstalled but has not yet seen own "ready" event.
diff --git a/qpid/cpp/src/qpid/cluster/Connection.cpp b/qpid/cpp/src/qpid/cluster/Connection.cpp
index 909ff68d92..1166f685d2 100644
--- a/qpid/cpp/src/qpid/cluster/Connection.cpp
+++ b/qpid/cpp/src/qpid/cluster/Connection.cpp
@@ -77,9 +77,9 @@ const std::string shadowPrefix("[shadow]");
// Shadow connection
Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
const std::string& mgmtId,
- const ConnectionId& id, unsigned int ssf)
+ const ConnectionId& id, const qpid::sys::SecuritySettings& external)
: cluster(c), self(id), catchUp(false), output(*this, out),
- connectionCtor(&output, cluster.getBroker(), mgmtId, ssf, false, 0, true),
+ connectionCtor(&output, cluster.getBroker(), mgmtId, external, false, 0, true),
expectProtocolHeader(false),
mcastFrameHandler(cluster.getMulticast(), self),
updateIn(c.getUpdateReceiver())
@@ -88,11 +88,11 @@ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
// Local connection
Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
const std::string& mgmtId, MemberId member,
- bool isCatchUp, bool isLink, unsigned int ssf
+ bool isCatchUp, bool isLink, const qpid::sys::SecuritySettings& external
) : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), output(*this, out),
connectionCtor(&output, cluster.getBroker(),
mgmtId,
- ssf,
+ external,
isLink,
isCatchUp ? ++catchUpId : 0,
isCatchUp), // isCatchUp => shadow
@@ -107,7 +107,10 @@ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
QPID_LOG(info, "new client connection " << *this);
giveReadCredit(cluster.getSettings().readMax);
cluster.getMulticast().mcastControl(
- ClusterConnectionAnnounceBody(ProtocolVersion(), mgmtId, getSsf()), getId());
+ ClusterConnectionAnnounceBody(ProtocolVersion(), mgmtId,
+ connectionCtor.external.ssf,
+ connectionCtor.external.authid,
+ connectionCtor.external.nodict), getId());
}
else {
// Catch-up shadow connections initialized using nextShadow id.
@@ -122,7 +125,7 @@ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
void Connection::init() {
connection = connectionCtor.construct();
QPID_LOG(debug, cluster << " initialized connection: " << *this
- << " ssf=" << connection->getSSF());
+ << " ssf=" << connection->getExternalSecuritySettings().ssf);
if (isLocalClient()) {
// Actively send cluster-order frames from local node
connection->setClusterOrderOutput(mcastFrameHandler);
@@ -142,9 +145,11 @@ void Connection::giveReadCredit(int credit) {
output.giveReadCredit(credit);
}
-void Connection::announce(const std::string& mgmtId, uint32_t ssf) {
+void Connection::announce(const std::string& mgmtId, uint32_t ssf, const std::string& authid, bool nodict) {
QPID_ASSERT(mgmtId == connectionCtor.mgmtId);
- QPID_ASSERT(ssf == connectionCtor.ssf);
+ QPID_ASSERT(ssf == connectionCtor.external.ssf);
+ QPID_ASSERT(authid == connectionCtor.external.authid);
+ QPID_ASSERT(nodict == connectionCtor.external.nodict);
init();
}
@@ -537,7 +542,7 @@ void Connection::addQueueListener(const std::string& q, uint32_t listener) {
void Connection::managementSchema(const std::string& data) {
management::ManagementAgent* agent = cluster.getBroker().getManagementAgent();
if (!agent)
- throw Exception(QPID_MSG("Management schema update but no management agent."));
+ throw Exception(QPID_MSG("Management schema update but management not enabled."));
framing::Buffer buf(const_cast<char*>(data.data()), data.size());
agent->importSchemas(buf);
QPID_LOG(debug, cluster << " updated management schemas");
@@ -552,7 +557,7 @@ void Connection::managementSetupState(uint64_t objectNum, uint16_t bootSequence)
<< objectNum << " seq " << bootSequence);
management::ManagementAgent* agent = cluster.getBroker().getManagementAgent();
if (!agent)
- throw Exception(QPID_MSG("Management schema update but no management agent."));
+ throw Exception(QPID_MSG("Management schema update but management not enabled."));
agent->setNextObjectId(objectNum);
agent->setBootSequence(bootSequence);
}
@@ -560,7 +565,7 @@ void Connection::managementSetupState(uint64_t objectNum, uint16_t bootSequence)
void Connection::managementAgents(const std::string& data) {
management::ManagementAgent* agent = cluster.getBroker().getManagementAgent();
if (!agent)
- throw Exception(QPID_MSG("Management agents update but no management agent."));
+ throw Exception(QPID_MSG("Management agent update but management not enabled."));
framing::Buffer buf(const_cast<char*>(data.data()), data.size());
agent->importAgents(buf);
QPID_LOG(debug, cluster << " updated management agents");
diff --git a/qpid/cpp/src/qpid/cluster/Connection.h b/qpid/cpp/src/qpid/cluster/Connection.h
index 85fad72948..2f72783418 100644
--- a/qpid/cpp/src/qpid/cluster/Connection.h
+++ b/qpid/cpp/src/qpid/cluster/Connection.h
@@ -34,6 +34,7 @@
#include "qpid/sys/AtomicValue.h"
#include "qpid/sys/ConnectionInputHandler.h"
#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/framing/SequenceNumber.h"
#include "qpid/framing/FrameDecoder.h"
@@ -66,10 +67,10 @@ class Connection :
/** Local connection. */
Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, MemberId, bool catchUp, bool isLink,
- unsigned int ssf);
+ const qpid::sys::SecuritySettings& external);
/** Shadow connection. */
Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, const ConnectionId& id,
- unsigned int ssf);
+ const qpid::sys::SecuritySettings& external);
~Connection();
ConnectionId getId() const { return self; }
@@ -163,7 +164,7 @@ class Connection :
void exchange(const std::string& encoded);
void giveReadCredit(int credit);
- void announce(const std::string& mgmtId, uint32_t ssf);
+ void announce(const std::string& mgmtId, uint32_t ssf, const std::string& authid, bool nodict);
void abort();
void deliverClose();
@@ -174,7 +175,7 @@ class Connection :
void managementAgents(const std::string& data);
void managementSetupState(uint64_t objectNum, uint16_t bootSequence);
- uint32_t getSsf() const { return connectionCtor.ssf; }
+ //uint32_t getSsf() const { return connectionCtor.external.ssf; }
private:
struct NullFrameHandler : public framing::FrameHandler {
@@ -186,7 +187,7 @@ class Connection :
sys::ConnectionOutputHandler* out;
broker::Broker& broker;
std::string mgmtId;
- unsigned int ssf;
+ qpid::sys::SecuritySettings external;
bool isLink;
uint64_t objectId;
bool shadow;
@@ -195,17 +196,17 @@ class Connection :
sys::ConnectionOutputHandler* out_,
broker::Broker& broker_,
const std::string& mgmtId_,
- unsigned int ssf_,
+ const qpid::sys::SecuritySettings& external_,
bool isLink_=false,
uint64_t objectId_=0,
bool shadow_=false
- ) : out(out_), broker(broker_), mgmtId(mgmtId_), ssf(ssf_),
+ ) : out(out_), broker(broker_), mgmtId(mgmtId_), external(external_),
isLink(isLink_), objectId(objectId_), shadow(shadow_)
{}
std::auto_ptr<broker::Connection> construct() {
return std::auto_ptr<broker::Connection>(
- new broker::Connection(out, broker, mgmtId, ssf, isLink, objectId, shadow));
+ new broker::Connection(out, broker, mgmtId, external, isLink, objectId, shadow));
}
};
diff --git a/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp b/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp
index 8f6f1d9ad5..931cda4893 100644
--- a/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp
+++ b/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp
@@ -37,26 +37,26 @@ using namespace framing;
sys::ConnectionCodec*
ConnectionCodec::Factory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
- unsigned int ssf) {
+ const qpid::sys::SecuritySettings& external) {
if (v == ProtocolVersion(0, 10))
- return new ConnectionCodec(v, out, id, cluster, false, false, ssf);
+ return new ConnectionCodec(v, out, id, cluster, false, false, external);
else if (v == ProtocolVersion(0x80 + 0, 0x80 + 10)) // Catch-up connection
- return new ConnectionCodec(v, out, id, cluster, true, false, ssf);
+ return new ConnectionCodec(v, out, id, cluster, true, false, external);
return 0;
}
// Used for outgoing Link connections
sys::ConnectionCodec*
ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& logId,
- unsigned int ssf) {
- return new ConnectionCodec(ProtocolVersion(0,10), out, logId, cluster, false, true, ssf);
+ const qpid::sys::SecuritySettings& external) {
+ return new ConnectionCodec(ProtocolVersion(0,10), out, logId, cluster, false, true, external);
}
ConnectionCodec::ConnectionCodec(
const ProtocolVersion& v, sys::OutputControl& out,
- const std::string& logId, Cluster& cluster, bool catchUp, bool isLink, unsigned int ssf
+ const std::string& logId, Cluster& cluster, bool catchUp, bool isLink, const qpid::sys::SecuritySettings& external
) : codec(out, logId, isLink),
- interceptor(new Connection(cluster, codec, logId, cluster.getId(), catchUp, isLink, ssf))
+ interceptor(new Connection(cluster, codec, logId, cluster.getId(), catchUp, isLink, external))
{
std::auto_ptr<sys::ConnectionInputHandler> ih(new ProxyInputHandler(interceptor));
codec.setInputHandler(ih);
diff --git a/qpid/cpp/src/qpid/cluster/ConnectionCodec.h b/qpid/cpp/src/qpid/cluster/ConnectionCodec.h
index 74cb3c507d..4b919ed351 100644
--- a/qpid/cpp/src/qpid/cluster/ConnectionCodec.h
+++ b/qpid/cpp/src/qpid/cluster/ConnectionCodec.h
@@ -53,14 +53,14 @@ class ConnectionCodec : public sys::ConnectionCodec {
Factory(boost::shared_ptr<sys::ConnectionCodec::Factory> f, Cluster& c)
: next(f), cluster(c) {}
sys::ConnectionCodec* create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ const qpid::sys::SecuritySettings& external);
sys::ConnectionCodec* create(sys::OutputControl&, const std::string& id,
- unsigned int conn_ssf);
+ const qpid::sys::SecuritySettings& external);
};
ConnectionCodec(const framing::ProtocolVersion&, sys::OutputControl& out,
const std::string& logId, Cluster& c, bool catchUp, bool isLink,
- unsigned int ssf);
+ const qpid::sys::SecuritySettings& external);
~ConnectionCodec();
// ConnectionCodec functions.
diff --git a/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp b/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp
index a1a1456618..c8ecc13f2c 100644
--- a/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp
+++ b/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp
@@ -86,8 +86,7 @@ bool InitialStatusMap::notInitialized(const Map::value_type& v) {
}
bool InitialStatusMap::isComplete() const {
- return !map.empty() && find_if(map.begin(), map.end(), &notInitialized) == map.end()
- && (map.size() >= size);
+ return !map.empty() && find_if(map.begin(), map.end(), &notInitialized) == map.end();
}
bool InitialStatusMap::transitionToComplete() {
@@ -100,7 +99,7 @@ bool InitialStatusMap::isResendNeeded() {
return ret;
}
-bool InitialStatusMap::isActive(const Map::value_type& v) {
+bool InitialStatusMap::isActiveEntry(const Map::value_type& v) {
return v.second && v.second->getActive();
}
@@ -110,10 +109,15 @@ bool InitialStatusMap::hasStore(const Map::value_type& v) {
v.second->getStoreState() == STORE_STATE_DIRTY_STORE);
}
+bool InitialStatusMap::isActive() {
+ assert(isComplete());
+ return (find_if(map.begin(), map.end(), &isActiveEntry) != map.end());
+}
+
bool InitialStatusMap::isUpdateNeeded() {
assert(isComplete());
// We need an update if there are any active members.
- if (find_if(map.begin(), map.end(), &isActive) != map.end()) return true;
+ if (isActive()) return true;
// Otherwise it depends on store status, get my own status:
Map::iterator me = map.find(self);
@@ -154,7 +158,7 @@ MemberSet InitialStatusMap::getElders() const {
Uuid InitialStatusMap::getClusterId() {
assert(isComplete());
assert(!map.empty());
- Map::iterator i = find_if(map.begin(), map.end(), &isActive);
+ Map::iterator i = find_if(map.begin(), map.end(), &isActiveEntry);
if (i != map.end())
return i->second->getClusterId(); // An active member
else
@@ -178,6 +182,7 @@ void InitialStatusMap::checkConsistent() {
Uuid clusterId;
Uuid shutdownId;
+ bool initialCluster = !isActive();
for (Map::iterator i = map.begin(); i != map.end(); ++i) {
assert(i->second);
if (i->second->getActive()) ++active;
@@ -193,8 +198,10 @@ void InitialStatusMap::checkConsistent() {
++clean;
checkId(clusterId, i->second->getClusterId(),
"Cluster-ID mismatch. Stores belong to different clusters.");
- checkId(shutdownId, i->second->getShutdownId(),
- "Shutdown-ID mismatch. Stores were not shut down together");
+ // Only need shutdownId to match if we are in an initially forming cluster.
+ if (initialCluster)
+ checkId(shutdownId, i->second->getShutdownId(),
+ "Shutdown-ID mismatch. Stores were not shut down together");
break;
}
}
@@ -202,10 +209,13 @@ void InitialStatusMap::checkConsistent() {
if (none && (clean+dirty+empty))
throw Exception("Mixing transient and persistent brokers in a cluster");
- // If there are no active members and there are dirty stores there
- // must be at least one clean store.
- if (!active && dirty && !clean)
- throw Exception("Cannot recover, no clean store.");
+ if (map.size() >= size) {
+ // All initial members are present. If there are no active
+ // members and there are dirty stores there must be at least
+ // one clean store.
+ if (!active && dirty && !clean)
+ throw Exception("Cannot recover, no clean store.");
+ }
}
std::string InitialStatusMap::getFirstConfigStr() const {
diff --git a/qpid/cpp/src/qpid/cluster/InitialStatusMap.h b/qpid/cpp/src/qpid/cluster/InitialStatusMap.h
index 26a99fa0b0..a5a600365e 100644
--- a/qpid/cpp/src/qpid/cluster/InitialStatusMap.h
+++ b/qpid/cpp/src/qpid/cluster/InitialStatusMap.h
@@ -31,6 +31,11 @@ namespace cluster {
/**
* Track status of cluster members during initialization.
+ *
+ * When a new member joins the CPG cluster, all members send an initial-status
+ * control. This map tracks those controls and provides data to make descisions
+ * about joining the cluster.
+ *
*/
class InitialStatusMap
{
@@ -38,7 +43,7 @@ class InitialStatusMap
typedef framing::ClusterInitialStatusBody Status;
InitialStatusMap(const MemberId& self, size_t size);
- /** Process a config change. @return true if we need to re-send our status */
+ /** Process a config change. May make isResendNeeded() true. */
void configChange(const MemberSet& newConfig);
/** @return true if we need to re-send status */
bool isResendNeeded();
@@ -46,13 +51,19 @@ class InitialStatusMap
/** Process received status */
void received(const MemberId&, const Status& is);
- /**@return true if the map is complete. */
+ /**@return true if the map has an entry for all current cluster members. */
bool isComplete() const;
+
+ size_t getActualSize() const { return map.size(); }
+ size_t getRequiredSize() const { return size; }
+
/**@return true if the map was completed by the last config change or received. */
bool transitionToComplete();
/**@pre isComplete(). @return this node's elders */
MemberSet getElders() const;
- /**@pre isComplete(). @return True if we need an update. */
+ /**@pre isComplete(). @return True if there are active members of the cluster. */
+ bool isActive();
+ /**@pre isComplete(). @return True if we need to request an update. */
bool isUpdateNeeded();
/**@pre isComplete(). @return Cluster-wide cluster ID. */
framing::Uuid getClusterId();
@@ -66,8 +77,9 @@ class InitialStatusMap
private:
typedef std::map<MemberId, boost::optional<Status> > Map;
static bool notInitialized(const Map::value_type&);
- static bool isActive(const Map::value_type&);
+ static bool isActiveEntry(const Map::value_type&);
static bool hasStore(const Map::value_type&);
+
Map map;
MemberSet firstConfig;
MemberId self;
diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.cpp b/qpid/cpp/src/qpid/cluster/Multicaster.cpp
index 4a8195438f..d57ff76941 100644
--- a/qpid/cpp/src/qpid/cluster/Multicaster.cpp
+++ b/qpid/cpp/src/qpid/cluster/Multicaster.cpp
@@ -33,10 +33,8 @@ Multicaster::Multicaster(Cpg& cpg_,
boost::function<void()> onError_) :
onError(onError_), cpg(cpg_),
queue(boost::bind(&Multicaster::sendMcast, this, _1), poller),
- ready(false)
-{
- queue.start();
-}
+ ready(false), bypass(true)
+{}
void Multicaster::mcastControl(const framing::AMQBody& body, const ConnectionId& id) {
mcast(Event::control(body, id));
@@ -61,10 +59,16 @@ void Multicaster::mcast(const Event& e) {
}
}
QPID_LOG(trace, "MCAST " << e);
- queue.push(e);
+ if (bypass) { // direct, don't queue
+ iovec iov = e.toIovec();
+ // FIXME aconway 2010-03-10: should do limited retry.
+ while (!cpg.mcast(&iov, 1))
+ ;
+ }
+ else
+ queue.push(e);
}
-
Multicaster::PollableEventQueue::Batch::const_iterator Multicaster::sendMcast(const PollableEventQueue::Batch& values) {
try {
PollableEventQueue::Batch::const_iterator i = values.begin();
@@ -86,6 +90,11 @@ Multicaster::PollableEventQueue::Batch::const_iterator Multicaster::sendMcast(co
}
}
+void Multicaster::start() {
+ queue.start();
+ bypass = false;
+}
+
void Multicaster::setReady() {
sys::Mutex::ScopedLock l(lock);
ready = true;
diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.h b/qpid/cpp/src/qpid/cluster/Multicaster.h
index 2db84a9ce0..f70bd5ca31 100644
--- a/qpid/cpp/src/qpid/cluster/Multicaster.h
+++ b/qpid/cpp/src/qpid/cluster/Multicaster.h
@@ -41,16 +41,18 @@ class Cpg;
/**
* Multicast to the cluster. Shared, thread safe object.
- *
- * Runs in two modes;
*
- * initializing: Hold connection mcast events. Multicast cluster
- * events directly in the calling thread. This mode is used before
- * joining the cluster where the poller may not yet be active and we
- * want to hold any connection traffic till we join.
+ * holding mode: Hold connection events for later multicast. Cluster
+ * events are never held. Used during PRE_INIT/INIT state when we
+ * want to hold any connection traffic till we are read in the
+ * cluster.
+ *
+ * bypass mode: Multicast cluster events directly in the calling
+ * thread. This mode is used by cluster in PRE_INIT state the poller
+ * is not yet be active.
*
- * ready: normal operation. Queues all mcasts on a pollable queue,
- * multicasts connection and cluster events.
+ * Multicaster is created in bypass+holding mode, they are disabled by
+ * start and setReady respectively.
*/
class Multicaster
{
@@ -65,7 +67,9 @@ class Multicaster
void mcastBuffer(const char*, size_t, const ConnectionId&);
void mcast(const Event& e);
- /** Switch to ready mode. */
+ /** Start the pollable queue, turn off bypass mode. */
+ void start();
+ /** Switch to ready mode, release held messages. */
void setReady();
private:
@@ -81,6 +85,7 @@ class Multicaster
bool ready;
PlainEventQueue holdingQueue;
std::vector<struct ::iovec> ioVector;
+ bool bypass;
};
}} // namespace qpid::cluster
diff --git a/qpid/cpp/src/qpid/cluster/PollableQueue.h b/qpid/cpp/src/qpid/cluster/PollableQueue.h
index 2aed6de5b9..59d0bcd36a 100644
--- a/qpid/cpp/src/qpid/cluster/PollableQueue.h
+++ b/qpid/cpp/src/qpid/cluster/PollableQueue.h
@@ -31,6 +31,13 @@ namespace cluster {
/**
* More convenient version of PollableQueue that handles iterating
* over the batch and error handling.
+ *
+ * Constructed in "bypass" mode where items are processed directly
+ * rather than put on the queue. This is important for the
+ * PRE_INIT stage when Cluster is pumping CPG dispatch directly
+ * before the poller has started.
+ *
+ * Calling start() starts the pollable queue and disabled bypass mode.
*/
template <class T> class PollableQueue : public sys::PollableQueue<T> {
public:
@@ -41,7 +48,7 @@ template <class T> class PollableQueue : public sys::PollableQueue<T> {
const boost::shared_ptr<sys::Poller>& poller)
: sys::PollableQueue<T>(boost::bind(&PollableQueue<T>::handleBatch, this, _1),
poller),
- callback(f), error(err), message(msg)
+ callback(f), error(err), message(msg), bypass(true)
{}
typename sys::PollableQueue<T>::Batch::const_iterator
@@ -62,10 +69,21 @@ template <class T> class PollableQueue : public sys::PollableQueue<T> {
}
}
+ void push(const T& t) {
+ if (bypass) callback(t);
+ else sys::PollableQueue<T>::push(t);
+ }
+
+ void start() {
+ bypass = false;
+ sys::PollableQueue<T>::start();
+ }
+
private:
Callback callback;
ErrorCallback error;
std::string message;
+ bool bypass;
};
diff --git a/qpid/cpp/src/qpid/cluster/StoreStatus.cpp b/qpid/cpp/src/qpid/cluster/StoreStatus.cpp
index 648fcfbbd5..b44c0e1a9a 100644
--- a/qpid/cpp/src/qpid/cluster/StoreStatus.cpp
+++ b/qpid/cpp/src/qpid/cluster/StoreStatus.cpp
@@ -21,6 +21,7 @@
#include "StoreStatus.h"
#include "qpid/Exception.h"
#include "qpid/Msg.h"
+#include "qpid/log/Statement.h"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
@@ -54,24 +55,39 @@ Uuid loadUuid(const fs::path& path) {
Uuid ret;
if (exists(path)) {
fs::ifstream i(path);
- throw_exceptions(i);
- i >> ret;
+ try {
+ throw_exceptions(i);
+ i >> ret;
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Cant load UUID from " << path.string() << ": " << e.what());
+ throw;
+ }
}
return ret;
}
void saveUuid(const fs::path& path, const Uuid& uuid) {
fs::ofstream o(path);
- throw_exceptions(o);
- o << uuid;
+ try {
+ throw_exceptions(o);
+ o << uuid;
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Cant save UUID to " << path.string() << ": " << e.what());
+ throw;
+ }
}
framing::SequenceNumber loadSeqNum(const fs::path& path) {
uint32_t n = 0;
if (exists(path)) {
fs::ifstream i(path);
- throw_exceptions(i);
- i >> n;
+ try {
+ throw_exceptions(i);
+ i >> n;
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Cant load sequence number from " << path.string() << ": " << e.what());
+ throw;
+ }
}
return framing::SequenceNumber(n);
}
@@ -105,9 +121,14 @@ void StoreStatus::save() {
create_directory(dir);
saveUuid(dir/CLUSTER_ID_FILE, clusterId);
saveUuid(dir/SHUTDOWN_ID_FILE, shutdownId);
- fs::ofstream o(dir/CONFIG_SEQ_FILE);
- throw_exceptions(o);
- o << configSeq.getValue();
+ try {
+ fs::ofstream o(dir/CONFIG_SEQ_FILE);
+ throw_exceptions(o);
+ o << configSeq.getValue();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Cant save sequence number to " << (dir/CONFIG_SEQ_FILE).string() << ": " << e.what());
+ throw;
+ }
}
catch (const std::exception&e) {
throw Exception(QPID_MSG("Cannot save cluster store status: " << e.what()));
diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
index 17d856b79c..ab992bf8cf 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
+++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -158,6 +158,12 @@ void UpdateClient::update() {
connection.close();
QPID_LOG(debug, updaterId << " update completed to " << updateeId
<< " at " << updateeUrl << ": " << membership);
+ // FIXME aconway 2010-03-15: This sleep avoids the race condition
+ // described in // https://bugzilla.redhat.com/show_bug.cgi?id=568831.
+ // It allows the connection to fully close before destroying the
+ // Connection object. Remove when the bug is fixed.
+ //
+ sys::usleep(10*1000); // 100ms
}
namespace {
diff --git a/qpid/cpp/src/qpid/framing/FieldValue.cpp b/qpid/cpp/src/qpid/framing/FieldValue.cpp
index fd911645f4..ce5a50117c 100644
--- a/qpid/cpp/src/qpid/framing/FieldValue.cpp
+++ b/qpid/cpp/src/qpid/framing/FieldValue.cpp
@@ -130,6 +130,21 @@ Str16Value::Str16Value(const std::string& v) :
reinterpret_cast<const uint8_t*>(v.data()+v.size())))
{}
+Var16Value::Var16Value(const std::string& v, uint8_t code) :
+ FieldValue(
+ code,
+ new VariableWidthValue<2>(
+ reinterpret_cast<const uint8_t*>(v.data()),
+ reinterpret_cast<const uint8_t*>(v.data()+v.size())))
+{}
+Var32Value::Var32Value(const std::string& v, uint8_t code) :
+ FieldValue(
+ code,
+ new VariableWidthValue<4>(
+ reinterpret_cast<const uint8_t*>(v.data()),
+ reinterpret_cast<const uint8_t*>(v.data()+v.size())))
+{}
+
Struct32Value::Struct32Value(const std::string& v) :
FieldValue(
0xAB,
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index bbb14f98e9..c3cd7e008f 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -96,11 +96,13 @@ ManagementAgent::~ManagementAgent ()
Mutex::ScopedLock lock (userLock);
// Reset the shared pointers to exchanges. If this is not done now, the exchanges
- // will stick around until dExchange and mExchange are implicitely destroyed (long
+ // will stick around until dExchange and mExchange are implicitly destroyed (long
// after this destructor completes). Those exchanges hold references to management
// objects that will be invalid.
dExchange.reset();
mExchange.reset();
+ v2Topic.reset();
+ v2Direct.reset();
moveNewObjectsLH();
for (ManagementObjectMap::iterator iter = managementObjects.begin ();
@@ -183,13 +185,20 @@ void ManagementAgent::writeData ()
}
}
-void ManagementAgent::setExchange (qpid::broker::Exchange::shared_ptr _mexchange,
- qpid::broker::Exchange::shared_ptr _dexchange)
+void ManagementAgent::setExchange(qpid::broker::Exchange::shared_ptr _mexchange,
+ qpid::broker::Exchange::shared_ptr _dexchange)
{
mExchange = _mexchange;
dExchange = _dexchange;
}
+void ManagementAgent::setExchangeV2(qpid::broker::Exchange::shared_ptr _texchange,
+ qpid::broker::Exchange::shared_ptr _dexchange)
+{
+ v2Topic = _texchange;
+ v2Direct = _dexchange;
+}
+
void ManagementAgent::registerClass (const string& packageName,
const string& className,
uint8_t* md5Sum,
@@ -210,22 +219,19 @@ void ManagementAgent::registerEvent (const string& packageName,
addClassLH(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall);
}
-
// Deprecated:
-ObjectId ManagementAgent::addObject(ManagementObject* object, uint64_t persistId, bool publishNow)
+ObjectId ManagementAgent::addObject(ManagementObject* object, uint64_t persistId)
{
// always force object to generate key string
- return addObject(object, std::string(), persistId != 0, publishNow);
+ return addObject(object, std::string(), persistId != 0);
}
ObjectId ManagementAgent::addObject(ManagementObject* object,
const std::string& key,
- bool persistent,
- bool publishNow)
+ bool persistent)
{
- Mutex::ScopedLock lock (addLock);
uint16_t sequence;
sequence = persistent ? 0 : bootSequence;
@@ -238,45 +244,21 @@ ObjectId ManagementAgent::addObject(ManagementObject* object,
}
object->setObjectId(objId);
- ManagementObjectMap::iterator destIter = newManagementObjects.find(objId);
- if (destIter != newManagementObjects.end()) {
- if (destIter->second->isDeleted()) {
- newDeletedManagementObjects.push_back(destIter->second);
- newManagementObjects.erase(destIter);
- } else {
- QPID_LOG(error, "ObjectId collision in addObject. class=" << object->getClassName() <<
- " key=" << objId.getV2Key());
- return objId;
- }
- }
- newManagementObjects[objId] = object;
-
- if (publishNow) {
- ::qpid::messaging::Message m;
- ::qpid::messaging::ListContent content(m);
- ::qpid::messaging::Variant::List &list_ = content.asList();
- ::qpid::messaging::Variant::Map map_;
- ::qpid::messaging::Variant::Map values;
- ::qpid::messaging::Variant::Map headers;
-
- map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(),
- object->getClassName(),
- "_data",
- object->getMd5Sum());
- object->mapEncodeValues(values, true, false); // send props only
- map_["_values"] = values;
- list_.push_back(map_);
-
- headers["method"] = "indication";
- headers["qmf.opcode"] = "_data_indication";
- headers["qmf.content"] = "_data";
- headers["qmf.agent"] = std::string(agentName);
- content.encode();
- stringstream key;
- key << "console.obj.1.0." << object->getPackageName() << "." << object->getClassName();
- sendBuffer(m.getContent(), 0, headers, mExchange, key.str());
- QPID_LOG(trace, "SEND Immediate ContentInd to=" << key.str());
+ {
+ Mutex::ScopedLock lock (addLock);
+ ManagementObjectMap::iterator destIter = newManagementObjects.find(objId);
+ if (destIter != newManagementObjects.end()) {
+ if (destIter->second->isDeleted()) {
+ newDeletedManagementObjects.push_back(destIter->second);
+ newManagementObjects.erase(destIter);
+ } else {
+ QPID_LOG(error, "ObjectId collision in addObject. class=" << object->getClassName() <<
+ " key=" << objId.getV2Key());
+ return objId;
+ }
+ }
+ newManagementObjects[objId] = object;
}
return objId;
@@ -350,11 +332,11 @@ void ManagementAgent::clientAdded (const std::string& routingKey)
}
void ManagementAgent::clusterUpdate() {
- // Called on all cluster memebesr when a new member joins a cluster.
+ // Called on all cluster memebers when a new member joins a cluster.
// Set clientWasAdded so that on the next periodicProcessing we will do
// a full update on all cluster members.
clientWasAdded = true;
- debugSnapshot("update");
+ QPID_LOG(debug, "cluster update " << debugSnapshot());
}
void ManagementAgent::encodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
@@ -670,7 +652,7 @@ void ManagementAgent::periodicProcessing (void)
sendBuffer (msgBuffer, contentSize, mExchange, routingKey);
QPID_LOG(trace, "SEND HeartbeatInd to=" << routingKey);
}
- debugSnapshot("periodic");
+ QPID_LOG(debug, "periodic update " << debugSnapshot());
}
void ManagementAgent::deleteObjectNowLH(const ObjectId& oid)
@@ -1271,7 +1253,7 @@ void ManagementAgent::handleAttachRequestLH (Buffer& inBuffer, string replyToKey
agent->mgmtObject->set_systemId ((const unsigned char*)systemId.data());
agent->mgmtObject->set_brokerBank (brokerBank);
agent->mgmtObject->set_agentBank (assignedBank);
- addObject (agent->mgmtObject, 0, true);
+ addObject (agent->mgmtObject, 0);
remoteAgents[connectionRef] = agent;
QPID_LOG(trace, "Remote Agent registered bank=[" << brokerBank << "." << assignedBank << "] replyTo=" << replyToKey);
@@ -1893,13 +1875,13 @@ size_t ManagementAgent::validateEventSchema(Buffer& inBuffer)
void ManagementAgent::setAllocator(std::auto_ptr<IdAllocator> a)
{
- Mutex::ScopedLock lock (addLock);
+ Mutex::ScopedLock lock (userLock);
allocator = a;
}
uint64_t ManagementAgent::allocateId(Manageable* object)
{
- Mutex::ScopedLock lock (addLock);
+ Mutex::ScopedLock lock (userLock);
if (allocator.get()) return allocator->getIdFor(object);
return 0;
}
@@ -2031,7 +2013,7 @@ void ManagementAgent::importSchemas(qpid::framing::Buffer& inBuf) {
void ManagementAgent::RemoteAgent::mapEncode(qpid::messaging::Variant::Map& map_) const {
::qpid::messaging::VariantMap _objId, _values;
-
+
map_["_brokerBank"] = brokerBank;
map_["_agentBank"] = agentBank;
map_["_routingKey"] = routingKey;
@@ -2068,10 +2050,10 @@ void ManagementAgent::RemoteAgent::mapDecode(const qpid::messaging::Variant::Map
mgmtObject->mapDecodeValues(i->second.asMap());
}
- agent.addObject(mgmtObject, 0, true);
+ // TODO aconway 2010-03-04: see comment in encode(), readProperties doesn't set v2key.
+ mgmtObject->set_connectionRef(connectionRef);
}
-
void ManagementAgent::exportAgents(std::string& out) {
::qpid::messaging::Message m;
::qpid::messaging::ListContent content(m);
@@ -2082,15 +2064,12 @@ void ManagementAgent::exportAgents(std::string& out) {
i != remoteAgents.end();
++i)
{
- ObjectId id = i->first;
+ // TODO aconway 2010-03-04: see comment in ManagementAgent::RemoteAgent::encode
RemoteAgent* agent = i->second;
map_.clear();
- omap.clear();
amap.clear();
- id.mapEncode(omap);
- map_["_object_id"] = omap;
agent->mapEncode(amap);
map_["_remote_agent"] = amap;
list_.push_back(map_);
@@ -2123,16 +2102,16 @@ void ManagementAgent::importAgents(qpid::framing::Buffer& inBuf) {
}
}
-void ManagementAgent::debugSnapshot(const char* type) {
+std::string ManagementAgent::debugSnapshot() {
std::ostringstream msg;
- msg << type << " snapshot, agents:";
+ msg << " management snapshot:";
for (RemoteAgentMap::const_iterator i=remoteAgents.begin();
i != remoteAgents.end(); ++i)
msg << " " << i->second->routingKey;
msg << " packages: " << packages.size();
msg << " objects: " << managementObjects.size();
msg << " new objects: " << newManagementObjects.size();
- QPID_LOG(trace, msg.str());
+ return msg.str();
}
qpid::messaging::Variant::Map ManagementAgent::toMap(const FieldTable& from)
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.h b/qpid/cpp/src/qpid/management/ManagementAgent.h
index 9ec28500c4..675bcb7774 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.h
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.h
@@ -75,9 +75,12 @@ public:
/** Called by cluster to suppress management output during update. */
void suppress(bool s) { suppressed = s; }
- void setInterval (uint16_t _interval) { interval = _interval; }
- void setExchange (qpid::broker::Exchange::shared_ptr mgmtExchange,
- qpid::broker::Exchange::shared_ptr directExchange);
+ void setInterval(uint16_t _interval) { interval = _interval; }
+ void setExchange(qpid::broker::Exchange::shared_ptr mgmtExchange,
+ qpid::broker::Exchange::shared_ptr directExchange);
+ void setExchangeV2(qpid::broker::Exchange::shared_ptr topicExchange,
+ qpid::broker::Exchange::shared_ptr directExchange);
+
int getMaxThreads () { return threadPoolSize; }
QPID_BROKER_EXTERN void registerClass (const std::string& packageName,
const std::string& className,
@@ -88,12 +91,10 @@ public:
uint8_t* md5Sum,
ManagementObject::writeSchemaCall_t schemaCall);
QPID_BROKER_EXTERN ObjectId addObject (ManagementObject* object,
- uint64_t persistId = 0,
- bool publishNow = false);
+ uint64_t persistId = 0);
QPID_BROKER_EXTERN ObjectId addObject (ManagementObject* object,
const std::string& key,
- bool persistent = true,
- bool publishNow = false);
+ bool persistent = true);
QPID_BROKER_EXTERN void raiseEvent(const ManagementEvent& event,
severity_t severity = SEV_DEFAULT);
QPID_BROKER_EXTERN void clientAdded (const std::string& routingKey);
@@ -238,10 +239,18 @@ private:
ManagementObjectVector newDeletedManagementObjects;
framing::Uuid uuid;
- sys::Mutex addLock;
- sys::Mutex userLock;
+
+ //
+ // Lock hierarchy: If a thread needs to take both addLock and userLock,
+ // it MUST take userLock first, then addLock.
+ //
+ sys::Mutex userLock;
+ sys::Mutex addLock;
+
qpid::broker::Exchange::shared_ptr mExchange;
qpid::broker::Exchange::shared_ptr dExchange;
+ qpid::broker::Exchange::shared_ptr v2Topic;
+ qpid::broker::Exchange::shared_ptr v2Direct;
std::string dataDir;
uint16_t interval;
qpid::broker::Broker* broker;
@@ -320,7 +329,7 @@ private:
size_t validateSchema(framing::Buffer&, uint8_t kind);
size_t validateTableSchema(framing::Buffer&);
size_t validateEventSchema(framing::Buffer&);
- void debugSnapshot(const char*);
+ std::string debugSnapshot();
};
}}
diff --git a/qpid/cpp/src/qpid/management/ManagementDirectExchange.cpp b/qpid/cpp/src/qpid/management/ManagementDirectExchange.cpp
new file mode 100644
index 0000000000..0813e30891
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementDirectExchange.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/management/ManagementDirectExchange.h"
+#include "qpid/log/Statement.h"
+#include <assert.h>
+
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+ManagementDirectExchange::ManagementDirectExchange(const string& _name, Manageable* _parent, Broker* b) :
+ Exchange (_name, _parent, b), DirectExchange(_name, _parent, b) {}
+ManagementDirectExchange::ManagementDirectExchange(const std::string& _name,
+ bool _durable,
+ const FieldTable& _args,
+ Manageable* _parent, Broker* b) :
+ Exchange (_name, _durable, _args, _parent, b),
+ DirectExchange(_name, _durable, _args, _parent, b) {}
+
+void ManagementDirectExchange::route(Deliverable& msg,
+ const string& routingKey,
+ const FieldTable* args)
+{
+ bool routeIt = true;
+
+ // TODO: Intercept messages directed to the embedded agent and send them to the management agent.
+
+ if (routeIt)
+ DirectExchange::route(msg, routingKey, args);
+}
+
+void ManagementDirectExchange::setManagmentAgent(ManagementAgent* agent, int qv)
+{
+ managementAgent = agent;
+ qmfVersion = qv;
+ assert(qmfVersion == 2); // QMFv1 doesn't use a specialized direct exchange
+}
+
+
+ManagementDirectExchange::~ManagementDirectExchange() {}
+
+const std::string ManagementDirectExchange::typeName("management-direct");
+
diff --git a/qpid/cpp/src/qpid/management/ManagementDirectExchange.h b/qpid/cpp/src/qpid/management/ManagementDirectExchange.h
new file mode 100644
index 0000000000..ab691afa70
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementDirectExchange.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ManagementDirectExchange_
+#define _ManagementDirectExchange_
+
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/management/ManagementAgent.h"
+
+namespace qpid {
+namespace broker {
+
+class ManagementDirectExchange : public virtual DirectExchange
+{
+ private:
+ management::ManagementAgent* managementAgent;
+ int qmfVersion;
+
+ public:
+ static const std::string typeName;
+
+ ManagementDirectExchange(const string& name, Manageable* _parent = 0, Broker* broker = 0);
+ ManagementDirectExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args,
+ Manageable* _parent = 0, Broker* broker = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual void route(Deliverable& msg,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
+
+ void setManagmentAgent(management::ManagementAgent* agent, int qmfVersion);
+
+ virtual ~ManagementDirectExchange();
+};
+
+
+}
+}
+
+#endif
diff --git a/qpid/cpp/src/qpid/management/ManagementExchange.cpp b/qpid/cpp/src/qpid/management/ManagementExchange.cpp
deleted file mode 100644
index b90bcd87d8..0000000000
--- a/qpid/cpp/src/qpid/management/ManagementExchange.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/management/ManagementExchange.h"
-#include "qpid/log/Statement.h"
-
-using namespace qpid::management;
-using namespace qpid::broker;
-using namespace qpid::framing;
-using namespace qpid::sys;
-
-ManagementExchange::ManagementExchange (const string& _name, Manageable* _parent, Broker* b) :
- Exchange (_name, _parent, b), TopicExchange(_name, _parent, b) {}
-ManagementExchange::ManagementExchange (const std::string& _name,
- bool _durable,
- const FieldTable& _args,
- Manageable* _parent, Broker* b) :
- Exchange (_name, _durable, _args, _parent, b),
- TopicExchange(_name, _durable, _args, _parent, b) {}
-
-void ManagementExchange::route (Deliverable& msg,
- const string& routingKey,
- const FieldTable* args)
-{
- bool routeIt = true;
-
- // Intercept management agent commands
- if ((routingKey.length() > 6 &&
- routingKey.substr(0, 6).compare("agent.") == 0) ||
- (routingKey == "broker"))
- routeIt = managementAgent->dispatchCommand(msg, routingKey, args);
-
- if (routeIt)
- TopicExchange::route(msg, routingKey, args);
-}
-
-bool ManagementExchange::bind (Queue::shared_ptr queue,
- const string& routingKey,
- const qpid::framing::FieldTable* args)
-{
- managementAgent->clientAdded(routingKey);
- return TopicExchange::bind(queue, routingKey, args);
-}
-
-void ManagementExchange::setManagmentAgent (ManagementAgent* agent)
-{
- managementAgent = agent;
-}
-
-
-ManagementExchange::~ManagementExchange() {}
-
-const std::string ManagementExchange::typeName("management");
-
diff --git a/qpid/cpp/src/qpid/management/ManagementTopicExchange.cpp b/qpid/cpp/src/qpid/management/ManagementTopicExchange.cpp
new file mode 100644
index 0000000000..98650b3adf
--- /dev/null
+++ b/qpid/cpp/src/qpid/management/ManagementTopicExchange.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/management/ManagementTopicExchange.h"
+#include "qpid/log/Statement.h"
+
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+ManagementTopicExchange::ManagementTopicExchange(const string& _name, Manageable* _parent, Broker* b) :
+ Exchange (_name, _parent, b), TopicExchange(_name, _parent, b) {}
+ManagementTopicExchange::ManagementTopicExchange(const std::string& _name,
+ bool _durable,
+ const FieldTable& _args,
+ Manageable* _parent, Broker* b) :
+ Exchange (_name, _durable, _args, _parent, b),
+ TopicExchange(_name, _durable, _args, _parent, b) {}
+
+void ManagementTopicExchange::route(Deliverable& msg,
+ const string& routingKey,
+ const FieldTable* args)
+{
+ bool routeIt = true;
+
+ // Intercept management agent commands
+ if (qmfVersion == 1) {
+ if ((routingKey.length() > 6 &&
+ routingKey.substr(0, 6).compare("agent.") == 0) ||
+ (routingKey == "broker"))
+ routeIt = managementAgent->dispatchCommand(msg, routingKey, args);
+ }
+
+ if (routeIt)
+ TopicExchange::route(msg, routingKey, args);
+}
+
+bool ManagementTopicExchange::bind(Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args)
+{
+ if (qmfVersion == 1)
+ managementAgent->clientAdded(routingKey);
+ return TopicExchange::bind(queue, routingKey, args);
+}
+
+void ManagementTopicExchange::setManagmentAgent(ManagementAgent* agent, int qv)
+{
+ managementAgent = agent;
+ qmfVersion = qv;
+}
+
+
+ManagementTopicExchange::~ManagementTopicExchange() {}
+
+const std::string ManagementTopicExchange::typeName("management-topic");
+
diff --git a/qpid/cpp/src/qpid/management/ManagementExchange.h b/qpid/cpp/src/qpid/management/ManagementTopicExchange.h
index 3fa4039af7..ece1c88ecf 100644
--- a/qpid/cpp/src/qpid/management/ManagementExchange.h
+++ b/qpid/cpp/src/qpid/management/ManagementTopicExchange.h
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#ifndef _ManagementExchange_
-#define _ManagementExchange_
+#ifndef _ManagementTopicExchange_
+#define _ManagementTopicExchange_
#include "qpid/broker/TopicExchange.h"
#include "qpid/management/ManagementAgent.h"
@@ -27,32 +27,33 @@
namespace qpid {
namespace broker {
-class ManagementExchange : public virtual TopicExchange
+class ManagementTopicExchange : public virtual TopicExchange
{
private:
management::ManagementAgent* managementAgent;
+ int qmfVersion;
public:
static const std::string typeName;
- ManagementExchange (const string& name, Manageable* _parent = 0, Broker* broker = 0);
- ManagementExchange (const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args,
- Manageable* _parent = 0, Broker* broker = 0);
+ ManagementTopicExchange(const string& name, Manageable* _parent = 0, Broker* broker = 0);
+ ManagementTopicExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args,
+ Manageable* _parent = 0, Broker* broker = 0);
virtual std::string getType() const { return typeName; }
- virtual void route (Deliverable& msg,
- const string& routingKey,
- const qpid::framing::FieldTable* args);
-
- virtual bool bind (Queue::shared_ptr queue,
+ virtual void route(Deliverable& msg,
const string& routingKey,
const qpid::framing::FieldTable* args);
- void setManagmentAgent (management::ManagementAgent* agent);
+ virtual bool bind(Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
+
+ void setManagmentAgent(management::ManagementAgent* agent, int qmfVersion);
- virtual ~ManagementExchange();
+ virtual ~ManagementTopicExchange();
};
diff --git a/qpid/cpp/src/qpid/messaging/AddressParser.cpp b/qpid/cpp/src/qpid/messaging/AddressParser.cpp
index 265b5fe195..4b29f126f2 100644
--- a/qpid/cpp/src/qpid/messaging/AddressParser.cpp
+++ b/qpid/cpp/src/qpid/messaging/AddressParser.cpp
@@ -198,6 +198,7 @@ bool AddressParser::readSimpleValue(Variant& value)
std::string s;
if (readWord(s)) {
value = s;
+ try { value = value.asInt32(); return true; } catch (const InvalidConversion&) {}
try { value = value.asInt64(); return true; } catch (const InvalidConversion&) {}
try { value = value.asDouble(); return true; } catch (const InvalidConversion&) {}
return true;
diff --git a/qpid/cpp/src/qpid/messaging/Connection.cpp b/qpid/cpp/src/qpid/messaging/Connection.cpp
index 230c9d5dbf..cb06af7693 100644
--- a/qpid/cpp/src/qpid/messaging/Connection.cpp
+++ b/qpid/cpp/src/qpid/messaging/Connection.cpp
@@ -23,23 +23,17 @@
#include "qpid/messaging/ConnectionImpl.h"
#include "qpid/messaging/Session.h"
#include "qpid/messaging/SessionImpl.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
#include "qpid/client/amqp0_10/ConnectionImpl.h"
#include "qpid/log/Statement.h"
namespace qpid {
-namespace client {
-
-typedef PrivateImplRef<qpid::messaging::Connection> PI;
-
-}
-
namespace messaging {
-using qpid::client::PI;
+typedef PrivateImplRef<qpid::messaging::Connection> PI;
Connection::Connection(ConnectionImpl* impl) { PI::ctor(*this, impl); }
-Connection::Connection(const Connection& c) : qpid::client::Handle<ConnectionImpl>() { PI::copy(*this, c); }
+Connection::Connection(const Connection& c) : Handle<ConnectionImpl>() { PI::copy(*this, c); }
Connection& Connection::operator=(const Connection& c) { return PI::assign(*this, c); }
Connection::~Connection() { PI::dtor(*this); }
@@ -67,40 +61,11 @@ Session Connection::newSession(bool transactional, const std::string& name)
return impl->newSession(transactional, name);
}
Session Connection::getSession(const std::string& name) const { return impl->getSession(name); }
-
-InvalidOptionString::InvalidOptionString(const std::string& msg) : Exception(msg) {}
-
-void parseKeyValuePair(const std::string& in, Variant::Map& out)
-{
- std::string::size_type i = in.find('=');
- if (i == std::string::npos || i == in.size() || in.find('=', i+1) != std::string::npos) {
- throw InvalidOptionString(QPID_MSG("Cannot parse name-value pair from " << in));
- } else {
- out[in.substr(0, i)] = in.substr(i+1);
- }
-}
-
-void parseOptionString(const std::string& in, Variant::Map& out)
-{
- std::string::size_type start = 0;
- std::string::size_type i = in.find('&');
- while (i != std::string::npos) {
- parseKeyValuePair(in.substr(start, i-start), out);
- if (i < in.size()) {
- start = i+1;
- i = in.find('&', start);
- } else {
- i = std::string::npos;
- }
- }
- parseKeyValuePair(in.substr(start), out);
+void Connection::setOption(const std::string& name, const Variant& value)
+{
+ impl->setOption(name, value);
}
-Variant::Map parseOptionString(const std::string& in)
-{
- Variant::Map map;
- parseOptionString(in, map);
- return map;
-}
+InvalidOptionString::InvalidOptionString(const std::string& msg) : Exception(msg) {}
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/ConnectionImpl.h b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h
index 589c9fbe57..2f03c9610b 100644
--- a/qpid/cpp/src/qpid/messaging/ConnectionImpl.h
+++ b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h
@@ -25,12 +25,10 @@
#include "qpid/RefCounted.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
class Session;
+class Variant;
class ConnectionImpl : public virtual qpid::RefCounted
{
@@ -40,6 +38,7 @@ class ConnectionImpl : public virtual qpid::RefCounted
virtual void close() = 0;
virtual Session newSession(bool transactional, const std::string& name) = 0;
virtual Session getSession(const std::string& name) const = 0;
+ virtual void setOption(const std::string& name, const Variant& value) = 0;
private:
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/PrivateImplRef.h b/qpid/cpp/src/qpid/messaging/PrivateImplRef.h
new file mode 100644
index 0000000000..cc2798c647
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/PrivateImplRef.h
@@ -0,0 +1,94 @@
+#ifndef QPID_MESSAGING_PRIVATEIMPL_H
+#define QPID_MESSAGING_PRIVATEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/messaging/ImportExport.h"
+#include <boost/intrusive_ptr.hpp>
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace messaging {
+
+// FIXME aconway 2009-04-24: details!
+/** @file
+ *
+ * Helper class to implement a class with a private, reference counted
+ * implementation and reference semantics.
+ *
+ * Such classes are used in the public API to hide implementation, they
+ * should. Example of use:
+ *
+ * === Foo.h
+ *
+ * template <class T> PrivateImplRef;
+ * class FooImpl;
+ *
+ * Foo : public Handle<FooImpl> {
+ * public:
+ * Foo(FooImpl* = 0);
+ * Foo(const Foo&);
+ * ~Foo();
+ * Foo& operator=(const Foo&);
+ *
+ * int fooDo(); // and other Foo functions...
+ *
+ * private:
+ * typedef FooImpl Impl;
+ * Impl* impl;
+ * friend class PrivateImplRef<Foo>;
+ *
+ * === Foo.cpp
+ *
+ * typedef PrivateImplRef<Foo> PI;
+ * Foo::Foo(FooImpl* p) { PI::ctor(*this, p); }
+ * Foo::Foo(const Foo& c) : Handle<FooImpl>() { PI::copy(*this, c); }
+ * Foo::~Foo() { PI::dtor(*this); }
+ * Foo& Foo::operator=(const Foo& c) { return PI::assign(*this, c); }
+ *
+ * int foo::fooDo() { return impl->fooDo(); }
+ *
+ */
+template <class T> class PrivateImplRef {
+ public:
+ typedef typename T::Impl Impl;
+ typedef boost::intrusive_ptr<Impl> intrusive_ptr;
+
+ static intrusive_ptr get(const T& t) { return intrusive_ptr(t.impl); }
+
+ static void set(T& t, const intrusive_ptr& p) {
+ if (t.impl == p) return;
+ if (t.impl) boost::intrusive_ptr_release(t.impl);
+ t.impl = p.get();
+ if (t.impl) boost::intrusive_ptr_add_ref(t.impl);
+ }
+
+ // Helper functions to implement the ctor, dtor, copy, assign
+ static void ctor(T& t, Impl* p) { t.impl = p; if (p) boost::intrusive_ptr_add_ref(p); }
+ static void copy(T& t, const T& x) { if (&t == &x) return; t.impl = 0; assign(t, x); }
+ static void dtor(T& t) { if(t.impl) boost::intrusive_ptr_release(t.impl); }
+ static T& assign(T& t, const T& x) { set(t, get(x)); return t;}
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_PRIVATEIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Receiver.cpp b/qpid/cpp/src/qpid/messaging/Receiver.cpp
index 841bee274c..df13052671 100644
--- a/qpid/cpp/src/qpid/messaging/Receiver.cpp
+++ b/qpid/cpp/src/qpid/messaging/Receiver.cpp
@@ -22,21 +22,15 @@
#include "qpid/messaging/Message.h"
#include "qpid/messaging/ReceiverImpl.h"
#include "qpid/messaging/Session.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
namespace qpid {
-namespace client {
-
-typedef PrivateImplRef<qpid::messaging::Receiver> PI;
-
-}
-
namespace messaging {
-using qpid::client::PI;
+typedef PrivateImplRef<qpid::messaging::Receiver> PI;
Receiver::Receiver(ReceiverImpl* impl) { PI::ctor(*this, impl); }
-Receiver::Receiver(const Receiver& s) : qpid::client::Handle<ReceiverImpl>() { PI::copy(*this, s); }
+Receiver::Receiver(const Receiver& s) : Handle<ReceiverImpl>() { PI::copy(*this, s); }
Receiver::~Receiver() { PI::dtor(*this); }
Receiver& Receiver::operator=(const Receiver& s) { return PI::assign(*this, s); }
bool Receiver::get(Message& message, Duration timeout) { return impl->get(message, timeout); }
diff --git a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
index a720fe8210..c156265f6c 100644
--- a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
@@ -24,9 +24,6 @@
#include "qpid/RefCounted.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
class Message;
diff --git a/qpid/cpp/src/qpid/messaging/Sender.cpp b/qpid/cpp/src/qpid/messaging/Sender.cpp
index 5e18db1d7c..711a857d7a 100644
--- a/qpid/cpp/src/qpid/messaging/Sender.cpp
+++ b/qpid/cpp/src/qpid/messaging/Sender.cpp
@@ -22,21 +22,14 @@
#include "qpid/messaging/Message.h"
#include "qpid/messaging/SenderImpl.h"
#include "qpid/messaging/Session.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
namespace qpid {
-namespace client {
-
-typedef PrivateImplRef<qpid::messaging::Sender> PI;
-
-}
-
namespace messaging {
-
-using qpid::client::PI;
+typedef PrivateImplRef<qpid::messaging::Sender> PI;
Sender::Sender(SenderImpl* impl) { PI::ctor(*this, impl); }
-Sender::Sender(const Sender& s) : qpid::client::Handle<SenderImpl>() { PI::copy(*this, s); }
+Sender::Sender(const Sender& s) : qpid::messaging::Handle<SenderImpl>() { PI::copy(*this, s); }
Sender::~Sender() { PI::dtor(*this); }
Sender& Sender::operator=(const Sender& s) { return PI::assign(*this, s); }
void Sender::send(const Message& message) { impl->send(message); }
diff --git a/qpid/cpp/src/qpid/messaging/SenderImpl.h b/qpid/cpp/src/qpid/messaging/SenderImpl.h
index 0294688771..7653049c26 100644
--- a/qpid/cpp/src/qpid/messaging/SenderImpl.h
+++ b/qpid/cpp/src/qpid/messaging/SenderImpl.h
@@ -24,9 +24,6 @@
#include "qpid/RefCounted.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
class Message;
diff --git a/qpid/cpp/src/qpid/messaging/Session.cpp b/qpid/cpp/src/qpid/messaging/Session.cpp
index 5d1a6fb815..2ac19727e3 100644
--- a/qpid/cpp/src/qpid/messaging/Session.cpp
+++ b/qpid/cpp/src/qpid/messaging/Session.cpp
@@ -25,21 +25,15 @@
#include "qpid/messaging/Sender.h"
#include "qpid/messaging/Receiver.h"
#include "qpid/messaging/SessionImpl.h"
-#include "qpid/client/PrivateImplRef.h"
+#include "qpid/messaging/PrivateImplRef.h"
namespace qpid {
-namespace client {
-
-typedef PrivateImplRef<qpid::messaging::Session> PI;
-
-}
-
namespace messaging {
-using qpid::client::PI;
+typedef PrivateImplRef<qpid::messaging::Session> PI;
Session::Session(SessionImpl* impl) { PI::ctor(*this, impl); }
-Session::Session(const Session& s) : qpid::client::Handle<SessionImpl>() { PI::copy(*this, s); }
+Session::Session(const Session& s) : Handle<SessionImpl>() { PI::copy(*this, s); }
Session::~Session() { PI::dtor(*this); }
Session& Session::operator=(const Session& s) { return PI::assign(*this, s); }
void Session::commit() { impl->commit(); }
diff --git a/qpid/cpp/src/qpid/messaging/SessionImpl.h b/qpid/cpp/src/qpid/messaging/SessionImpl.h
index 653df8fdda..79f0d007b5 100644
--- a/qpid/cpp/src/qpid/messaging/SessionImpl.h
+++ b/qpid/cpp/src/qpid/messaging/SessionImpl.h
@@ -26,9 +26,6 @@
#include "qpid/messaging/Duration.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
class Address;
diff --git a/qpid/cpp/src/qpid/messaging/Variant.cpp b/qpid/cpp/src/qpid/messaging/Variant.cpp
index ba93f160ec..2567b7508b 100644
--- a/qpid/cpp/src/qpid/messaging/Variant.cpp
+++ b/qpid/cpp/src/qpid/messaging/Variant.cpp
@@ -20,6 +20,7 @@
*/
#include "qpid/messaging/Variant.h"
#include "qpid/Msg.h"
+#include "qpid/log/Statement.h"
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <algorithm>
@@ -50,7 +51,7 @@ class VariantImpl
VariantImpl(int64_t);
VariantImpl(float);
VariantImpl(double);
- VariantImpl(const std::string&);
+ VariantImpl(const std::string&, const std::string& encoding=std::string());
VariantImpl(const Variant::Map&);
VariantImpl(const Variant::List&);
VariantImpl(const Uuid&);
@@ -130,7 +131,8 @@ VariantImpl::VariantImpl(int32_t i) : type(VAR_INT32) { value.i32 = i; }
VariantImpl::VariantImpl(int64_t i) : type(VAR_INT64) { value.i64 = i; }
VariantImpl::VariantImpl(float f) : type(VAR_FLOAT) { value.f = f; }
VariantImpl::VariantImpl(double d) : type(VAR_DOUBLE) { value.d = d; }
-VariantImpl::VariantImpl(const std::string& s) : type(VAR_STRING) { value.v = new std::string(s); }
+VariantImpl::VariantImpl(const std::string& s, const std::string& e)
+ : type(VAR_STRING), encoding(e) { value.v = new std::string(s); }
VariantImpl::VariantImpl(const Variant::Map& m) : type(VAR_MAP) { value.v = new Variant::Map(m); }
VariantImpl::VariantImpl(const Variant::List& l) : type(VAR_LIST) { value.v = new Variant::List(l); }
VariantImpl::VariantImpl(const Uuid& u) : type(VAR_UUID) { value.v = new Uuid(u); }
@@ -448,7 +450,7 @@ VariantImpl* VariantImpl::create(const Variant& v)
case VAR_INT64: return new VariantImpl(v.asInt64());
case VAR_FLOAT: return new VariantImpl(v.asFloat());
case VAR_DOUBLE: return new VariantImpl(v.asDouble());
- case VAR_STRING: return new VariantImpl(v.asString());
+ case VAR_STRING: return new VariantImpl(v.asString(), v.getEncoding());
case VAR_MAP: return new VariantImpl(v.asMap());
case VAR_LIST: return new VariantImpl(v.asList());
case VAR_UUID: return new VariantImpl(v.asUuid());
diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
index f658b7d50f..5771141d08 100644
--- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
+++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp
@@ -22,6 +22,7 @@
#include "qpid/sys/AsynchIOHandler.h"
#include "qpid/sys/AsynchIO.h"
#include "qpid/sys/Socket.h"
+#include "qpid/sys/SecuritySettings.h"
#include "qpid/framing/AMQP_HighestVersion.h"
#include "qpid/framing/ProtocolInitiation.h"
#include "qpid/log/Statement.h"
@@ -144,7 +145,7 @@ void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
decoded = in.getPosition();
QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
try {
- codec = factory->create(protocolInit.getVersion(), *this, identifier, 0);
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, SecuritySettings());
if (!codec) {
//TODO: may still want to revise this...
//send valid version header & close connection.
@@ -200,7 +201,7 @@ void AsynchIOHandler::nobuffs(AsynchIO&) {
void AsynchIOHandler::idle(AsynchIO&){
if (isClient && codec == 0) {
- codec = factory->create(*this, identifier, 0);
+ codec = factory->create(*this, identifier, SecuritySettings());
write(framing::ProtocolInitiation(codec->getVersion()));
return;
}
diff --git a/qpid/cpp/src/qpid/sys/ConnectionCodec.h b/qpid/cpp/src/qpid/sys/ConnectionCodec.h
index 7231b1daa6..c2890f06dc 100644
--- a/qpid/cpp/src/qpid/sys/ConnectionCodec.h
+++ b/qpid/cpp/src/qpid/sys/ConnectionCodec.h
@@ -30,6 +30,7 @@ namespace sys {
class InputHandlerFactory;
class OutputControl;
+struct SecuritySettings;
/**
* Interface of coder/decoder for a connection of a specific protocol
@@ -49,27 +50,15 @@ class ConnectionCodec : public Codec {
struct Factory {
virtual ~Factory() {}
- /** Security Strength Factor - indicates the level of security provided
- * by the underlying transport. If zero, the transport provides no
- * security (e.g. TCP). If non-zero, the transport provides some level
- * of security (e.g. SSL). The values for SSF can be interpreted as:
- *
- * 0 = No protection.
- * 1 = Integrity checking only.
- * >1 = Supports authentication, integrity and confidentiality.
- * The number represents the encryption key length.
- */
-
/** Return 0 if version unknown */
virtual ConnectionCodec* create(
framing::ProtocolVersion, OutputControl&, const std::string& id,
- unsigned int conn_ssf
+ const SecuritySettings&
) = 0;
/** Return "preferred" codec for outbound connections. */
virtual ConnectionCodec* create(
- OutputControl&, const std::string& id,
- unsigned int conn_ssf
+ OutputControl&, const std::string& id, const SecuritySettings&
) = 0;
};
};
diff --git a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
index b325931793..5a5c10401c 100644
--- a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
@@ -27,6 +27,7 @@
#include "qpid/log/Statement.h"
#include "qpid/sys/rdma/RdmaIO.h"
#include "qpid/sys/OutputControl.h"
+#include "qpid/sys/SecuritySettings.h"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
@@ -139,7 +140,7 @@ void RdmaIOHandler::initProtocolOut() {
// but we must be able to send
assert( codec == 0 );
assert( aio->writable() && aio->bufferAvailable() );
- codec = factory->create(*this, identifier, 0);
+ codec = factory->create(*this, identifier, SecuritySettings());
write(framing::ProtocolInitiation(codec->getVersion()));
}
@@ -186,7 +187,7 @@ void RdmaIOHandler::initProtocolIn(Rdma::Buffer* buff) {
decoded = in.getPosition();
QPID_LOG(debug, "Rdma: RECV [" << identifier << "] INIT(" << protocolInit << ")");
- codec = factory->create(protocolInit.getVersion(), *this, identifier, 0);
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, SecuritySettings());
// If we failed to create the codec then we don't understand the offered protocol version
if (!codec) {
diff --git a/qpid/cpp/src/qpid/sys/SecuritySettings.h b/qpid/cpp/src/qpid/sys/SecuritySettings.h
new file mode 100644
index 0000000000..bfcd08fd0f
--- /dev/null
+++ b/qpid/cpp/src/qpid/sys/SecuritySettings.h
@@ -0,0 +1,58 @@
+#ifndef QPID_SYS_SECURITYSETTINGS_H
+#define QPID_SYS_SECURITYSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace qpid {
+namespace sys {
+
+/**
+ * Conveys security information from a given transport to the upper
+ * layers.
+ */
+struct SecuritySettings
+{
+ /**
+ * Security Strength Factor (SSF). Possible values are:
+ *
+ * @li 0 No security
+ * @li 1 Integrity checking only
+ * @li >1 Integrity and confidentiality with the number
+ * giving the encryption key length.
+ */
+ unsigned int ssf;
+ /**
+ * An authorisation id
+ */
+ std::string authid;
+
+ /**
+ * Disables SASL mechanisms that are vulnerable to passive
+ * dictionary-based password attacks
+ */
+ bool nodict;
+
+ SecuritySettings() : ssf(0), nodict(false) {}
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_SECURITYSETTINGS_H*/
diff --git a/qpid/cpp/src/qpid/sys/SslPlugin.cpp b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
index c143f1f1d0..297787f497 100644
--- a/qpid/cpp/src/qpid/sys/SslPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
@@ -41,14 +41,18 @@ struct SslServerOptions : ssl::SslOptions
{
uint16_t port;
bool clientAuth;
+ bool nodict;
SslServerOptions() : port(5671),
- clientAuth(false)
+ clientAuth(false),
+ nodict(false)
{
addOptions()
("ssl-port", optValue(port, "PORT"), "Port on which to listen for SSL connections")
("ssl-require-client-authentication", optValue(clientAuth),
- "Forces clients to authenticate in order to establish an SSL connection");
+ "Forces clients to authenticate in order to establish an SSL connection")
+ ("ssl-sasl-no-dict", optValue(nodict),
+ "Disables SASL mechanisms that are vulnerable to passive dictionary-based password attacks");
}
};
@@ -57,6 +61,7 @@ class SslProtocolFactory : public ProtocolFactory {
qpid::sys::ssl::SslSocket listener;
const uint16_t listeningPort;
std::auto_ptr<qpid::sys::ssl::SslAcceptor> acceptor;
+ bool nodict;
public:
SslProtocolFactory(const SslServerOptions&, int backlog, bool nodelay);
@@ -97,7 +102,8 @@ static struct SslPlugin : public Plugin {
const broker::Broker::Options& opts = broker->getOptions();
ProtocolFactory::shared_ptr protocol(new SslProtocolFactory(options,
- opts.connectionBacklog, opts.tcpNoDelay));
+ opts.connectionBacklog,
+ opts.tcpNoDelay));
QPID_LOG(notice, "Listening for SSL connections on TCP port " << protocol->getPort());
broker->registerProtocolFactory("ssl", protocol);
} catch (const std::exception& e) {
@@ -109,12 +115,13 @@ static struct SslPlugin : public Plugin {
} sslPlugin;
SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, int backlog, bool nodelay) :
- tcpNoDelay(nodelay), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth))
+ tcpNoDelay(nodelay), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth)),
+ nodict(options.nodict)
{}
void SslProtocolFactory::established(Poller::shared_ptr poller, const qpid::sys::ssl::SslSocket& s,
ConnectionCodec::Factory* f, bool isClient) {
- qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getPeerAddress(), f);
+ qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getPeerAddress(), f, nodict);
if (tcpNoDelay) {
s.setTcpNoDelay(tcpNoDelay);
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp b/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp
index 3469f88c0f..5516d72065 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp
+++ b/qpid/cpp/src/qpid/sys/ssl/SslHandler.cpp
@@ -42,13 +42,14 @@ struct Buff : public SslIO::BufferBase {
{ delete [] bytes;}
};
-SslHandler::SslHandler(std::string id, ConnectionCodec::Factory* f) :
+SslHandler::SslHandler(std::string id, ConnectionCodec::Factory* f, bool _nodict) :
identifier(id),
aio(0),
factory(f),
codec(0),
readError(false),
- isClient(false)
+ isClient(false),
+ nodict(_nodict)
{}
SslHandler::~SslHandler() {
@@ -111,7 +112,7 @@ void SslHandler::readbuff(SslIO& , SslIO::BufferBase* buff) {
decoded = in.getPosition();
QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
try {
- codec = factory->create(protocolInit.getVersion(), *this, identifier, aio->getKeyLen());
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, getSecuritySettings(aio));
if (!codec) {
//TODO: may still want to revise this...
//send valid version header & close connection.
@@ -166,7 +167,7 @@ void SslHandler::nobuffs(SslIO&) {
void SslHandler::idle(SslIO&){
if (isClient && codec == 0) {
- codec = factory->create(*this, identifier, aio->getKeyLen());
+ codec = factory->create(*this, identifier, getSecuritySettings(aio));
write(framing::ProtocolInitiation(codec->getVersion()));
return;
}
@@ -183,5 +184,12 @@ void SslHandler::idle(SslIO&){
aio->queueWriteClose();
}
+SecuritySettings SslHandler::getSecuritySettings(SslIO* aio)
+{
+ SecuritySettings settings = aio->getSecuritySettings();
+ settings.nodict = nodict;
+ return settings;
+}
+
}}} // namespace qpid::sys::ssl
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslHandler.h b/qpid/cpp/src/qpid/sys/ssl/SslHandler.h
index 8f6b8e732a..a340109966 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslHandler.h
+++ b/qpid/cpp/src/qpid/sys/ssl/SslHandler.h
@@ -45,11 +45,13 @@ class SslHandler : public OutputControl {
ConnectionCodec* codec;
bool readError;
bool isClient;
+ bool nodict;
void write(const framing::ProtocolInitiation&);
+ qpid::sys::SecuritySettings getSecuritySettings(SslIO* aio);
public:
- SslHandler(std::string id, ConnectionCodec::Factory* f);
+ SslHandler(std::string id, ConnectionCodec::Factory* f, bool nodict);
~SslHandler();
void init(SslIO* a, int numBuffs);
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp b/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp
index c149d6ea74..a57123c182 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp
+++ b/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp
@@ -436,4 +436,9 @@ void SslIO::close(DispatchHandle& h) {
}
}
-int SslIO::getKeyLen() {return socket.getKeyLen();}
+SecuritySettings SslIO::getSecuritySettings() {
+ SecuritySettings settings;
+ settings.ssf = socket.getKeyLen();
+ settings.authid = socket.getClientAuthId();
+ return settings;
+}
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslIo.h b/qpid/cpp/src/qpid/sys/ssl/SslIo.h
index 3162abac40..53ac69d8d6 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslIo.h
+++ b/qpid/cpp/src/qpid/sys/ssl/SslIo.h
@@ -22,6 +22,7 @@
*/
#include "qpid/sys/DispatchHandle.h"
+#include "qpid/sys/SecuritySettings.h"
#include <boost/function.hpp>
#include <deque>
@@ -156,7 +157,7 @@ public:
bool writeQueueEmpty() { return writeQueue.empty(); }
BufferBase* getQueuedBuffer();
- int getKeyLen();
+ qpid::sys::SecuritySettings getSecuritySettings();
private:
~SslIO();
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
index aa8cf127d7..22b0909ad4 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
+++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
@@ -102,6 +102,34 @@ std::string getService(int fd, bool local)
return servName;
}
+const std::string DOMAIN_SEPARATOR("@");
+const std::string DC_SEPARATOR(".");
+const std::string DC("DC");
+const std::string DN_DELIMS(" ,=");
+
+std::string getDomainFromSubject(std::string subject)
+{
+ std::string::size_type last = subject.find_first_not_of(DN_DELIMS, 0);
+ std::string::size_type i = subject.find_first_of(DN_DELIMS, last);
+
+ std::string domain;
+ bool nextTokenIsDC = false;
+ while (std::string::npos != i || std::string::npos != last)
+ {
+ std::string token = subject.substr(last, i - last);
+ if (nextTokenIsDC) {
+ if (domain.size()) domain += DC_SEPARATOR;
+ domain += token;
+ nextTokenIsDC = false;
+ } else if (token == DC) {
+ nextTokenIsDC = true;
+ }
+ last = subject.find_first_not_of(DN_DELIMS, i);
+ i = subject.find_first_of(DN_DELIMS, last);
+ }
+ return domain;
+}
+
}
SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0)
@@ -294,4 +322,25 @@ int SslSocket::getKeyLen() const
return 0;
}
+std::string SslSocket::getClientAuthId() const
+{
+ std::string authId;
+ CERTCertificate* cert = SSL_PeerCertificate(socket);
+ if (cert) {
+ authId = CERT_GetCommonName(&(cert->subject));
+ /*
+ * The NSS function CERT_GetDomainComponentName only returns
+ * the last component of the domain name, so we have to parse
+ * the subject manually to extract the full domain.
+ */
+ std::string domain = getDomainFromSubject(cert->subjectName);
+ if (!domain.empty()) {
+ authId += DOMAIN_SEPARATOR;
+ authId += domain;
+ }
+ CERT_DestroyCertificate(cert);
+ }
+ return authId;
+}
+
}}} // namespace qpid::sys::ssl
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
index f1f05e7a98..e2443e31c8 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
+++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
@@ -101,6 +101,7 @@ public:
int getError() const;
int getKeyLen() const;
+ std::string getClientAuthId() const;
private:
mutable std::string connectname;
diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
index 6771767969..fbf7566a18 100644
--- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
@@ -34,6 +34,10 @@
#include <xercesc/framework/MemBufInputSource.hpp>
+#ifdef XQ_EFFECTIVE_BOOLEAN_VALUE_HPP
+#include <xqilla/ast/XQEffectiveBooleanValue.hpp>
+#endif
+
#include <xqilla/ast/XQGlobalVariable.hpp>
#include <xqilla/context/ItemFactory.hpp>
@@ -51,7 +55,7 @@ namespace qpid {
namespace broker {
- XmlExchange::XmlExchange(const string& _name, Manageable* _parent, Broker* b) : Exchange(_name, _parent, b)
+XmlExchange::XmlExchange(const string& _name, Manageable* _parent, Broker* b) : Exchange(_name, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
@@ -180,7 +184,13 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
}
Result result = query->execute(context.get());
+#ifdef XQ_EFFECTIVE_BOOLEAN_VALUE_HPP
+ Item::Ptr first_ = result->next(context.get());
+ Item::Ptr second_ = result->next(context.get());
+ return XQEffectiveBooleanValue::get(first_, second_, context.get(), 0);
+#else
return result->getEffectiveBooleanValue(context.get(), 0);
+#endif
}
catch (XQException& e) {
QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent);
diff --git a/qpid/cpp/src/tests/ClusterFixture.cpp b/qpid/cpp/src/tests/ClusterFixture.cpp
index fd90ed170e..b7e8e88abf 100644
--- a/qpid/cpp/src/tests/ClusterFixture.cpp
+++ b/qpid/cpp/src/tests/ClusterFixture.cpp
@@ -130,11 +130,11 @@ void ClusterFixture::kill(size_t n, int sig) {
forkedBrokers[n]->kill(sig);
}
-/** Kill a broker and suppressing errors from closing connection c. */
+/** Kill a broker and suppress errors from closing connection c. */
void ClusterFixture::killWithSilencer(size_t n, client::Connection& c, int sig) {
ScopedSuppressLogging sl;
- kill(n,sig);
try { c.close(); } catch(...) {}
+ kill(n,sig);
}
/**
diff --git a/qpid/cpp/src/tests/InitialStatusMap.cpp b/qpid/cpp/src/tests/InitialStatusMap.cpp
index dc86c41103..ecbe2d4161 100644
--- a/qpid/cpp/src/tests/InitialStatusMap.cpp
+++ b/qpid/cpp/src/tests/InitialStatusMap.cpp
@@ -37,19 +37,19 @@ QPID_AUTO_TEST_SUITE(InitialStatusMapTestSuite)
typedef InitialStatusMap::Status Status;
Status activeStatus(const Uuid& id=Uuid(), const MemberSet& ms=MemberSet()) {
- return Status(ProtocolVersion(), 0, true, id, STORE_STATE_NO_STORE, Uuid(), 0,
+ return Status(ProtocolVersion(), 0, true, id, STORE_STATE_NO_STORE, Uuid(),
encodeMemberSet(ms));
}
Status newcomerStatus(const Uuid& id=Uuid(), const MemberSet& ms=MemberSet()) {
- return Status(ProtocolVersion(), 0, false, id, STORE_STATE_NO_STORE, Uuid(), 0,
+ return Status(ProtocolVersion(), 0, false, id, STORE_STATE_NO_STORE, Uuid(),
encodeMemberSet(ms));
}
Status storeStatus(bool active, StoreState state, Uuid start=Uuid(), Uuid stop=Uuid(),
const MemberSet& ms=MemberSet())
{
- return Status(ProtocolVersion(), 0, active, start, state, stop, 0,
+ return Status(ProtocolVersion(), 0, active, start, state, stop,
encodeMemberSet(ms));
}
@@ -173,20 +173,6 @@ QPID_AUTO_TEST_CASE(testInteveningConfig) {
BOOST_CHECK_EQUAL(map.getClusterId(), id);
}
-QPID_AUTO_TEST_CASE(testInitialSize) {
- InitialStatusMap map(MemberId(0), 3);
- map.configChange(list_of<MemberId>(0)(1));
- map.received(MemberId(0), newcomerStatus());
- map.received(MemberId(1), newcomerStatus());
- BOOST_CHECK(!map.isComplete());
-
- map.configChange(list_of<MemberId>(0)(1)(2));
- map.received(MemberId(0), newcomerStatus());
- map.received(MemberId(1), newcomerStatus());
- map.received(MemberId(2), newcomerStatus());
- BOOST_CHECK(map.isComplete());
-}
-
QPID_AUTO_TEST_CASE(testAllCleanNoUpdate) {
InitialStatusMap map(MemberId(0), 3);
map.configChange(list_of<MemberId>(0)(1)(2));
@@ -244,8 +230,6 @@ QPID_AUTO_TEST_CASE(testEmptyAlone) {
BOOST_CHECK(!map.isUpdateNeeded());
}
-// FIXME aconway 2009-11-20: consistency tests for mixed stores,
-
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index 1dc6c9a0e2..9c1a761062 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -17,8 +17,6 @@
# under the License.
#
-SUBDIRS = . testagent
-
AM_CXXFLAGS = $(WARNING_CFLAGS) -DBOOST_TEST_DYN_LINK
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src
PUBLIC_INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include # Use public API only
@@ -381,3 +379,5 @@ python_prep:
--prefix=$(PYTHON_BLD_DIR) --install-lib=$(PYTHON_BLD_DIR) \
--install-scripts=$(PYTHON_BLD_DIR)/commands; \
else echo "WARNING: python client not built, missing $(PYTHON_SRC_DIR)"; fi
+
+include testagent.mk
diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp
index dea98216b4..a1e90f83f3 100644
--- a/qpid/cpp/src/tests/MessagingSessionTests.cpp
+++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp
@@ -336,6 +336,12 @@ QPID_AUTO_TEST_CASE(testMapMessage)
MapContent content(out);
content["abc"] = "def";
content["pi"] = 3.14f;
+ Variant utf8("A utf 8 string");
+ utf8.setEncoding("utf8");
+ content["utf8"] = utf8;
+ Variant utf16("\x00\x61\x00\x62\x00\x63");
+ utf16.setEncoding("utf16");
+ content["utf16"] = utf16;
content.encode();
sender.send(out);
Receiver receiver = fix.session.createReceiver(fix.queue);
@@ -343,6 +349,10 @@ QPID_AUTO_TEST_CASE(testMapMessage)
MapView view(in);
BOOST_CHECK_EQUAL(view["abc"].asString(), "def");
BOOST_CHECK_EQUAL(view["pi"].asFloat(), 3.14f);
+ BOOST_CHECK_EQUAL(view["utf8"].asString(), utf8.asString());
+ BOOST_CHECK_EQUAL(view["utf8"].getEncoding(), utf8.getEncoding());
+ BOOST_CHECK_EQUAL(view["utf16"].asString(), utf16.asString());
+ BOOST_CHECK_EQUAL(view["utf16"].getEncoding(), utf16.getEncoding());
fix.session.acknowledge();
}
diff --git a/qpid/cpp/src/tests/Variant.cpp b/qpid/cpp/src/tests/Variant.cpp
index c0bb9772c8..db9e419eab 100644
--- a/qpid/cpp/src/tests/Variant.cpp
+++ b/qpid/cpp/src/tests/Variant.cpp
@@ -178,6 +178,21 @@ QPID_AUTO_TEST_CASE(testIsEqualTo)
BOOST_CHECK_EQUAL(a, b);
}
+QPID_AUTO_TEST_CASE(testEncoding)
+{
+ Variant a("abc");
+ a.setEncoding("utf8");
+ Variant b = a;
+ Variant map = Variant::Map();
+ map.asMap()["a"] = a;
+ map.asMap()["b"] = b;
+ BOOST_CHECK_EQUAL(a.getEncoding(), std::string("utf8"));
+ BOOST_CHECK_EQUAL(a.getEncoding(), b.getEncoding());
+ BOOST_CHECK_EQUAL(a.getEncoding(), map.asMap()["a"].getEncoding());
+ BOOST_CHECK_EQUAL(b.getEncoding(), map.asMap()["b"].getEncoding());
+ BOOST_CHECK_EQUAL(map.asMap()["a"].getEncoding(), map.asMap()["b"].getEncoding());
+}
+
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/cluster_tests.fail b/qpid/cpp/src/tests/cluster_tests.fail
index 268795642d..b28b04f643 100644
--- a/qpid/cpp/src/tests/cluster_tests.fail
+++ b/qpid/cpp/src/tests/cluster_tests.fail
@@ -1,3 +1,3 @@
-cluster_tests.LongTests.test_management
+
diff --git a/qpid/cpp/src/tests/cluster_tests.py b/qpid/cpp/src/tests/cluster_tests.py
index 276ad1af2d..4fefe26db3 100755
--- a/qpid/cpp/src/tests/cluster_tests.py
+++ b/qpid/cpp/src/tests/cluster_tests.py
@@ -29,9 +29,19 @@ from itertools import chain
log = getLogger("qpid.cluster_tests")
+# Note: brokers that shut themselves down due to critical error during
+# normal operation will still have an exit code of 0. Brokers that
+# shut down because of an error found during initialize will exit with
+# a non-0 code. Hence the apparently inconsistent use of EXPECT_EXIT_OK
+# and EXPECT_EXIT_FAIL in some of the tests below.
+
+# FIXME aconway 2010-03-11: resolve this - ideally any exit due to an error
+# should give non-0 exit status.
+
# Import scripts as modules
qpid_cluster=import_script(checkenv("QPID_CLUSTER_EXEC"))
+
def readfile(filename):
"""Returns te content of file named filename as a string"""
f = file(filename)
@@ -144,7 +154,7 @@ class LongTests(BrokerTest):
i += 1
b = cluster.start(expect=EXPECT_EXIT_FAIL)
ErrorGenerator(b)
- time.sleep(1)
+ time.sleep(min(5,self.duration()/2))
sender.stop()
receiver.stop(sender.sent)
for i in range(i, len(cluster)): cluster[i].kill()
@@ -152,7 +162,7 @@ class LongTests(BrokerTest):
def test_management(self):
"""Run management clients and other clients concurrently."""
- # FIXME aconway 2010-03-03: move to framework
+ # TODO aconway 2010-03-03: move to brokertest framework
class ClientLoop(StoppableThread):
"""Run a client executable in a loop."""
def __init__(self, broker, cmd):
@@ -173,14 +183,21 @@ class LongTests(BrokerTest):
self.cmd, expect=EXPECT_UNKNOWN)
finally: self.lock.release()
try: exit = self.process.wait()
- except: exit = 1
+ 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
+ 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 status %s" %
- (self.broker.name, exit))
+ self.process.unexpected(
+ "client of %s exit code %s"%(self.broker.name, exit))
finally: self.lock.release()
except Exception, e:
self.error = RethrownException("Error in ClientLoop.run")
@@ -218,9 +235,7 @@ class LongTests(BrokerTest):
["perftest", "--count", 1000,
"--base-name", str(qpid.datatypes.uuid4()), "--port", broker.port()],
["qpid-queue-stats", "-a", "localhost:%s" %(broker.port())],
- [os.path.join(self.rootdir, "testagent/testagent"), "localhost",
- str(broker.port())]
- ]:
+ ["testagent", "localhost", str(broker.port())] ]:
batch.append(ClientLoop(broker, cmd))
clients.append(batch)
@@ -238,7 +253,7 @@ class LongTests(BrokerTest):
start_mclients(b)
while time.time() < endtime:
- time.sleep(min(5,self.duration()))
+ time.sleep(min(5,self.duration()/2))
for b in cluster[alive:]: b.ready() # Check if a broker crashed.
# Kill the first broker. Ignore errors on its clients and all the mclients
for c in clients[alive] + mclients: c.expect_fail()
@@ -252,7 +267,6 @@ class LongTests(BrokerTest):
b = cluster.start()
start_clients(b)
for b in cluster[alive:]: start_mclients(b)
-
for c in chain(mclients, *clients):
c.stop()
@@ -283,6 +297,11 @@ class StoreTests(BrokerTest):
m = cluster.start("restartme").get_message("q")
self.assertEqual("x", m.content)
+ def stop_cluster(self,broker):
+ """Clean shut-down of a cluster"""
+ self.assertEqual(0, qpid_cluster.main(
+ ["qpid-cluster", "-kf", broker.host_port()]))
+
def test_persistent_restart(self):
"""Verify persistent cluster shutdown/restart scenarios"""
cluster = self.cluster(0, args=self.args() + ["--cluster-size=3"])
@@ -298,7 +317,7 @@ class StoreTests(BrokerTest):
self.assertEqual(c.get_message("q").content, "2")
# Shut down the entire cluster cleanly and bring it back up
a.send_message("q", Message("3", durable=True))
- self.assertEqual(0, qpid_cluster.main(["qpid-cluster", "-kf", a.host_port()]))
+ self.stop_cluster(a)
a = cluster.start("a", wait=False)
b = cluster.start("b", wait=False)
c = cluster.start("c", wait=True)
@@ -316,7 +335,7 @@ class StoreTests(BrokerTest):
b.kill()
self.assertEqual(c.get_message("q").content, "4")
c.send_message("q", Message("clean", durable=True))
- self.assertEqual(0, qpid_cluster.main(["qpid-cluster", "-kf", c.host_port()]))
+ self.stop_cluster(c)
a = cluster.start("a", wait=False)
b = cluster.start("b", wait=False)
c = cluster.start("c", wait=True)
@@ -329,7 +348,7 @@ class StoreTests(BrokerTest):
a.terminate()
cluster2 = self.cluster(1, args=self.args())
try:
- a = cluster2.start("a", expect=EXPECT_EXIT_OK)
+ a = cluster2.start("a", expect=EXPECT_EXIT_FAIL)
a.ready()
self.fail("Expected exception")
except: pass
@@ -339,27 +358,29 @@ class StoreTests(BrokerTest):
cluster = self.cluster(0, args=self.args()+["--cluster-size=2"])
a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
b = cluster.start("b", expect=EXPECT_EXIT_OK, wait=False)
- self.assertEqual(0, qpid_cluster.main(["qpid_cluster", "-kf", a.host_port()]))
+ self.stop_cluster(a)
self.assertEqual(a.wait(), 0)
self.assertEqual(b.wait(), 0)
# Restart with a different member and shut down.
a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
c = cluster.start("c", expect=EXPECT_EXIT_OK, wait=False)
- self.assertEqual(0, qpid_cluster.main(["qpid_cluster", "-kf", a.host_port()]))
+ self.stop_cluster(a)
self.assertEqual(a.wait(), 0)
self.assertEqual(c.wait(), 0)
-
# Mix members from both shutdown events, they should fail
- a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
- b = cluster.start("b", expect=EXPECT_EXIT_OK, wait=False)
+ # FIXME aconway 2010-03-11: can't predict the exit status of these
+ # as it depends on the order of delivery of initial-status messages.
+ # See comment at top of this file.
+ a = cluster.start("a", expect=EXPECT_UNKNOWN, wait=False)
+ b = cluster.start("b", expect=EXPECT_UNKNOWN, wait=False)
self.assertRaises(Exception, lambda: a.ready())
self.assertRaises(Exception, lambda: b.ready())
def assert_dirty_store(self, broker):
- self.assertRaises(Exception, lambda: broker.ready())
+ assert retry(lambda: os.path.exists(broker.log)), "Missing log file %s"%broker.log
msg = re.compile("critical.*no clean store")
- assert msg.search(readfile(broker.log))
+ assert retry(lambda: msg.search(readfile(broker.log))), "Expected dirty store message in %s"%broker.log
def test_solo_store_clean(self):
# A single node cluster should always leave a clean store.
@@ -371,7 +392,6 @@ class StoreTests(BrokerTest):
self.assertEqual(a.get_message("q").content, "x")
def test_last_store_clean(self):
-
# Verify that only the last node in a cluster to shut down has
# a clean store. Start with cluster of 3, reduce to 1 then
# increase again to ensure that a node that was once alone but
@@ -390,13 +410,41 @@ class StoreTests(BrokerTest):
time.sleep(0.1) # pause for a to find out hes last.
a.kill() # really last
# b & c should be dirty
- b = cluster.start("b", wait=False, expect=EXPECT_EXIT_OK)
+ b = cluster.start("b", wait=False, expect=EXPECT_EXIT_FAIL)
self.assert_dirty_store(b)
- c = cluster.start("c", wait=False, expect=EXPECT_EXIT_OK)
+ c = cluster.start("c", wait=False, expect=EXPECT_EXIT_FAIL)
self.assert_dirty_store(c)
# a should be clean
a = cluster.start("a")
self.assertEqual(a.get_message("q").content, "x")
+ def test_restart_clean(self):
+ """Verify that we can re-start brokers one by one in a
+ persistent cluster after a clean oshutdown"""
+ cluster = self.cluster(0, self.args())
+ a = cluster.start("a", expect=EXPECT_EXIT_OK)
+ b = cluster.start("b", expect=EXPECT_EXIT_OK)
+ c = cluster.start("c", expect=EXPECT_EXIT_OK)
+ a.send_message("q", Message("x", durable=True))
+ self.stop_cluster(a)
+ a = cluster.start("a")
+ b = cluster.start("b")
+ c = cluster.start("c")
+ self.assertEqual(c.get_message("q").content, "x")
+ def test_join_sub_size(self):
+ """Verify that after starting a cluster with cluster-size=N,
+ we can join new members even if size < N-1"""
+ cluster = self.cluster(0, self.args())
+ a = cluster.start("a", wait=False, expect=EXPECT_EXIT_FAIL)
+ b = cluster.start("b", wait=False, expect=EXPECT_EXIT_FAIL)
+ c = cluster.start("c")
+ a.send_message("q", Message("x", durable=True))
+ a.send_message("q", Message("y", durable=True))
+ a.kill()
+ b.kill()
+ a = cluster.start("a")
+ self.assertEqual(c.get_message("q").content, "x")
+ b = cluster.start("b")
+ self.assertEqual(c.get_message("q").content, "y")
diff --git a/qpid/cpp/src/tests/qpid_recv.cpp b/qpid/cpp/src/tests/qpid_recv.cpp
index 9e4e202053..10738578ed 100644
--- a/qpid/cpp/src/tests/qpid_recv.cpp
+++ b/qpid/cpp/src/tests/qpid_recv.cpp
@@ -27,12 +27,14 @@
#include <qpid/Options.h>
#include <qpid/log/Logger.h>
#include <qpid/log/Options.h>
+#include <qpid/client/amqp0_10/FailoverUpdates.h>
#include "TestOptions.h"
#include <iostream>
-
+#include <memory>
using namespace qpid::messaging;
+using qpid::client::amqp0_10::FailoverUpdates;
using namespace std;
@@ -54,6 +56,7 @@ struct Options : public qpid::Options
uint tx;
uint rollbackFrequency;
bool printHeaders;
+ bool failoverUpdates;
qpid::log::Options log;
Options(const std::string& argv0=std::string())
@@ -69,6 +72,7 @@ struct Options : public qpid::Options
tx(0),
rollbackFrequency(0),
printHeaders(false),
+ failoverUpdates(false),
log(argv0)
{
addOptions()
@@ -84,6 +88,7 @@ struct Options : public qpid::Options
("tx", qpid::optValue(tx, "N"), "batch size for transactions (0 implies transaction are not used)")
("rollback-frequency", qpid::optValue(rollbackFrequency, "N"), "rollback frequency (0 implies no transaction will be rolledback)")
("print-headers", qpid::optValue(printHeaders), "If specified print out all message headers as well as content")
+ ("failover-updates", qpid::optValue(failoverUpdates), "Listen for membership updates distributed via amq.failover")
("help", qpid::optValue(help), "print this usage statement");
add(log);
}
@@ -143,9 +148,10 @@ int main(int argc, char ** argv)
{
Options opts;
if (opts.parse(argc, argv)) {
+ Connection connection(opts.connectionOptions);
try {
- Connection connection(opts.connectionOptions);
connection.open(opts.url);
+ std::auto_ptr<FailoverUpdates> updates(opts.failoverUpdates ? new FailoverUpdates(connection) : 0);
Session session = connection.newSession(opts.tx > 0);
Receiver receiver = session.createReceiver(opts.address);
receiver.setCapacity(opts.capacity);
@@ -201,6 +207,7 @@ int main(int argc, char ** argv)
return 0;
} catch(const std::exception& error) {
std::cerr << "Failure: " << error.what() << std::endl;
+ connection.close();
}
}
return 1;
diff --git a/qpid/cpp/src/tests/qpid_send.cpp b/qpid/cpp/src/tests/qpid_send.cpp
index 57c348ab9c..a8b0241a1d 100644
--- a/qpid/cpp/src/tests/qpid_send.cpp
+++ b/qpid/cpp/src/tests/qpid_send.cpp
@@ -25,16 +25,15 @@
#include <qpid/messaging/Message.h>
#include <qpid/messaging/Sender.h>
#include <qpid/messaging/Session.h>
+#include <qpid/client/amqp0_10/FailoverUpdates.h>
#include "TestOptions.h"
#include <fstream>
#include <iostream>
+#include <memory>
using namespace qpid::messaging;
-using qpid::framing::Uuid;
-using qpid::sys::AbsTime;
-using qpid::sys::now;
-using qpid::sys::TIME_INFINITE;
+using qpid::client::amqp0_10::FailoverUpdates;
typedef std::vector<std::string> string_vector;
@@ -49,7 +48,6 @@ struct Options : public qpid::Options
std::string url;
std::string connectionOptions;
std::string address;
- int64_t timeout;
uint count;
std::string id;
std::string replyto;
@@ -64,13 +62,13 @@ struct Options : public qpid::Options
uint tx;
uint rollbackFrequency;
uint capacity;
+ bool failoverUpdates;
qpid::log::Options log;
Options(const std::string& argv0=std::string())
: qpid::Options("Options"),
help(false),
url("amqp:tcp:127.0.0.1"),
- timeout(TIME_INFINITE),
count(1),
sendEos(0),
durable(false),
@@ -78,13 +76,13 @@ struct Options : public qpid::Options
tx(0),
rollbackFrequency(0),
capacity(0),
+ failoverUpdates(false),
log(argv0)
{
addOptions()
("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to")
("address,a", qpid::optValue(address, "ADDRESS"), "address to drain from")
("connection-options", qpid::optValue(connectionOptions, "OPTIONS"), "options for the connection")
- ("timeout,t", qpid::optValue(timeout, "TIMEOUT"), "exit after the specified time")
("count,c", qpid::optValue(count, "COUNT"), "stop after count messages have been sent, zero disables")
("id,i", qpid::optValue(id, "ID"), "use the supplied id instead of generating one")
("reply-to", qpid::optValue(replyto, "REPLY-TO"), "specify reply-to address")
@@ -99,6 +97,7 @@ struct Options : public qpid::Options
("capacity", qpid::optValue(capacity, "N"), "size of the senders outgoing message queue")
("tx", qpid::optValue(tx, "N"), "batch size for transactions (0 implies transaction are not used)")
("rollback-frequency", qpid::optValue(rollbackFrequency, "N"), "rollback frequency (0 implies no transaction will be rolledback)")
+ ("failover-updates", qpid::optValue(failoverUpdates), "Listen for membership updates distributed via amq.failover")
("help", qpid::optValue(help), "print this usage statement");
add(log);
}
@@ -182,9 +181,10 @@ int main(int argc, char ** argv)
{
Options opts;
if (opts.parse(argc, argv)) {
+ Connection connection(opts.connectionOptions);
try {
- Connection connection(opts.connectionOptions);
connection.open(opts.url);
+ std::auto_ptr<FailoverUpdates> updates(opts.failoverUpdates ? new FailoverUpdates(connection) : 0);
Session session = connection.newSession(opts.tx > 0);
Sender sender = session.createSender(opts.address);
if (opts.capacity) sender.setCapacity(opts.capacity);
@@ -230,6 +230,7 @@ int main(int argc, char ** argv)
return 0;
} catch(const std::exception& error) {
std::cout << "Failed: " << error.what() << std::endl;
+ connection.close();
}
}
return 1;
diff --git a/qpid/cpp/src/tests/qpid_stream.cpp b/qpid/cpp/src/tests/qpid_stream.cpp
index ca21fa248b..5ed7f84492 100644
--- a/qpid/cpp/src/tests/qpid_stream.cpp
+++ b/qpid/cpp/src/tests/qpid_stream.cpp
@@ -40,16 +40,33 @@ struct Args : public qpid::Options
{
std::string url;
std::string address;
+ uint size;
uint rate;
bool durable;
-
- Args() : url("amqp:tcp:127.0.0.1:5672"), address("test-queue"), rate(1000), durable(false)
+ uint receiverCapacity;
+ uint senderCapacity;
+ uint ackFrequency;
+
+ Args() :
+ url("amqp:tcp:127.0.0.1:5672"),
+ address("test-queue"),
+ size(512),
+ rate(1000),
+ durable(false),
+ receiverCapacity(0),
+ senderCapacity(0),
+ ackFrequency(1)
{
addOptions()
("url", qpid::optValue(url, "URL"), "Url to connect to.")
("address", qpid::optValue(address, "ADDRESS"), "Address to stream messages through.")
+ ("size", qpid::optValue(size, "bytes"), "Message size in bytes (content only, not headers).")
("rate", qpid::optValue(rate, "msgs/sec"), "Rate at which to stream messages.")
- ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.");
+ ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.")
+ ("sender-capacity", qpid::optValue(senderCapacity, "N"), "Credit window (0 implies infinite window)")
+ ("receiver-capacity", qpid::optValue(receiverCapacity, "N"), "Credit window (0 implies infinite window)")
+ ("ack-frequency", qpid::optValue(ackFrequency, "N"),
+ "Ack frequency (0 implies none of the messages will get accepted)");
}
};
@@ -70,8 +87,8 @@ struct Client : qpid::sys::Runnable
void run()
{
+ Connection connection;
try {
- Connection connection;
connection.open(opts.url);
Session session = connection.newSession();
doWork(session);
@@ -79,6 +96,7 @@ struct Client : qpid::sys::Runnable
connection.close();
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
+ connection.close();
}
}
@@ -93,7 +111,8 @@ struct Publish : Client
void doWork(Session& session)
{
Sender sender = session.createSender(opts.address);
- Message msg;
+ if (opts.senderCapacity) sender.setCapacity(opts.senderCapacity);
+ Message msg(std::string(opts.size, 'X'));
uint64_t interval = qpid::sys::TIME_SEC / opts.rate;
uint64_t sent = 0, missedRate = 0;
qpid::sys::AbsTime start = qpid::sys::now();
@@ -123,9 +142,12 @@ struct Consume : Client
double maxLatency = 0;
double totalLatency = 0;
Receiver receiver = session.createReceiver(opts.address);
+ if (opts.receiverCapacity) receiver.setCapacity(opts.receiverCapacity);
while (receiver.fetch(msg)) {
- session.acknowledge();//TODO: add batching option
++received;
+ if (opts.ackFrequency && (received % opts.ackFrequency == 0)) {
+ session.acknowledge();
+ }
//calculate latency
uint64_t receivedAt = timestamp(qpid::sys::now());
uint64_t sentAt = msg.getHeaders()[TIMESTAMP].asUint64();
diff --git a/qpid/cpp/src/tests/quick_topictest.ps1 b/qpid/cpp/src/tests/quick_topictest.ps1
index b2efbdd684..8f5b2caff7 100644
--- a/qpid/cpp/src/tests/quick_topictest.ps1
+++ b/qpid/cpp/src/tests/quick_topictest.ps1
@@ -20,11 +20,11 @@
# Quick and quiet topic test for make check.
[string]$me = $myInvocation.InvocationName
$srcdir = Split-Path $me
-& "$srcdir\topictest.ps1" -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1
+Invoke-Expression "$srcdir\topictest.ps1 -subscribers 2 -messages 2 -batches 1" > topictest.log 2>&1
if (!$?) {
"$me FAILED:"
cat topictest.log
- exit $LastExitCode
+ exit 1
}
Remove-Item topictest.log
exit 0
diff --git a/qpid/cpp/src/tests/testagent/testagent.cpp b/qpid/cpp/src/tests/testagent.cpp
index 61b47d83da..61b47d83da 100644
--- a/qpid/cpp/src/tests/testagent/testagent.cpp
+++ b/qpid/cpp/src/tests/testagent.cpp
diff --git a/qpid/cpp/src/tests/testagent.mk b/qpid/cpp/src/tests/testagent.mk
new file mode 100644
index 0000000000..f5a84b07ff
--- /dev/null
+++ b/qpid/cpp/src/tests/testagent.mk
@@ -0,0 +1,51 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Build a simple qmf agent for test purposes.
+
+QMF_GEN=$(top_srcdir)/managementgen/qmf-gen
+
+TESTAGENT_GEN_SRC= \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Parent.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Child.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Parent.cpp \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Child.cpp \
+ testagent_gen/qmf/org/apache/qpid/agent/example/ArgsParentCreate_child.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/EventChildCreated.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/EventChildCreated.cpp \
+ testagent_gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.cpp \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Package.h \
+ testagent_gen/qmf/org/apache/qpid/agent/example/Package.cpp
+
+$(TESTAGENT_GEN_SRC): testagent_gen.timestamp
+
+testagent_gen.timestamp: testagent.xml
+ $(QMF_GEN) -o testagent_gen/qmf $(srcdir)/testagent.xml
+ touch testagent_gen.timestamp
+
+CLEANFILES+=$(TESTAGENT_GEN_SRC) testagent_gen.timestamp
+
+testagent-testagent.$(OBJEXT): $(TESTAGENT_GEN_SRC)
+qpidtest_PROGRAMS+=testagent
+testagent_CXXFLAGS=$(CXXFLAGS) -Itestagent_gen
+testagent_SOURCES=testagent.cpp $(TESTAGENT_GEN_SRC)
+testagent_LDADD=$(top_builddir)/src/libqmf.la
+
+EXTRA_DIST+=testagent.xml
diff --git a/qpid/cpp/src/tests/testagent/schema.xml b/qpid/cpp/src/tests/testagent.xml
index 8be21b7e68..8be21b7e68 100644
--- a/qpid/cpp/src/tests/testagent/schema.xml
+++ b/qpid/cpp/src/tests/testagent.xml
diff --git a/qpid/cpp/src/tests/testagent/Makefile.am b/qpid/cpp/src/tests/testagent/Makefile.am
deleted file mode 100644
index 7ff7cb0bd7..0000000000
--- a/qpid/cpp/src/tests/testagent/Makefile.am
+++ /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.
-#
-
-# Build a simple qmf agent for test purposes.
-
-QMF_GEN=$(top_srcdir)/managementgen/qmf-gen
-GEN_SRC= \
- gen/qmf/org/apache/qpid/agent/example/Parent.h \
- gen/qmf/org/apache/qpid/agent/example/Child.h \
- gen/qmf/org/apache/qpid/agent/example/Parent.cpp \
- gen/qmf/org/apache/qpid/agent/example/Child.cpp \
- gen/qmf/org/apache/qpid/agent/example/ArgsParentCreate_child.h \
- gen/qmf/org/apache/qpid/agent/example/EventChildCreated.h \
- gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.h \
- gen/qmf/org/apache/qpid/agent/example/EventChildCreated.cpp \
- gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.cpp \
- gen/qmf/org/apache/qpid/agent/example/Package.h \
- gen/qmf/org/apache/qpid/agent/example/Package.cpp
-
-$(GEN_SRC): gen.timestamp
-
-gen.timestamp: schema.xml
- $(QMF_GEN) -o gen/qmf $(srcdir)/schema.xml
- touch gen.timestamp
-
-CLEANFILES=$(GEN_SRC)
-
-INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -Igen
-
-noinst_PROGRAMS=testagent
-testagent_SOURCES=testagent.cpp $(GEN_SRC)
-testagent_LDADD=$(top_builddir)/src/libqmf.la
-
-EXTRA_DIST=schema.xml
diff --git a/qpid/cpp/src/tests/topictest.ps1 b/qpid/cpp/src/tests/topictest.ps1
index 0d22cea657..59a483c2d5 100644
--- a/qpid/cpp/src/tests/topictest.ps1
+++ b/qpid/cpp/src/tests/topictest.ps1
@@ -17,19 +17,21 @@
# under the License.
#
-# Run the C++ topic test
-$srcdir = Split-Path $myInvocation.InvocationName
-
# Parameters with default values: s (subscribers) m (messages) b (batches)
# h (host) t (false; use transactions)
param (
[int]$subscribers = 10,
- [int]$messages = 2000,
+ [int]$message_count = 2000,
[int]$batches = 10,
[string]$broker,
[switch] $t # transactional
)
+# Run the C++ topic test
+[string]$me = $myInvocation.InvocationName
+$srcdir = Split-Path $me
+#$srcdir = Split-Path $myInvocation.InvocationName
+
# Clean up old log files
Get-Item subscriber_*.log | Remove-Item
@@ -41,7 +43,7 @@ if ($t) {
. $srcdir\find_prog.ps1 .\topic_listener.exe
function subscribe {
- param ([int]$num)
+ param ([int]$num, [string]$sub)
"Start subscriber $num"
$LOG = "subscriber_$num.log"
$cmdline = ".\$sub\topic_listener $transactional > $LOG 2>&1
@@ -51,7 +53,8 @@ function subscribe {
}
function publish {
- Invoke-Expression ".\$sub\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional" 2>&1
+ param ([string]$sub)
+ Invoke-Expression ".\$sub\topic_publisher --messages $message_count --batches $batches --subscribers $subscribers $host $transactional" 2>&1
}
if ($broker.length) {
@@ -60,11 +63,11 @@ if ($broker.length) {
$i = $subscribers
while ($i -gt 0) {
- subscribe $i
+ subscribe $i $sub
$i--
}
# FIXME aconway 2007-03-27: Hack around startup race. Fix topic test.
Start-Sleep 2
-publish
+publish $sub
exit $LastExitCode
diff --git a/qpid/cpp/xml/cluster.xml b/qpid/cpp/xml/cluster.xml
index 44f055ea32..8f94eb3fd1 100644
--- a/qpid/cpp/xml/cluster.xml
+++ b/qpid/cpp/xml/cluster.xml
@@ -64,7 +64,6 @@
<field name="cluster-id" type="uuid"/>>
<field name="store-state" type="store-state"/>
<field name="shutdown-id" type="uuid"/>
- <field name="config-seq" type="sequence-no"/>
<field name="first-config" type="str16"/>
</control>
@@ -122,6 +121,10 @@
encryption (e.g. ssl), ssf is the bit length of the key. Zero if no
encryption provided. -->
<field name="ssf" type="uint32"/>
+ <!-- external auth id (e.g. ssl client certificate id) -->
+ <field name="authid" type="str16"/>
+ <!-- exclude certain sasl mechs, used with ssl and sasl-external -->
+ <field name="nodict" type="bit"/>
</control>
<!-- Marks the cluster-wide point when a connection is considered closed. -->
diff --git a/qpid/doc/book/Makefile b/qpid/doc/book/Makefile
new file mode 100644
index 0000000000..2781f131ab
--- /dev/null
+++ b/qpid/doc/book/Makefile
@@ -0,0 +1,42 @@
+###############################################################
+#
+# This Makefile requires the following:
+#
+# Apache FOP, version 0.95 or higher
+# Docbook 4.5
+# Docbook XSL stylesheets - tested with xsl-stylesheets-1.75.2
+# xsltproc
+# xmllint
+#
+
+DOCBOOKXSL = /usr/share/sgml/docbook/xsl-stylesheets-1.75.2/
+
+out/pdf/qpid-book.pdf: build/qpid-book.fo
+ mkdir -p out/pdf
+ fop build/qpid-book.fo out/pdf/qpid-book.pdf
+
+build/qpid-book.fo: build/qpid-book.xml
+ xsltproc ${DOCBOOKXSL}/fo/docbook.xsl build/qpid-book.xml >build/qpid-book.fo
+
+build/qpid-book.xml:
+ mkdir -p build
+ xmllint --xinclude src/Book.xml >build/qpid-book.xml
+
+out/html/index.html: build/qpid-book.xml
+ mkdir -p out/html
+ mkdir -p out/html/Common_Content
+ cd out/html; ln -s ../../src/images
+ cd out/html/Common_Content; ln -s ../../../src/images
+ cd out/html; xsltproc ${DOCBOOKXSL}/html/chunk.xsl ../../build/qpid-book.xml
+
+pdf: out/pdf/qpid-book.pdf
+
+html: out/html/index.html
+
+all: pdf html
+
+clean:
+ rm -rf build
+ rm -rf out
+
+ \ No newline at end of file
diff --git a/qpid/doc/book/README.txt b/qpid/doc/book/README.txt
new file mode 100644
index 0000000000..2deb20a13b
--- /dev/null
+++ b/qpid/doc/book/README.txt
@@ -0,0 +1,118 @@
+The documentation in this directory is written in DocBook 4.5. The
+original content was taken from the Apache Qpid Wiki.
+
+1. Building the Documentation
+
+You need the following to build the documentation:
+
+- Apache FOP, version 0.95 or higher
+- Docbook 4.5
+- Docbook XSL stylesheets - I have tested with xsl-stylesheets-1.75.2
+- xsltproc
+- xmllint
+
+On many Linux machines, these can usually be installed from standard
+repos. For instance, on Fedora they can be installed as follows:
+
+$ sudo yum install fop docbook-dtds docbook-style-xsl libxslt libxml2
+
+After installing, use make to build the documentation:
+
+$ make
+
+By default, the Makefile builds a PDF. It supports the following
+targets:
+
+pdf Make the PDF
+html Make HTML pages
+all Make both PDF and HTML
+clean Delete the build and output directories
+
+
+You will see quite a few error messages. Many of these are due to
+unresolved links, and these should go away. Many are due to the
+verbosity of Apache FOP, which generates many warnings.
+
+2. Editing Tools
+
+For Emacs, I like nxml-mode, especially if you learn how to use tag
+completion, outlining, etc. This is described in some detail in
+http://www.dpawson.co.uk/relaxng/nxml/info.html.
+
+For vi, the macros described in this Linux Journal article may be
+helpful: http://www.linuxjournal.com/article/7737.
+
+Commercial XML editors provide good support for DocBook. On Windows, I
+like Stylus Studio (http://www.stylusstudio.com/). On Linux, I like
+Oxygen (http://www.oxygenxml.com/).
+
+Here's a page on authoring tools for DocBook:
+http://wiki.docbook.org/topic/DocBookAuthoringTools
+
+
+3. File Structure
+
+The source files are in qpid/doc/book/src.
+
+The following XInclude tree shows the organization of files in the
+document.
+
+Book.xml
+ Book-Info.xml
+ Introduction.xml
+ AMQP.xml
+ Getting-Started.xml
+ Download.xml
+ AMQP-Messaging-Broker-CPP.xml
+ Running-CPP-Broker.xml
+ Cheat-Sheet-for-configuring-Queue-Options.xml
+ Cheat-Sheet-for-configuring-Exchange-Options.xml
+ Using-Broker-Federation.xml
+ SSL.xml
+ LVQ.xml
+ queue-state-replication.xml
+ Starting-a-cluster.xml
+ ACL.xml
+ Managing-CPP-Broker.xml
+ QMan-Qpid-Management-bridge.xml
+ Qpid-Management-Framework.xml
+ Management-Design-notes.xml
+ QMF-Python-Console-Tutorial.xml
+ AMQP-Messaging-Broker-Java.xml
+ Java-Broker-Feature-Guide.xml
+ Qpid-Java-FAQ.xml
+ Java-Environment-Variables.xml
+ Qpid-Troubleshooting-Guide.xml
+ Add-New-Users.xml
+ Configure-ACLs.xml
+ Configure-Java-Qpid-to-use-a-SSL-connection.xml
+ Configure-Log4j-CompositeRolling-Appender.xml
+ Configure-the-Broker-via-config.xml.xml
+ Configure-the-Virtual-Hosts-via-virtualhosts.xml.xml
+ Debug-using-log4j.xml
+ How-to-Tune-M3-Java-Broker-Performance.xml
+ Qpid-Java-Build-How-To.xml
+ Use-Priority-Queues.xml
+ Qpid-JMX-Management-Console.xml
+ Configuring-Management-Users.xml
+ Configuring-Qpid-JMX-Management-Console.xml
+ Management-Console-Security.xml
+ Qpid-JMX-Management-Console-FAQ.xml
+ Qpid-JMX-Management-Console-User-Guide.xml
+ Qpid-Management-Features.xml
+ MessageStore-Tool.xml
+ Qpid-Java-Broker-Management-CLI.xml
+ AMQP-Java-JMS-Messaging-Client.xml
+ System-Properties.xml
+ Connection-URL-Format.xml
+ Binding-URL-Format.xml
+ AMQP-C++-Messaging-Client.xml
+ AMQP-.NET-Messaging-Client.xml
+ NET-User-Guide.xml
+ Excel-AddIn.xml
+ WCF.xml
+ AMQP-Python-Messaging-Client.xml
+ PythonBrokerTest.xml
+ AMQP-Ruby-Messaging-Client.xml
+ AMQP-Compatibility.xml
+ Qpid-Interoperability-Documentation.xml
diff --git a/qpid/doc/book/build.sh b/qpid/doc/book/build.sh
new file mode 100755
index 0000000000..fd78ef79e8
--- /dev/null
+++ b/qpid/doc/book/build.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -ex
+
+########################################################################
+#
+# Build a PDF from Docbook XML
+#
+# The Makefile is cleaner ....
+#
+########################################################################
+
+rm -rf build
+mkdir -p build
+mkdir -p pdf
+
+# Assemble all documents using XInclude
+xmllint --xinclude src/Book.xml >build/qpid-book.xml
+
+# Create the .fo
+xsltproc /usr/share/sgml/docbook/xsl-stylesheets-1.75.2/fo/docbook.xsl build/qpid-book.xml >build/qpid-book.fo
+
+# Use Apache FOP to create the PDF
+fop build/qpid-book.fo pdf/qpid-book.pdf
diff --git a/qpid/doc/book/build.xml b/qpid/doc/book/build.xml
new file mode 100644
index 0000000000..ff6c058f9f
--- /dev/null
+++ b/qpid/doc/book/build.xml
@@ -0,0 +1,173 @@
+<!--
+ Build Apache Qpid documentation.
+
+ For documentation on using XSLT in ant, see http://ant.apache.org/manual/CoreTasks/style.html
+
+ For documentation on using Apache FOP in ant, see http://xmlgraphics.apache.org/fop/0.94/anttask.html
+
+ Note: Validation is currently off by default, too many dangling references. We will tighten this up as soon as we can.
+ -->
+
+<project
+ name="generate"
+ basedir="."
+ default="pdf">
+
+ <property name="Qpid" value="http://qpid.apache.org"/>
+
+
+<!--
+###########################################################################
+#
+# Directories
+#
+# Change the directory paths in this section to the correct paths for
+# your machine.
+#
+###########################################################################
+-->
+
+ <property name="src.dir" location="src"/>
+ <property name="build.dir" location="build"/>
+ <property name="out.dir" location="out"/>
+
+ <!-- Docbook schemas and stylesheets -->
+ <property name="schema.dir" location="docbook"/>
+ <property name="style.dir" location="docbook-xsl"/>
+ <property name="fo.stylesheet" location="${style.dir}/fo/docbook.xsl" />
+ <property name="html.stylesheet" location="${style.dir}/html/docbook.xsl" />
+
+ <!-- ${lib.dir} has subdirectories for saxon and fop -->
+ <property name="lib.dir" location="lib"/>
+
+ <property name="xmllint" location="/usr/bin/xmllint"/>
+
+<!--
+###########################################################################
+#
+# Setting up tasks
+#
+# You shouldn't need to change anything in this section or following sections.
+#
+###########################################################################
+-->
+
+ <path id="saxon6.classpath">
+ <pathelement location="${lib.dir}/saxon/resolver.jar"/>
+ <pathelement location="${lib.dir}/saxon/xml-apis.jar"/>
+ <pathelement location="${lib.dir}/saxon/xercesImpl.jar"/>
+ <pathelement location="${lib.dir}/saxon/saxon.jar"/>
+ </path>
+
+<taskdef name="fop"
+ classname="org.apache.fop.tools.anttasks.Fop">
+ <classpath>
+ <fileset dir="${lib.dir}/fop-0.95/lib">
+ <include name="*.jar"/>
+ </fileset>
+ <fileset dir="${lib.dir}/fop-0.95/build">
+ <include name="fop.jar"/>
+ <include name="fop-hyph.jar" />
+ </fileset>
+ </classpath>
+</taskdef>
+
+<!--
+###########################################################################
+#
+# Tasks
+#
+###########################################################################
+-->
+
+<!--
+ init
+-->
+
+<target name="init">
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${out.dir}"/>
+</target>
+
+<!--
+ XInclude
+-->
+
+<target name="xinclude" depends="init">
+ <exec executable="${xmllint}">
+ <arg value="-o"/>
+ <arg value="${build.dir}/xinclude.xml"/>
+ <arg value="--xinclude"/>
+ <arg value="${src.dir}/Book.xml"/>
+ </exec>
+</target>
+
+
+
+<!--
+ FO
+-->
+
+ <target name="fo" depends="xinclude" description="Generates qpid-book.fo, which is needed to create a PDF">
+
+ <xslt in="${build.dir}/xinclude.xml" out="${build.dir}/qpid-book.fo"
+ style="${fo.stylesheet}" classpathref="saxon6.classpath">
+ <param name="specdoc" expression="${spec.code}"/>
+ <param name="uri" expression="${spec.uri}"/>
+ </xslt>
+ </target>
+
+
+<!--
+ PDF
+-->
+
+<target name="pdf" depends="fo" description="Generates qpid-book.pdf">
+ <fop format="application/pdf"
+ fofile="${build.dir}/qpid-book.fo"
+ outfile="${out.dir}/qpid-book.pdf"/>
+</target
+>
+<!--
+ HTML
+-->
+
+ <target name="html" depends="xinclude" description="Generates qpid-book.html">
+ <xslt in="${build.dir}/xinclude.xml" out="${out.dir}/qpid-book.html"
+ style="${html.stylesheet}" classpathref="saxon6.classpath">
+ </xslt>
+ </target>
+
+<!--
+ Validate
+-->
+
+<target name="validate" depends="xinclude">
+ <xmlvalidate file="${build.dir}/xinclude.xml" warn="true">
+ <dtd publicId="-//OASIS//DTD DocBook V4.5//EN"
+ location="docbook/docbook.dtd"/>
+ </xmlvalidate>
+</target>
+
+<!--
+ Clean
+-->
+
+<target name="clean">
+ <delete dir="${build.dir}"/>
+</target>
+
+<!--
+ Check
+-->
+
+<target name="check" depends="xinclude">
+ <xmlvalidate file="${build.dir}/xinclude.xml" warn="false">
+ <dtd publicId="-//OASIS//DTD DocBook V4.5//EN"
+ location="docbook/docbook.dtd"/>
+ </xmlvalidate>
+</target>
+
+
+</project>
+
diff --git a/qpid/doc/book/src/SASL-Compatibility.xml b/qpid/doc/book/src/SASL-Compatibility.xml
index 96c523e519..beb138c182 100644
--- a/qpid/doc/book/src/SASL-Compatibility.xml
+++ b/qpid/doc/book/src/SASL-Compatibility.xml
@@ -12,18 +12,18 @@ This table list the various SASL mechanisms that each component supports. The ve
functionality was added to the product.
|| Component || ANONYMOUS || CRAM-MD5 || DIGEST-MD5 || EXTERNAL || GSSAPI/Kerberos || PLAIN ||
-| C++ Broker |M3\[[#1]\] |M3\[[#1],[#2]\]| | |M3\[[#1],[#2]\] | M1 |
-| C++ Client |M3\[[#1]\] | | | | | M1 |
+| C++ Broker |M3 |M3 | M3 |0.8\[[#1]\]|M3 | M1 |
+| C++ Client |M3 |0.5 | 0.5 |0.8\[[#1]\]| | M1 |
| Java Broker | | M1 | | | | M1 |
-| Java Client | | M1 | | | | M1 |
+| Java Client | | M1 | | M1 | | M1 |
| .Net Client | M2 | M2 | M2 | M2 | | M2 |
-| Python Client | | | | | | ? |
-| Ruby Client | | | | | | ? |
+| Python Client |0.6\[[#2]\]|0.6\[[#2]\]|0.6\[[#2]\] |0.6\[[#2]\]|0.6\[[#2]\] | M4 |
+| Ruby Client |0.6\[[#2]\]|0.6\[[#2]\]|0.6\[[#2]\] |0.6\[[#2]\]|0.6\[[#2]\] | M4 |
{anchor:1}
-1: Support for these will be in M3 (currently available on trunk).
+1: Only enabled for client authenticated SSL connections.
{anchor:2}
-2: C++ Broker uses [Cyrus Sasl|http://freshmeat.net/projects/cyrussasl/] which supports CRAM-MD5 and GSSAPI but these have not been tested yet
+2: On linux only via cyrus-sasl integration.
h4. Custom Mechanisms
diff --git a/qpid/doc/book/src/schemas.xml b/qpid/doc/book/src/schemas.xml
index b78cdd5d3c..550481ca0a 100644
--- a/qpid/doc/book/src/schemas.xml
+++ b/qpid/doc/book/src/schemas.xml
@@ -21,37 +21,73 @@
-->
<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
- <uri resource="Download.xml" typeId="DocBook"/>
- <uri resource="Getting-Started.xml" typeId="DocBook"/>
- <uri resource="WCF.xml" typeId="DocBook"/>
- <uri resource="Book-Info.xml" typeId="DocBook"/>
- <uri resource="Book-Info.xml" typeId="DocBook"/>
- <uri resource="Book.xml" uri="../../../../../../../usr/share/xml/docbook5/schema/rng/5.0/docbookxi.rnc"/>
- <uri resource="queue%20state%20replication.xml" typeId="DocBook"/>
- <uri resource="queue state replication.xml" typeId="DocBook"/>
- <uri resource="AMQP Ruby Messaging Client.xml" typeId="DocBook"/>
- <uri resource="AMQP Compatibility.xml" typeId="DocBook"/>
- <uri resource="Qpid Troubleshooting Guide.xml" typeId="DocBook"/>
- <uri resource="Book_Info.xml" typeId="DocBook"/>
- <uri resource="Book_Info.xml" typeId="DocBook"/>
- <uri resource="AMQP-Messaging-Broker-CPP.xml" typeId="DocBook"/>
- <uri resource="Configure the Broker via config.xml.xml" typeId="DocBook"/>
- <uri resource="SSL.xml" typeId="DocBook"/>
- <uri resource="Using Broker Federation.xml" typeId="DocBook"/>
- <uri resource="Cheat Sheet for configuring Exchange Options.xml" typeId="DocBook"/>
- <uri resource="foo.xml" typeId="DocBook"/>
- <uri resource="Download.xml" typeId="DocBook"/>
- <uri resource="Download.xml" typeId="DocBook"/>
- <uri resource="Starting a cluster.xml" typeId="DocBook"/>
- <uri resource="queue state replication.xml" typeId="DocBook"/>
- <uri resource="LVQ.xml" typeId="DocBook"/>
- <uri resource="LVQ.xml" typeId="DocBook"/>
- <uri resource="Cheat Sheet for configuring Queue Options.xml" typeId="DocBook"/>
- <uri resource="Cheat Sheet for configuring Exchange Options.xml" typeId="DocBook"/>
- <uri resource="Cheat Sheet for configuring Exchange Options.xml" typeId="DocBook"/>
- <uri resource="AMQP-Messaging-Broker-CPP.xml" typeId="DocBook"/>
- <uri resource="RASC.xml" typeId="DocBook"/>
- <uri resource="Brokers.xml" typeId="DocBook"/>
- <uri resource="AMQP.xml" typeId="DocBook"/>
- <uri resource="qpid-book.xml" typeId="DocBook"/>
+ <uri resource="ACL.xml" typeId="DocBook"/>
+ <uri resource="Add-New-Users.xml" typeId="DocBook"/>
+ <uri resource="AMQP-C++-Messaging-Client.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Compatibility.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Java-JMS-Messaging-Client.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Messaging-Broker-CPP.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Messaging-Broker-Java.xml" typeId="DocBook"/>
+ <uri resource="AMQP-.NET-Messaging-Client.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Python-Messaging-Client.xml" typeId="DocBook"/>
+ <uri resource="AMQP-Ruby-Messaging-Client.xml" typeId="DocBook"/>
+ <uri resource="AMQP.xml" typeId="DocBook"/>
+ <uri resource="Binding-URL-Format.xml" typeId="DocBook"/>
+ <uri resource="Book-Info.xml" typeId="DocBook"/>
+ <uri resource="Book.xml" typeId="DocBook"/>
+ <uri resource="Broker-CPP.xml" typeId="DocBook"/>
+ <uri resource="Broker-Java.xml" typeId="DocBook"/>
+ <uri resource="Cheat-Sheet-for-configuring-Exchange-Options.xml" typeId="DocBook"/>
+ <uri resource="Cheat-Sheet-for-configuring-Queue-Options.xml" typeId="DocBook"/>
+ <uri resource="Clients.xml" typeId="DocBook"/>
+ <uri resource="Configure-ACLs.xml" typeId="DocBook"/>
+ <uri resource="Configure-Java-Qpid-to-use-a-SSL-connection.xml" typeId="DocBook"/>
+ <uri resource="Configure-Log4j-CompositeRolling-Appender.xml" typeId="DocBook"/>
+ <uri resource="Configure-the-Broker-via-config.xml.xml" typeId="DocBook"/>
+ <uri resource="Configure-the-Virtual-Hosts-via-virtualhosts.xml.xml" typeId="DocBook"/>
+ <uri resource="Configuring-Management-Users.xml" typeId="DocBook"/>
+ <uri resource="Configuring-Qpid-JMX-Management-Console.xml" typeId="DocBook"/>
+ <uri resource="Connection-URL-Format.xml" typeId="DocBook"/>
+ <uri resource="Debug-using-log4j.xml" typeId="DocBook"/>
+ <uri resource="Download.xml" typeId="DocBook"/>
+ <uri resource="Excel-AddIn.xml" typeId="DocBook"/>
+ <uri resource="FAQ.xml" typeId="DocBook"/>
+ <uri resource="foo.xml" typeId="DocBook"/>
+ <uri resource="f.xml" typeId="DocBook"/>
+ <uri resource="Getting-Started.xml" typeId="DocBook"/>
+ <uri resource="How-to-Tune-M3-Java-Broker-Performance.xml" typeId="DocBook"/>
+ <uri resource="How-to-Use-JNDI.xml" typeId="DocBook"/>
+ <uri resource="Introduction.xml" typeId="DocBook"/>
+ <uri resource="Java-Broker-Feature-Guide.xml" typeId="DocBook"/>
+ <uri resource="Java-Environment-Variables.xml" typeId="DocBook"/>
+ <uri resource="LVQ.xml" typeId="DocBook"/>
+ <uri resource="Management-Console-Security.xml" typeId="DocBook"/>
+ <uri resource="Management-Design-notes.xml" typeId="DocBook"/>
+ <uri resource="Managing-CPP-Broker.xml" typeId="DocBook"/>
+ <uri resource="MessageStore-Tool.xml" typeId="DocBook"/>
+ <uri resource="NET-User-Guide.xml" typeId="DocBook"/>
+ <uri resource="PythonBrokerTest.xml" typeId="DocBook"/>
+ <uri resource="QMan-Qpid-Management-bridge.xml" typeId="DocBook"/>
+ <uri resource="QMF-Python-Console-Tutorial.xml" typeId="DocBook"/>
+ <uri resource="Qpid-ACLs.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Interoperability-Documentation.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Java-Broker-Management-CLI.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Java-Build-How-To.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Java-FAQ.xml" typeId="DocBook"/>
+ <uri resource="Qpid-JMX-Management-Console-FAQ.xml" typeId="DocBook"/>
+ <uri resource="Qpid-JMX-Management-Console-User-Guide.xml" typeId="DocBook"/>
+ <uri resource="Qpid-JMX-Management-Console.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Management-Features.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Management-Framework.xml" typeId="DocBook"/>
+ <uri resource="Qpid-Troubleshooting-Guide.xml" typeId="DocBook"/>
+ <uri resource="queue-state-replication.xml" typeId="DocBook"/>
+ <uri resource="Running-CPP-Broker.xml" typeId="DocBook"/>
+ <uri resource="SASL-Compatibility.xml" typeId="DocBook"/>
+ <uri resource="SSL.xml" typeId="DocBook"/>
+ <uri resource="Starting-a-cluster.xml" typeId="DocBook"/>
+ <uri resource="System-Properties.xml" typeId="DocBook"/>
+ <uri resource="Use-Priority-Queues.xml" typeId="DocBook"/>
+ <uri resource="Using-Broker-Federation.xml" typeId="DocBook"/>
+ <uri resource="Using-Qpid-with-other-JNDI-Providers.xml" typeId="DocBook"/>
+ <uri resource="WCF.xml" typeId="DocBook"/>
</locatingRules>
diff --git a/qpid/dotnet/TestClient/TestClient.csproj b/qpid/dotnet/TestClient/TestClient.csproj
index 3b54a27b44..cc7ab37657 100644
--- a/qpid/dotnet/TestClient/TestClient.csproj
+++ b/qpid/dotnet/TestClient/TestClient.csproj
@@ -1,4 +1,4 @@
-<!--
+<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -19,7 +19,7 @@
-->
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
diff --git a/qpid/dotnet/TopicListener/TopicListener.csproj b/qpid/dotnet/TopicListener/TopicListener.csproj
index a1e95cd668..46da42ea61 100644
--- a/qpid/dotnet/TopicListener/TopicListener.csproj
+++ b/qpid/dotnet/TopicListener/TopicListener.csproj
@@ -1,4 +1,4 @@
-<!--
+<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -19,7 +19,7 @@
-->
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
diff --git a/qpid/dotnet/TopicPublisher/TopicPublisher.csproj b/qpid/dotnet/TopicPublisher/TopicPublisher.csproj
index 695d39ffe7..fbbf77fb8e 100644
--- a/qpid/dotnet/TopicPublisher/TopicPublisher.csproj
+++ b/qpid/dotnet/TopicPublisher/TopicPublisher.csproj
@@ -1,4 +1,4 @@
-<!--
+<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -19,7 +19,7 @@
-->
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
diff --git a/qpid/extras/qmf/.gitignore b/qpid/extras/qmf/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/qpid/extras/qmf/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
index aa18b5a136..e552596058 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
@@ -31,7 +31,6 @@ import org.apache.qpid.server.configuration.ExchangeConfigType;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeReferrer;
import org.apache.qpid.server.exchange.ExchangeType;
-import org.apache.qpid.server.exchange.topic.TopicBinding;
import org.apache.qpid.server.exchange.topic.TopicExchangeResult;
import org.apache.qpid.server.exchange.topic.TopicMatcherResult;
import org.apache.qpid.server.exchange.topic.TopicNormalizer;
@@ -47,7 +46,6 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -55,6 +53,7 @@ import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicLong;
public class ManagementExchange implements Exchange, QMFService.Listener
@@ -69,8 +68,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener
private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults =
new ConcurrentHashMap<AMQShortString, TopicExchangeResult>();
- private final Map<TopicBinding, FieldTable> _topicBindings = new HashMap<TopicBinding, FieldTable>();
- private final Set<Binding> _bindingSet = new HashSet<Binding>();
+ private final Set<Binding> _bindingSet = new CopyOnWriteArraySet<Binding>();
private UUID _id;
private static final String AGENT_BANK = "0";
@@ -254,21 +252,7 @@ public class ManagementExchange implements Exchange, QMFService.Listener
public synchronized void addBinding(final Binding b)
{
- _bindingSet.add(b);
-
- for(BindingListener listener : _listeners)
- {
- listener.bindingAdded(this, b);
- }
-
- if(_bindingSet.size() > _bindingCountHigh)
- {
- _bindingCountHigh = _bindingSet.size();
- }
-
- TopicBinding binding = new TopicBinding(new AMQShortString(b.getBindingKey()), b.getQueue(), null);
-
- if(!_topicBindings.containsKey(binding))
+ if(_bindingSet.add(b))
{
AMQShortString routingKey = TopicNormalizer.normalize(new AMQShortString(b.getBindingKey()));
@@ -284,10 +268,20 @@ public class ManagementExchange implements Exchange, QMFService.Listener
{
result.addUnfilteredQueue(b.getQueue());
}
- _topicBindings.put(binding, null);
+ result.addBinding(b);
+ }
+
+ for(BindingListener listener : _listeners)
+ {
+ listener.bindingAdded(this, b);
+ }
+ if(_bindingSet.size() > _bindingCountHigh)
+ {
+ _bindingCountHigh = _bindingSet.size();
}
+
String bindingKey = b.getBindingKey();
if(bindingKey.startsWith("schema.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#."))
@@ -355,6 +349,13 @@ public class ManagementExchange implements Exchange, QMFService.Listener
HashSet<AMQQueue> queues = new HashSet<AMQQueue>();
for(TopicMatcherResult result : results)
{
+ TopicExchangeResult res = (TopicExchangeResult)result;
+
+ for(Binding b : res.getBindings())
+ {
+ b.incrementMatches();
+ }
+
queues.addAll(((TopicExchangeResult)result).getUnfilteredQueues());
}
for(AMQQueue queue : queues)
@@ -378,14 +379,11 @@ public class ManagementExchange implements Exchange, QMFService.Listener
public synchronized void removeBinding(final Binding binding)
{
- _bindingSet.remove(binding);
-
- TopicBinding topicBinding = new TopicBinding(new AMQShortString(binding.getBindingKey()), binding.getQueue(), null);
-
- if(_topicBindings.containsKey(topicBinding))
+ if(_bindingSet.remove(binding))
{
- AMQShortString bindingKey = TopicNormalizer.normalize(topicBinding.getBindingKey());
+ AMQShortString bindingKey = TopicNormalizer.normalize(new AMQShortString(binding.getBindingKey()));
TopicExchangeResult result = _topicExchangeResults.get(bindingKey);
+ result.removeBinding(binding);
result.removeUnfilteredQueue(binding.getQueue());
}
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 6d360b2084..381c376f56 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
@@ -1004,14 +1004,12 @@ public class QMFService implements ConfigStore.ConfigEventListener
public Long getUnackedMessages()
{
- // TODO
- return 0l;
+ return _obj.getUnackedMessageCount();
}
public Long getUnackedMessagesHigh()
{
- // TODO
- return 0l;
+ return _obj.getUnackedMessageCountHigh();
}
public Long getUnackedMessagesLow()
@@ -1404,8 +1402,7 @@ public class QMFService implements ConfigStore.ConfigEventListener
public Long getDelivered()
{
- // TODO
- return 0l;
+ return _obj.getDelivered();
}
public UUID getId()
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 41ae52e9b8..be4e8f8ec1 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
@@ -110,7 +110,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
public String[] getExchangeTypes() throws IOException
{
ArrayList<String> exchangeTypes = new ArrayList<String>();
- for(ExchangeType<? extends Exchange> ex : _exchangeFactory.getRegisteredTypes())
+ for(ExchangeType<? extends Exchange> ex : _exchangeFactory.getPublicCreatableTypes())
{
exchangeTypes.add(ex.getName().toString());
}
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 3b17da5af7..fe5da20fa5 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
@@ -200,16 +200,22 @@ public class AMQChannel implements SessionConfig
private void incrementOutstandingTxnsIfNecessary()
{
- //There can currently only be at most one outstanding transaction
- //due to only having LocalTransaction support. Set value to 1 if 0.
- _txnCount.compareAndSet(0,1);
+ if(isTransactional())
+ {
+ //There can currently only be at most one outstanding transaction
+ //due to only having LocalTransaction support. Set value to 1 if 0.
+ _txnCount.compareAndSet(0,1);
+ }
}
private void decrementOutstandingTxnsIfNecessary()
{
- //There can currently only be at most one outstanding transaction
- //due to only having LocalTransaction support. Set value to 0 if 1.
- _txnCount.compareAndSet(1,0);
+ if(isTransactional())
+ {
+ //There can currently only be at most one outstanding transaction
+ //due to only having LocalTransaction support. Set value to 0 if 1.
+ _txnCount.compareAndSet(1,0);
+ }
}
public Long getTxnStarts()
@@ -313,7 +319,7 @@ public class AMQChannel implements SessionConfig
}
else
{
- _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage,isTransactional()));
+ _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage));
}
}
@@ -1031,7 +1037,7 @@ public class AMQChannel implements SessionConfig
}
- private AMQMessage createAMQMessage(IncomingMessage incomingMessage, boolean transactional)
+ private AMQMessage createAMQMessage(IncomingMessage incomingMessage)
throws AMQException
{
@@ -1055,7 +1061,6 @@ public class AMQChannel implements SessionConfig
private class MessageDeliveryAction implements ServerTransaction.Action
{
- private boolean _transactional;
private IncomingMessage _incommingMessage;
private ArrayList<? extends BaseQueue> _destinationQueues;
@@ -1063,7 +1068,6 @@ public class AMQChannel implements SessionConfig
ArrayList<? extends BaseQueue> destinationQueues,
boolean transactional)
{
- _transactional = transactional;
_incommingMessage = currentMessage;
_destinationQueues = destinationQueues;
}
@@ -1074,7 +1078,7 @@ public class AMQChannel implements SessionConfig
{
final boolean immediate = _incommingMessage.isImmediate();
- final AMQMessage amqMessage = createAMQMessage(_incommingMessage, _transactional);
+ final AMQMessage amqMessage = createAMQMessage(_incommingMessage);
MessageReference ref = amqMessage.newReference();
for(final BaseQueue queue : _destinationQueues)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
index 0b689c16a7..60c9a86b76 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
@@ -37,7 +37,7 @@ public class Binding
private final UUID _id;
private final AtomicLong _matches = new AtomicLong();
- Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments)
+ public Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments)
{
_id = id;
_bindingKey = bindingKey;
@@ -89,29 +89,30 @@ public class Binding
@Override
public boolean equals(final Object o)
{
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (o == null || !(o instanceof Binding))
+ {
+ return false;
+ }
final Binding binding = (Binding) o;
- if (!_bindingKey.equals(binding._bindingKey)) return false;
- if (!_exchange.equals(binding._exchange)) return false;
- if (!_queue.equals(binding._queue)) return false;
-
- return true;
+ return (_bindingKey == null ? binding.getBindingKey() == null : _bindingKey.equals(binding.getBindingKey()))
+ && (_exchange == null ? binding.getExchange() == null : _exchange.equals(binding.getExchange()))
+ && (_queue == null ? binding.getQueue() == null : _queue.equals(binding.getQueue()));
}
@Override
public int hashCode()
{
- int result = _bindingKey.hashCode();
- result = 31 * result + _queue.hashCode();
- result = 31 * result + _exchange.hashCode();
+ int result = _bindingKey == null ? 1 : _bindingKey.hashCode();
+ result = 31 * result + (_queue == null ? 3 : _queue.hashCode());
+ result = 31 * result + (_exchange == null ? 5 : _exchange.hashCode());
return result;
}
-
-
-
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java
index 95e2aa516b..4c9ec6619e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java
@@ -75,6 +75,10 @@ public interface QueueConfig extends ConfiguredObject<QueueConfigType, QueueConf
long getPersistentMsgEnqueues();
long getPersistentMsgDequeues();
+
+ long getUnackedMessageCount();
+
+ long getUnackedMessageCountHigh();
void purge(long request);
} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java
index 985ecb2be9..b101d70553 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java
@@ -43,5 +43,5 @@ public interface SubscriptionConfig extends ConfiguredObject<SubscriptionConfigT
boolean isExplicitAcknowledge();
-
+ Long getDelivered();
} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 1c4c341c14..9be8bddd28 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -20,8 +20,12 @@
*/
package org.apache.qpid.server.exchange;
-import org.apache.log4j.Logger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQUnknownExchangeType;
import org.apache.qpid.framing.AMQShortString;
@@ -30,10 +34,6 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
public class DefaultExchangeFactory implements ExchangeFactory
{
private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class);
@@ -60,6 +60,21 @@ public class DefaultExchangeFactory implements ExchangeFactory
{
return _exchangeClassMap.values();
}
+
+ public Collection<ExchangeType<? extends Exchange>> getPublicCreatableTypes()
+ {
+ Collection<ExchangeType<? extends Exchange>> publicTypes =
+ new ArrayList<ExchangeType<? extends Exchange>>();
+ publicTypes.addAll(_exchangeClassMap.values());
+
+ //Remove the ManagementExchange type if present, as these
+ //are private and cannot be created by external means
+ publicTypes.remove(ManagementExchange.TYPE);
+
+ return publicTypes;
+ }
+
+
public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete)
throws AMQException
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
index b91bf559f1..aa4cc1ec24 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
@@ -38,6 +38,8 @@ public interface ExchangeFactory
void initialise(VirtualHostConfiguration hostConfig);
Collection<ExchangeType<? extends Exchange>> getRegisteredTypes();
+
+ Collection<ExchangeType<? extends Exchange>> getPublicCreatableTypes();
Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
index 35c4a8f9b2..f58a6513a9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.qpid.framing.AMQTypedValue;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.message.AMQMessageHeader;
/**
@@ -38,69 +39,35 @@ class HeadersBinding
private static final Logger _logger = Logger.getLogger(HeadersBinding.class);
private final FieldTable _mappings;
+ private final Binding _binding;
private final Set<String> required = new HashSet<String>();
private final Map<String,Object> matches = new HashMap<String,Object>();
private boolean matchAny;
- private final class MatchesOrProcessor implements FieldTable.FieldTableElementProcessor
- {
- private Boolean _result = Boolean.FALSE;
-
- public boolean processElement(String propertyName, AMQTypedValue value)
- {
- if((value != null) && (value.getValue() != null) && value.getValue().equals(matches.get(propertyName)))
- {
- _result = Boolean.TRUE;
- return false;
- }
- return true;
- }
-
- public Object getResult()
- {
- return _result;
- }
- }
-
- private final class RequiredOrProcessor implements FieldTable.FieldTableElementProcessor
- {
- Boolean _result = Boolean.FALSE;
-
- public boolean processElement(String propertyName, AMQTypedValue value)
- {
- if(required.contains(propertyName))
- {
- _result = Boolean.TRUE;
- return false;
- }
- return true;
- }
-
- public Object getResult()
- {
- return _result;
- }
- }
-
-
-
/**
- * Creates a binding for a set of mappings. Those mappings whose value is
+ * Creates a header binding for a set of mappings. Those mappings whose value is
* null or the empty string are assumed only to be required headers, with
* no constraint on the value. Those with a non-null value are assumed to
* define a required match of value.
- * @param mappings the defined mappings this binding should use
+ *
+ * @param binding the binding to create a header binding using
*/
-
- HeadersBinding(FieldTable mappings)
+ public HeadersBinding(Binding binding)
{
- _mappings = mappings;
- initMappings();
+ _binding = binding;
+ if(_binding !=null)
+ {
+ _mappings = FieldTable.convertToFieldTable(_binding.getArguments());
+ initMappings();
+ }
+ else
+ {
+ _mappings = null;
+ }
}
-
+
private void initMappings()
{
-
_mappings.processOverElements(new FieldTable.FieldTableElementProcessor()
{
@@ -133,6 +100,11 @@ class HeadersBinding
{
return _mappings;
}
+
+ public Binding getBinding()
+ {
+ return _binding;
+ }
/**
* Checks whether the supplied headers match the requirements of this binding
@@ -250,4 +222,39 @@ class HeadersBinding
{
return key.startsWith("X-") || key.startsWith("x-");
}
-}
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (o == null)
+ {
+ return false;
+ }
+
+ if (!(o instanceof HeadersBinding))
+ {
+ return false;
+ }
+
+ final HeadersBinding hb = (HeadersBinding) o;
+
+ if(_binding == null)
+ {
+ if(hb.getBinding() != null)
+ {
+ return false;
+ }
+ }
+ else if (!_binding.equals(hb.getBinding()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
index ce0b14932f..e98a603d12 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
@@ -24,8 +24,6 @@ import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.BaseQueue;
@@ -36,10 +34,11 @@ import org.apache.qpid.server.binding.Binding;
import javax.management.JMException;
import java.util.ArrayList;
-import java.util.List;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
/**
* An exchange that binds queues based on a set of required headers and header values
@@ -72,7 +71,14 @@ public class HeadersExchange extends AbstractExchange
{
private static final Logger _logger = Logger.getLogger(HeadersExchange.class);
-
+
+ private final ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>> _bindingsByKey =
+ new ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>>();
+
+ private final CopyOnWriteArrayList<HeadersBinding> _bindingHeaderMatchers =
+ new CopyOnWriteArrayList<HeadersBinding>();
+
+
public static final ExchangeType<HeadersExchange> TYPE = new ExchangeType<HeadersExchange>()
{
@@ -102,34 +108,12 @@ public class HeadersExchange extends AbstractExchange
}
};
-
- private final List<Registration> _bindings = new CopyOnWriteArrayList<Registration>();
- private Map<AMQShortString, Registration> _bindingByKey = new ConcurrentHashMap<AMQShortString, Registration>();
-
-
public HeadersExchange()
{
super(TYPE);
}
+
- public void registerQueue(String routingKey, AMQQueue queue, Map<String,Object> args)
- {
- registerQueue(new AMQShortString(routingKey), queue, FieldTable.convertToFieldTable(args));
- }
-
- public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args)
- {
- _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() + " with " + args);
-
- Registration registration = new Registration(new HeadersBinding(args), queue, routingKey);
- _bindings.add(registration);
-
- }
-
- public void deregisterQueue(String routingKey, AMQQueue queue, Map<String,Object> args)
- {
- _bindings.remove(new Registration(args == null ? null : new HeadersBinding(FieldTable.convertToFieldTable(args)), queue, new AMQShortString(routingKey)));
- }
public ArrayList<BaseQueue> doRoute(InboundMessage payload)
{
@@ -138,24 +122,27 @@ public class HeadersExchange extends AbstractExchange
{
_logger.debug("Exchange " + getNameShortString() + ": routing message with headers " + header);
}
- boolean routed = false;
- ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>();
- for (Registration e : _bindings)
+
+ LinkedHashSet<BaseQueue> queues = new LinkedHashSet<BaseQueue>();
+
+ for (HeadersBinding hb : _bindingHeaderMatchers)
{
-
- if (e.binding.matches(header))
+ if (hb.matches(header))
{
+ Binding b = hb.getBinding();
+
+ b.incrementMatches();
+
if (_logger.isDebugEnabled())
{
_logger.debug("Exchange " + getNameShortString() + ": delivering message with headers " +
- header + " to " + e.queue.getNameShortString());
+ header + " to " + b.getQueue().getNameShortString());
}
- queues.add(e.queue);
-
- routed = true;
+ queues.add(b.getQueue());
}
}
- return queues;
+
+ return new ArrayList<BaseQueue>(queues);
}
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
@@ -166,38 +153,49 @@ public class HeadersExchange extends AbstractExchange
public boolean isBound(AMQShortString routingKey, AMQQueue queue)
{
- return isBound(queue);
+ String bindingKey = (routingKey == null) ? "" : routingKey.toString();
+ CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
+
+ if(bindings != null)
+ {
+ for(Binding binding : bindings)
+ {
+ if(binding.getQueue().equals(queue))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
public boolean isBound(AMQShortString routingKey)
{
- return hasBindings();
+ String bindingKey = (routingKey == null) ? "" : routingKey.toString();
+ CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
+ return bindings != null && !bindings.isEmpty();
}
public boolean isBound(AMQQueue queue)
{
- for (Registration r : _bindings)
+ for (CopyOnWriteArraySet<Binding> bindings : _bindingsByKey.values())
{
- if (r.queue.equals(queue))
+ for(Binding binding : bindings)
{
- return true;
+ if(binding.getQueue().equals(queue))
+ {
+ return true;
+ }
}
}
+
return false;
}
public boolean hasBindings()
{
- return !_bindings.isEmpty();
- }
-
-
-
- protected FieldTable getHeaders(ContentHeaderBody contentHeaderFrame)
- {
- //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers,
- //but these are not yet implemented.
- return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders();
+ return !getBindings().isEmpty();
}
protected AbstractExchangeMBean createMBean() throws JMException
@@ -210,59 +208,51 @@ public class HeadersExchange extends AbstractExchange
return _logger;
}
-
- static class Registration
+ protected void onBind(final Binding binding)
{
- private final HeadersBinding binding;
- private final AMQQueue queue;
- private final AMQShortString routingKey;
+ String bindingKey = binding.getBindingKey();
+ AMQQueue queue = binding.getQueue();
+ AMQShortString routingKey = AMQShortString.valueOf(bindingKey);
+ Map<String,Object> args = binding.getArguments();
- Registration(HeadersBinding binding, AMQQueue queue, AMQShortString routingKey)
- {
- this.binding = binding;
- this.queue = queue;
- this.routingKey = routingKey;
- }
+ assert queue != null;
+ assert routingKey != null;
- public int hashCode()
- {
- int queueHash = queue.hashCode();
- int routingHash = routingKey == null ? 0 : routingKey.hashCode();
- return queueHash + routingHash;
- }
+ CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
- public boolean equals(Object o)
+ if(bindings == null)
{
- return o instanceof Registration
- && ((Registration) o).queue.equals(queue)
- && (routingKey == null ? ((Registration)o).routingKey == null
- : routingKey.equals(((Registration)o).routingKey));
- }
-
- public HeadersBinding getBinding()
- {
- return binding;
+ bindings = new CopyOnWriteArraySet<Binding>();
+ CopyOnWriteArraySet<Binding> newBindings;
+ if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null)
+ {
+ bindings = newBindings;
+ }
}
-
- public AMQQueue getQueue()
+
+ if(_logger.isDebugEnabled())
{
- return queue;
+ _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() +
+ " with binding key '" +bindingKey + "' and args: " + args);
}
- public AMQShortString getRoutingKey()
- {
- return routingKey;
- }
- }
+ _bindingHeaderMatchers.add(new HeadersBinding(binding));
+ bindings.add(binding);
- protected void onBind(final Binding binding)
- {
- registerQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments());
}
protected void onUnbind(final Binding binding)
{
- deregisterQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments());
+ assert binding != null;
+
+ CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(binding.getBindingKey());
+ if(bindings != null)
+ {
+ bindings.remove(binding);
+ }
+
+ _logger.debug("===============");
+ _logger.debug("Removing Binding: " + _bindingHeaderMatchers.remove(new HeadersBinding(binding)));
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
index 14f15dd92c..1245efdafa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
@@ -31,6 +31,7 @@ import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.BaseQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.exchange.topic.*;
import org.apache.qpid.server.filter.JMSSelectorFilter;
import org.apache.qpid.server.message.InboundMessage;
@@ -83,7 +84,7 @@ public class TopicExchange extends AbstractExchange
private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults =
new ConcurrentHashMap<AMQShortString, TopicExchangeResult>();
- private final Map<TopicBinding, FieldTable> _bindings = new HashMap<TopicBinding, FieldTable>();
+ private final Map<Binding, FieldTable> _bindings = new HashMap<Binding, FieldTable>();
private final Map<String, WeakReference<JMSSelectorFilter>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter>>();
@@ -92,20 +93,12 @@ public class TopicExchange extends AbstractExchange
super(TYPE);
}
- public synchronized void registerQueue(String rKey, AMQQueue queue, Map<String,Object> args)
- {
- try
- {
- registerQueue(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args));
- }
- catch (AMQInvalidArgumentException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQInvalidArgumentException
+ protected synchronized void registerQueue(final Binding binding) throws AMQInvalidArgumentException
{
+ AMQShortString rKey = new AMQShortString(binding.getBindingKey()) ;
+ AMQQueue queue = binding.getQueue();
+ FieldTable args = FieldTable.convertToFieldTable(binding.getArguments());
+
assert queue != null;
assert rKey != null;
@@ -114,8 +107,6 @@ public class TopicExchange extends AbstractExchange
AMQShortString routingKey = TopicNormalizer.normalize(rKey);
- TopicBinding binding = new TopicBinding(rKey, queue, args);
-
if(_bindings.containsKey(binding))
{
FieldTable oldArgs = _bindings.get(binding);
@@ -146,6 +137,8 @@ public class TopicExchange extends AbstractExchange
return;
}
}
+
+ result.addBinding(binding);
}
else
@@ -177,6 +170,8 @@ public class TopicExchange extends AbstractExchange
result.addUnfilteredQueue(queue);
}
}
+
+ result.addBinding(binding);
_bindings.put(binding, args);
}
@@ -226,7 +221,8 @@ public class TopicExchange extends AbstractExchange
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
{
- TopicBinding binding = new TopicBinding(routingKey, queue, arguments);
+ Binding binding = new Binding(null, routingKey.toString(), queue, this, FieldTable.convertToMap(arguments));
+
if (arguments == null)
{
return _bindings.containsKey(binding);
@@ -253,7 +249,7 @@ public class TopicExchange extends AbstractExchange
public boolean isBound(AMQShortString routingKey)
{
- for(TopicBinding b : _bindings.keySet())
+ for(Binding b : _bindings.keySet())
{
if(b.getBindingKey().equals(routingKey))
{
@@ -266,7 +262,7 @@ public class TopicExchange extends AbstractExchange
public boolean isBound(AMQQueue queue)
{
- for(TopicBinding b : _bindings.keySet())
+ for(Binding b : _bindings.keySet())
{
if(b.getQueue().equals(queue))
{
@@ -282,19 +278,16 @@ public class TopicExchange extends AbstractExchange
return !_bindings.isEmpty();
}
-
- public void deregisterQueue(String rKey, AMQQueue queue, Map<String, Object> args)
- {
- removeBinding(new TopicBinding(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args)));
- }
-
- private boolean removeBinding(final TopicBinding binding)
+ private boolean deregisterQueue(final Binding binding)
{
if(_bindings.containsKey(binding))
{
FieldTable bindingArgs = _bindings.remove(binding);
- AMQShortString bindingKey = TopicNormalizer.normalize(binding.getBindingKey());
+ AMQShortString bindingKey = TopicNormalizer.normalize(new AMQShortString(binding.getBindingKey()));
TopicExchangeResult result = _topicExchangeResults.get(bindingKey);
+
+ result.removeBinding(binding);
+
if(argumentsContainSelector(bindingArgs))
{
try
@@ -341,8 +334,14 @@ public class TopicExchange extends AbstractExchange
Collection<AMQQueue> queues = results.size() == 1 ? null : new HashSet<AMQQueue>();
for(TopicMatcherResult result : results)
{
+ TopicExchangeResult res = (TopicExchangeResult)result;
- queues = ((TopicExchangeResult)result).processMessage(message, queues);
+ for(Binding b : res.getBindings())
+ {
+ b.incrementMatches();
+ }
+
+ queues = res.processMessage(message, queues);
}
return queues;
}
@@ -350,14 +349,21 @@ public class TopicExchange extends AbstractExchange
}
- protected void onBind(final org.apache.qpid.server.binding.Binding binding)
+ protected void onBind(final Binding binding)
{
- registerQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments());
+ try
+ {
+ registerQueue(binding);
+ }
+ catch (AMQInvalidArgumentException e)
+ {
+ throw new RuntimeException(e);
+ }
}
- protected void onUnbind(final org.apache.qpid.server.binding.Binding binding)
+ protected void onUnbind(final Binding binding)
{
- deregisterQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments());
+ deregisterQueue(binding);
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java
deleted file mode 100644
index c6383a886e..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.exchange.topic;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.exchange.TopicExchange;
-
-public class TopicBinding
-{
- private final AMQShortString _bindingKey;
- private final AMQQueue _queue;
- private final FieldTable _args;
-
- public TopicBinding(AMQShortString bindingKey, AMQQueue queue, FieldTable args)
- {
- _bindingKey = bindingKey;
- _queue = queue;
- _args = args;
- }
-
- public AMQShortString getBindingKey()
- {
- return _bindingKey;
- }
-
- public AMQQueue getQueue()
- {
- return _queue;
- }
-
- public int hashCode()
- {
- return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode();
- }
-
- public boolean equals(Object o)
- {
- if(this == o)
- {
- return true;
- }
- if(o instanceof TopicBinding)
- {
- TopicBinding other = (TopicBinding) o;
- return (_queue == other._queue)
- && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey));
- }
- return false;
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
index d9a779802f..41dc0d749a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
@@ -21,14 +21,22 @@
package org.apache.qpid.server.exchange.topic;
import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.filter.MessageFilter;
import org.apache.qpid.server.message.InboundMessage;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
public final class TopicExchangeResult implements TopicMatcherResult
{
+ private final List<Binding> _bindings = new CopyOnWriteArrayList<Binding>();
private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>();
private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>();
@@ -64,6 +72,20 @@ public final class TopicExchangeResult implements TopicMatcherResult
return _unfilteredQueues.keySet();
}
+ public void addBinding(Binding binding)
+ {
+ _bindings.add(binding);
+ }
+
+ public void removeBinding(Binding binding)
+ {
+ _bindings.remove(binding);
+ }
+
+ public List<Binding> getBindings()
+ {
+ return new ArrayList<Binding>(_bindings);
+ }
public void addFilteredQueue(AMQQueue queue, MessageFilter filter)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index d3867d8140..45c84d7603 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -111,6 +111,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
void dequeue(QueueEntry entry, Subscription sub);
+ void decrementUnackedMsgCount();
boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index bf4015eb7a..1ba4f4d89b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -226,22 +226,29 @@ public class QueueEntryImpl implements QueueEntry
public void release()
{
- _stateUpdater.set(this,AVAILABLE_STATE);
- if(!getQueue().isDeleted())
+ EntryState state = _state;
+
+ if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, AVAILABLE_STATE))
{
- getQueue().requeue(this);
- if(_stateChangeListeners != null)
+ if(state instanceof SubscriptionAcquiredState)
{
- notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
+ getQueue().decrementUnackedMsgCount();
}
+
+ if(!getQueue().isDeleted())
+ {
+ getQueue().requeue(this);
+ if(_stateChangeListeners != null)
+ {
+ notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
+ }
+ }
+ else if(acquire())
+ {
+ routeToAlternate();
+ }
}
- else if(acquire())
- {
- routeToAlternate();
- }
-
-
}
public boolean releaseButRetain()
@@ -369,6 +376,7 @@ public class QueueEntryImpl implements QueueEntry
Subscription s = null;
if (state instanceof SubscriptionAcquiredState)
{
+ getQueue().decrementUnackedMsgCount();
s = ((SubscriptionAcquiredState) state).getSubscription();
s.onDequeue(this);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index b5d1290e98..cf2f637697 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -127,6 +127,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final AtomicLong _byteTxnEnqueues = new AtomicLong(0);
private final AtomicLong _msgTxnDequeues = new AtomicLong(0);
private final AtomicLong _byteTxnDequeues = new AtomicLong(0);
+ private final AtomicLong _unackedMsgCount = new AtomicLong(0);
+ private final AtomicLong _unackedMsgCountHigh = new AtomicLong(0);
private final AtomicInteger _bindingCountHigh = new AtomicInteger();
@@ -693,6 +695,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throws AMQException
{
_deliveredMessages.incrementAndGet();
+ incrementUnackedMsgCount();
+
sub.send(entry);
setLastSeenEntry(sub,entry);
@@ -2138,4 +2142,33 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
return String.valueOf(getNameShortString());
}
+
+ public long getUnackedMessageCountHigh()
+ {
+ return _unackedMsgCountHigh.get();
+ }
+
+ public long getUnackedMessageCount()
+ {
+ return _unackedMsgCount.get();
+ }
+
+ public void decrementUnackedMsgCount()
+ {
+ _unackedMsgCount.decrementAndGet();
+ }
+
+ private void incrementUnackedMsgCount()
+ {
+ long unackedMsgCount = _unackedMsgCount.incrementAndGet();
+
+ long unackedMsgCountHigh;
+ while(unackedMsgCount > (unackedMsgCountHigh = _unackedMsgCountHigh.get()))
+ {
+ if(_unackedMsgCountHigh.compareAndSet(unackedMsgCountHigh, unackedMsgCount))
+ {
+ break;
+ }
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
index 1309e05978..46c1a6af9a 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
@@ -30,7 +30,7 @@ import org.apache.log4j.Logger;
class SubFlushRunner implements ReadWriteRunnable
{
- private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
+ private static final Logger _logger = Logger.getLogger(SubFlushRunner.class);
private final Subscription _sub;
@@ -46,29 +46,36 @@ class SubFlushRunner implements ReadWriteRunnable
public void run()
{
-
- Thread.currentThread().setName(_name);
-
- boolean complete = false;
+ String originalName = Thread.currentThread().getName();
try
{
- CurrentActor.set(_sub.getLogActor());
- complete = getQueue().flushSubscription(_sub, ITERATIONS);
+ Thread.currentThread().setName(_name);
+
+ boolean complete = false;
+ try
+ {
+ CurrentActor.set(_sub.getLogActor());
+ complete = getQueue().flushSubscription(_sub, ITERATIONS);
+
+ }
+ catch (AMQException e)
+ {
+ _logger.error(e);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ if (!complete && !_sub.isSuspended())
+ {
+ getQueue().execute(this);
+ }
}
- catch (AMQException e)
- {
- _logger.error(e);
- }
finally
{
- CurrentActor.remove();
+ Thread.currentThread().setName(originalName);
}
- if (!complete && !_sub.isSuspended())
- {
- getQueue().execute(this);
- }
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
index c548f3ccad..eed57fbf39 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -94,6 +94,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
private LogSubject _logSubject;
private LogActor _logActor;
private UUID _id;
+ private final AtomicLong _deliveredCount = new AtomicLong(0);
private long _createTime = System.currentTimeMillis();
@@ -340,7 +341,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
{
return getQueue().getConfigStore();
}
-
+
+ public Long getDelivered()
+ {
+ return _deliveredCount.get();
+ }
public synchronized void setQueue(AMQQueue queue, boolean exclusive)
{
@@ -648,6 +653,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
throws AMQException
{
_deliveryMethod.deliverToClient(this,entry,deliveryTag);
+ _deliveredCount.incrementAndGet();
}
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 4cc7e6fce2..5b3f5250c5 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
@@ -101,6 +101,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
private String _traceExclude;
private String _trace;
private long _createTime = System.currentTimeMillis();
+ private final AtomicLong _deliveredCount = new AtomicLong(0);
public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode,
@@ -257,6 +258,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
{
return getQueue().getConfigStore();
}
+
+ public Long getDelivered()
+ {
+ return _deliveredCount.get();
+ }
public void creditStateChanged(boolean hasCredit)
{
@@ -531,7 +537,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
if(!excludeDueToFederation)
{
- if(_acceptMode == MessageAcceptMode.NONE)
+ if(_acceptMode == MessageAcceptMode.NONE && _acquireMode != MessageAcquireMode.PRE_ACQUIRED)
{
xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW));
}
@@ -558,7 +564,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
}
_session.sendMessage(xfr, _postIdSettingAction);
-
+ _deliveredCount.incrementAndGet();
if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED)
{
forceDequeue(entry, false);
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 63d540be6b..b5d5d7bba9 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
@@ -401,6 +401,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
public void selectTx()
{
_transaction = new LocalTransaction(this.getMessageStore());
+ _txnStarts.incrementAndGet();
}
public void commit()
@@ -424,16 +425,22 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
private void incrementOutstandingTxnsIfNecessary()
{
- //There can currently only be at most one outstanding transaction
- //due to only having LocalTransaction support. Set value to 1 if 0.
- _txnCount.compareAndSet(0,1);
+ if(isTransactional())
+ {
+ //There can currently only be at most one outstanding transaction
+ //due to only having LocalTransaction support. Set value to 1 if 0.
+ _txnCount.compareAndSet(0,1);
+ }
}
private void decrementOutstandingTxnsIfNecessary()
{
- //There can currently only be at most one outstanding transaction
- //due to only having LocalTransaction support. Set value to 0 if 1.
- _txnCount.compareAndSet(1,0);
+ if(isTransactional())
+ {
+ //There can currently only be at most one outstanding transaction
+ //due to only having LocalTransaction support. Set value to 0 if 1.
+ _txnCount.compareAndSet(1,0);
+ }
}
public Long getTxnStarts()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
index 06d5d80ac1..2d8b157297 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -31,6 +31,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.FieldTableFactory;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.binding.BindingFactory;
import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.message.AMQMessageHeader;
@@ -53,8 +54,10 @@ import org.apache.qpid.server.subscription.Subscription;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@@ -92,31 +95,31 @@ public class AbstractHeadersExchangeTestBase extends TestCase
protected TestQueue bindDefault(String... bindings) throws AMQException
{
- return bind("Queue" + (++count), bindings);
- }
+ String queueName = "Queue" + (++count);
- protected TestQueue bind(String queueName, String... bindings) throws AMQException
- {
- return bind(queueName, getHeaders(bindings));
+ return bind(queueName, queueName, getHeadersMap(bindings));
}
-
- protected TestQueue bind(String queue, FieldTable bindings) throws AMQException
+
+ protected void unbind(TestQueue queue, String... bindings) throws AMQException
{
- return bind(new TestQueue(new AMQShortString(queue)), bindings);
+ String queueName = queue.getName();
+ //TODO - check this
+ exchange.onUnbind(new Binding(null,queueName, queue, exchange, getHeadersMap(bindings)));
}
-
- protected TestQueue bind(TestQueue queue, String... bindings) throws AMQException
+
+ protected int getCount()
{
- return bind(queue, getHeaders(bindings));
+ return count;
}
- protected TestQueue bind(TestQueue queue, FieldTable bindings) throws AMQException
+ private TestQueue bind(String key, String queueName, Map<String,Object> args) throws AMQException
{
+ TestQueue queue = new TestQueue(new AMQShortString(queueName));
queues.add(queue);
- exchange.registerQueue(null, queue, bindings);
+ exchange.onBind(new Binding(null,key, queue, exchange, args));
return queue;
}
-
+
protected int route(Message m) throws AMQException
{
@@ -171,6 +174,23 @@ public class AbstractHeadersExchangeTestBase extends TestCase
}
}
+
+ static Map<String,Object> getHeadersMap(String... entries)
+ {
+ if(entries == null)
+ {
+ return null;
+ }
+
+ Map<String,Object> headers = new HashMap<String,Object>();
+
+ for (String s : entries)
+ {
+ String[] parts = s.split("=", 2);
+ headers.put(parts[0], parts.length > 1 ? parts[1] : "");
+ }
+ return headers;
+ }
static FieldTable getHeaders(String... entries)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
index 1e56a32383..a7c226cbd8 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
@@ -26,7 +26,9 @@ import java.util.Set;
import junit.framework.TestCase;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.queue.MockAMQQueue;
/**
*/
@@ -119,166 +121,193 @@ public class HeadersBindingTest extends TestCase
}
}
- private FieldTable bindHeaders = new FieldTable();
+ private Map<String,Object> bindHeaders = new HashMap<String,Object>();
private MockHeader matchHeaders = new MockHeader();
+ private int _count = 0;
+ private MockAMQQueue _queue;
+
+ protected void setUp()
+ {
+ _count++;
+ _queue = new MockAMQQueue(getQueueName());
+ }
+
+ protected String getQueueName()
+ {
+ return "Queue" + _count;
+ }
public void testDefault_1()
{
- bindHeaders.setString("A", "Value of A");
+ bindHeaders.put("A", "Value of A");
matchHeaders.setString("A", "Value of A");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testDefault_2()
{
- bindHeaders.setString("A", "Value of A");
+ bindHeaders.put("A", "Value of A");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Value of B");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testDefault_3()
{
- bindHeaders.setString("A", "Value of A");
+ bindHeaders.put("A", "Value of A");
matchHeaders.setString("A", "Altered value of A");
- assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertFalse(new HeadersBinding(b).matches(matchHeaders));
}
public void testAll_1()
{
- bindHeaders.setString("X-match", "all");
- bindHeaders.setString("A", "Value of A");
+ bindHeaders.put("X-match", "all");
+ bindHeaders.put("A", "Value of A");
matchHeaders.setString("A", "Value of A");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAll_2()
{
- bindHeaders.setString("X-match", "all");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "all");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
- assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertFalse(new HeadersBinding(b).matches(matchHeaders));
}
public void testAll_3()
{
- bindHeaders.setString("X-match", "all");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "all");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Value of B");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAll_4()
{
- bindHeaders.setString("X-match", "all");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "all");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Value of B");
matchHeaders.setString("C", "Value of C");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAll_5()
{
- bindHeaders.setString("X-match", "all");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "all");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Altered value of B");
matchHeaders.setString("C", "Value of C");
- assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertFalse(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_1()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
matchHeaders.setString("A", "Value of A");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_2()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_3()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Value of B");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_4()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Value of B");
matchHeaders.setString("C", "Value of C");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_5()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Value of A");
matchHeaders.setString("B", "Altered value of B");
matchHeaders.setString("C", "Value of C");
- assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertTrue(new HeadersBinding(b).matches(matchHeaders));
}
public void testAny_6()
{
- bindHeaders.setString("X-match", "any");
- bindHeaders.setString("A", "Value of A");
- bindHeaders.setString("B", "Value of B");
+ bindHeaders.put("X-match", "any");
+ bindHeaders.put("A", "Value of A");
+ bindHeaders.put("B", "Value of B");
matchHeaders.setString("A", "Altered value of A");
matchHeaders.setString("B", "Altered value of B");
matchHeaders.setString("C", "Value of C");
- assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ Binding b = new Binding(null, getQueueName(), _queue, null, bindHeaders);
+ assertFalse(new HeadersBinding(b).matches(matchHeaders));
}
public static junit.framework.Test suite()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
index 580bc78b8d..f982c3976f 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
@@ -106,6 +106,22 @@ public class HeadersExchangeTest extends AbstractHeadersExchangeTestBase
pb2.setMandatory(true);
routeAndTest(m1,true);
}
+
+ public void testOnUnbind() throws AMQException
+ {
+ TestQueue q1 = bindDefault("F0000");
+ TestQueue q2 = bindDefault("F0000=Aardvark");
+ TestQueue q3 = bindDefault("F0001");
+
+ routeAndTest(new Message(_protocolSession, "Message1", "F0000"), q1);
+ routeAndTest(new Message(_protocolSession, "Message2", "F0000=Aardvark"), q1, q2);
+ routeAndTest(new Message(_protocolSession, "Message3", "F0001"), q3);
+
+ unbind(q1,"F0000");
+ routeAndTest(new Message(_protocolSession, "Message4", "F0000"));
+ routeAndTest(new Message(_protocolSession, "Message5", "F0000=Aardvark"), q2);
+ }
+
public static junit.framework.Test suite()
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java
index daa0377e0a..4fa47d039e 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java
@@ -28,6 +28,7 @@ import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.binding.Binding;
import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.AMQException;
@@ -64,7 +65,7 @@ public class TopicExchangeTest extends TestCase
public void testNoRoute() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.*.#.b", queue,_exchange, null));
IncomingMessage message = createMessage("a.b");
@@ -76,7 +77,7 @@ public class TopicExchangeTest extends TestCase
public void testDirectMatch() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("ab"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.b", queue,_exchange, null));
IncomingMessage message = createMessage("a.b");
@@ -103,7 +104,7 @@ public class TopicExchangeTest extends TestCase
public void testStarMatch() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.*", queue,_exchange, null));
IncomingMessage message = createMessage("a.b");
@@ -142,7 +143,7 @@ public class TopicExchangeTest extends TestCase
public void testHashMatch() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.#"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.#", queue,_exchange, null));
IncomingMessage message = createMessage("a.b.c");
@@ -205,7 +206,7 @@ public class TopicExchangeTest extends TestCase
public void testMidHash() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.*.#.b", queue,_exchange, null));
IncomingMessage message = createMessage("a.c.d.b");
@@ -235,7 +236,7 @@ public class TopicExchangeTest extends TestCase
public void testMatchafterHash() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b.c"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.*.#.b.c", queue,_exchange, null));
IncomingMessage message = createMessage("a.c.b.b");
@@ -281,7 +282,7 @@ public class TopicExchangeTest extends TestCase
public void testHashAfterHash() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b.c.#.d"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.*.#.b.c.#.d", queue,_exchange, null));
IncomingMessage message = createMessage("a.c.b.b.c");
@@ -308,7 +309,7 @@ public class TopicExchangeTest extends TestCase
public void testHashHash() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.#.*.#.d"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.#.*.#.d", queue,_exchange, null));
IncomingMessage message = createMessage("a.c.b.b.c");
@@ -334,7 +335,7 @@ public class TopicExchangeTest extends TestCase
public void testSubMatchFails() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b.c.d"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.b.c.d", queue,_exchange, null));
IncomingMessage message = createMessage("a.b.c");
@@ -364,7 +365,7 @@ public class TopicExchangeTest extends TestCase
public void testMoreRouting() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.b", queue,_exchange, null));
IncomingMessage message = createMessage("a.b.c");
@@ -379,7 +380,7 @@ public class TopicExchangeTest extends TestCase
public void testMoreQueue() throws AMQException
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+ _exchange.registerQueue(new Binding(null,"a.b", queue,_exchange, null));
IncomingMessage message = createMessage("a");
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
index 7063beefca..dbd51af68c 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
@@ -572,4 +572,19 @@ public class MockAMQQueue implements AMQQueue
{
return 0;
}
+
+ public void decrementUnackedMsgCount()
+ {
+
+ }
+
+ public long getUnackedMessageCount()
+ {
+ return 0;
+ }
+
+ public long getUnackedMessageCountHigh()
+ {
+ return 0;
+ }
}
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 5ad297580e..4717a9495b 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
@@ -157,45 +157,9 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
+ _conn.getPassword());
}
- String saslMechs = brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS) != null ?
- brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS):
- System.getProperty("qpid.sasl_mechs", "PLAIN");
-
- // Sun SASL Kerberos client uses the
- // protocol + servername as the service key.
- String protocol = brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME) != null ?
- brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME):
- System.getProperty("qpid.sasl_protocol", "AMQP");
-
- String saslServerName = brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME) != null ?
- brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME):
- System.getProperty("qpid.sasl_server_name", "localhost");
-
- boolean useSSL = brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL);
-
- boolean useSASLEncryption = brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SASL_ENCRYPTION)?
- brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SASL_ENCRYPTION):
- Boolean.getBoolean("qpid.sasl_encryption");
-
- boolean useTcpNodelay = brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)?
- brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY):
- Boolean.getBoolean("amqj.tcp_nodelay");
-
-
ConnectionSettings conSettings = new ConnectionSettings();
- conSettings.setHost(brokerDetail.getHost());
- conSettings.setPort(brokerDetail.getPort());
- conSettings.setVhost(_conn.getVirtualHost());
- conSettings.setUsername(_conn.getUsername());
- conSettings.setPassword(_conn.getPassword());
- conSettings.setUseSASLEncryption(useSASLEncryption);
- conSettings.setUseSSL(useSSL);
- conSettings.setSaslMechs(saslMechs);
- conSettings.setTcpNodelay(useTcpNodelay);
- conSettings.setSaslProtocol(protocol);
- conSettings.setSaslServerName(saslServerName);
- conSettings.setHeartbeatInterval(getHeartbeatInterval(brokerDetail));
-
+ retriveConnectionSettings(conSettings,brokerDetail);
+
_qpidConnection.connect(conSettings);
_conn._connected = true;
@@ -328,6 +292,87 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
return ProtocolVersion.v0_10;
}
+ private void retriveConnectionSettings(ConnectionSettings conSettings, BrokerDetails brokerDetail)
+ {
+
+ conSettings.setHost(brokerDetail.getHost());
+ conSettings.setPort(brokerDetail.getPort());
+ conSettings.setVhost(_conn.getVirtualHost());
+ conSettings.setUsername(_conn.getUsername());
+ conSettings.setPassword(_conn.getPassword());
+
+ // ------------ sasl options ---------------
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS) != null)
+ {
+ conSettings.setSaslMechs(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_MECHS));
+ }
+
+ // Sun SASL Kerberos client uses the
+ // protocol + servername as the service key.
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME) != null)
+ {
+ conSettings.setSaslProtocol(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_PROTOCOL_NAME));
+ }
+
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME) != null)
+ {
+ conSettings.setSaslServerName(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_SASL_SERVER_NAME));
+ }
+
+ conSettings.setUseSASLEncryption(
+ brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SASL_ENCRYPTION));
+
+ // ------------- ssl options ---------------------
+ conSettings.setUseSSL(brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL));
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE) != null)
+ {
+ conSettings.setTrustStorePath(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE));
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD) != null)
+ {
+ conSettings.setTrustStorePassword(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_TRUST_STORE_PASSWORD));
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE) != null)
+ {
+ conSettings.setKeyStorePath(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE));
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD) != null)
+ {
+ conSettings.setKeyStorePassword(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_KEY_STORE_PASSWORD));
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS) != null)
+ {
+ conSettings.setCertAlias(
+ brokerDetail.getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS));
+ }
+ // ----------------------------
+
+ conSettings.setVerifyHostname(brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_SSL_VERIFY_HOSTNAME));
+
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY) != null)
+ {
+ conSettings.setTcpNodelay(
+ brokerDetail.getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY));
+ }
+
+ conSettings.setHeartbeatInterval(getHeartbeatInterval(brokerDetail));
+ }
+
// The idle_timeout prop is in milisecs while
// the new heartbeat prop is in secs
private int getHeartbeatInterval(BrokerDetails brokerDetail)
@@ -353,4 +398,9 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
}
return 0;
}
+
+ protected org.apache.qpid.transport.Connection getQpidConnection()
+ {
+ return _qpidConnection;
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java
new file mode 100644
index 0000000000..540b6042bf
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java
@@ -0,0 +1,16 @@
+package org.apache.qpid.client;
+
+import org.apache.qpid.transport.Connection;
+
+public class AMQTestConnection_0_10 extends AMQConnection
+{
+ public AMQTestConnection_0_10(String url) throws Exception
+ {
+ super(url);
+ }
+
+ public Connection getConnection()
+ {
+ return((AMQConnectionDelegate_0_10)_delegate).getQpidConnection();
+ }
+}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java b/qpid/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
index 35adda9348..4f4fc3ddd3 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
@@ -48,8 +48,13 @@ public class XAResourceImpl implements XAResource
*/
private Xid _xid;
+ /**
+ * The time for this resource
+ */
+ private int _timeout;
+
//--- constructor
-
+
/**
* Create an XAResource associated with a XASession
*
@@ -90,6 +95,10 @@ public class XAResourceImpl implements XAResource
_xaSession.createSession();
convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
+ finally
+ {
+ _xid = null;
+ }
checkStatus(result.getStatus());
}
@@ -171,6 +180,10 @@ public class XAResourceImpl implements XAResource
_xaSession.createSession();
convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
+ finally
+ {
+ _xid = null;
+ }
}
@@ -178,30 +191,13 @@ public class XAResourceImpl implements XAResource
* Obtains the current transaction timeout value set for this XAResource instance.
* If XAResource.setTransactionTimeout was not used prior to invoking this method,
* the return value is the default timeout i.e. 0;
- * otherwise, the value used in the previous setTransactionTimeout call is returned.
*
* @return The transaction timeout value in seconds.
* @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL.
*/
public int getTransactionTimeout() throws XAException
{
- int result = 0;
- if (_xid != null)
- {
- Future<GetTimeoutResult> future =
- _xaSession.getQpidSession().dtxGetTimeout(convertXid(_xid));
- try
- {
- result = (int) future.get().getTimeout();
- }
- catch (SessionException e)
- {
- // we need to restore the qpid session that has been closed
- _xaSession.createSession();
- convertExecutionErrorToXAErr(e.getException().getErrorCode());
- }
- }
- return result;
+ return _timeout;
}
/**
@@ -325,6 +321,10 @@ public class XAResourceImpl implements XAResource
_xaSession.createSession();
convertExecutionErrorToXAErr( e.getException().getErrorCode());
}
+ finally
+ {
+ _xid = null;
+ }
checkStatus(result.getStatus());
}
@@ -340,25 +340,29 @@ public class XAResourceImpl implements XAResource
*/
public boolean setTransactionTimeout(int timeout) throws XAException
{
- boolean result = false;
- if (_xid != null)
+ _timeout = timeout;
+ if (timeout != _timeout && _xid != null)
+ {
+ setDtxTimeout(_timeout);
+ }
+ return true;
+ }
+
+ private void setDtxTimeout(int timeout) throws XAException
+ {
+ try
{
- try
- {
- _xaSession.getQpidSession()
- .dtxSetTimeout(XidImpl.convert(_xid), timeout);
- }
- catch (QpidException e)
+ _xaSession.getQpidSession()
+ .dtxSetTimeout(XidImpl.convert(_xid), timeout);
+ }
+ catch (QpidException e)
+ {
+ if (_logger.isDebugEnabled())
{
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Cannot convert Xid into String format ", e);
- }
- throw new XAException(XAException.XAER_PROTO);
+ _logger.debug("Cannot convert Xid into String format ", e);
}
- result = true;
+ throw new XAException(XAException.XAER_PROTO);
}
- return result;
}
/**
@@ -413,6 +417,10 @@ public class XAResourceImpl implements XAResource
}
checkStatus(result.getStatus());
_xid = xid;
+ if (_timeout > 0)
+ {
+ setDtxTimeout(_timeout);
+ }
}
//------------------------------------------------------------------------
@@ -477,7 +485,15 @@ public class XAResourceImpl implements XAResource
throw new XAException(XAException.XAER_DUPID);
case NOT_FOUND:
// The XID is not valid.
- throw new XAException(XAException.XAER_NOTA);
+ try
+ {
+ throw new XAException(XAException.XAER_NOTA);
+ }
+ catch (XAException e)
+ {
+ e.printStackTrace();
+ throw e;
+ }
case ILLEGAL_STATE:
// Routine was invoked in an inproper context.
throw new XAException(XAException.XAER_PROTO);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
index c09472fcad..6d81f728c9 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
@@ -42,6 +42,14 @@ public interface BrokerDetails
public static final String OPTIONS_TCP_NO_DELAY = "tcp_nodelay";
public static final String OPTIONS_SASL_PROTOCOL_NAME = "sasl_protocol";
public static final String OPTIONS_SASL_SERVER_NAME = "sasl_server";
+
+ public static final String OPTIONS_TRUST_STORE = "trust_store";
+ public static final String OPTIONS_TRUST_STORE_PASSWORD = "trust_store_password";
+ public static final String OPTIONS_KEY_STORE = "key_store";
+ public static final String OPTIONS_KEY_STORE_PASSWORD = "key_store_password";
+ public static final String OPTIONS_SSL_VERIFY_HOSTNAME = "ssl_verify_hostname";
+ public static final String OPTIONS_SSL_CERT_ALIAS = "ssl_cert_alias";
+
public static final int DEFAULT_PORT = 5672;
public static final String SOCKET = "socket";
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
index e142d21e06..702746b3da 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
@@ -27,10 +27,13 @@ import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
+
/**
* Factory used to create SSLContexts. SSL needs to be configured
* before this will work.
@@ -68,7 +71,7 @@ public class SSLContextFactory {
*/
private String _trustStoreCertType;
-
+ private KeyManager customKeyManager;
public SSLContextFactory(String trustStorePath, String trustStorePassword,
String trustStoreCertType)
@@ -90,7 +93,7 @@ public class SSLContextFactory {
_trustStorePath = trustStorePath;
_trustStorePassword = trustStorePassword;
- if (_trustStorePassword.equals("none"))
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
{
_trustStorePassword = null;
}
@@ -99,7 +102,7 @@ public class SSLContextFactory {
_keyStorePath = keyStorePath;
_keyStorePassword = keyStorePassword;
- if (_keyStorePassword.equals("none"))
+ if (_keyStorePassword != null && _keyStorePassword.equals("none"))
{
_keyStorePassword = null;
}
@@ -113,29 +116,63 @@ public class SSLContextFactory {
}
}
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ KeyManager customKeyManager)
+ {
+
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
+ {
+ _trustStorePassword = null;
+ }
+ _trustStoreCertType = trustStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
+ }
+ if (_trustStoreCertType == null) {
+ throw new IllegalArgumentException("Cert type must be specified");
+ }
+
+ this.customKeyManager = customKeyManager;
+ }
+
+
/**
* Builds a SSLContext appropriate for use with a server
* @return SSLContext
* @throws GeneralSecurityException
* @throws IOException
*/
+
public SSLContext buildServerContext() throws GeneralSecurityException, IOException
{
- // Create keystore
- KeyStore ks = getInitializedKeyStore(_keyStorePath,_keyStorePassword);
-
- // Set up key manager factory to use our key store
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
- kmf.init(ks, _keyStorePassword.toCharArray());
-
- KeyStore ts = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ KeyStore ts = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ts);
// Initialize the SSLContext to work with our key managers.
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ if (customKeyManager != null)
+ {
+ sslContext.init(new KeyManager[]{customKeyManager},
+ tmf.getTrustManagers(), null);
+
+ }
+ else
+ {
+ // Create keystore
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_keyStorePath,_keyStorePassword);
+ // Set up key manager factory to use our key store
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
+ kmf.init(ks, _keyStorePassword.toCharArray());
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ }
+
return sslContext;
}
@@ -147,7 +184,7 @@ public class SSLContextFactory {
*/
public SSLContext buildClientContext() throws GeneralSecurityException, IOException
{
- KeyStore ks = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ks);
SSLContext context = SSLContext.getInstance("TLS");
@@ -155,41 +192,4 @@ public class SSLContextFactory {
return context;
}
- private KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
- {
- KeyStore ks = KeyStore.getInstance("JKS");
- InputStream in = null;
- try
- {
- File f = new File(storePath);
- if (f.exists())
- {
- in = new FileInputStream(f);
- }
- else
- {
- in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
- }
- if (in == null)
- {
- throw new IOException("Unable to load keystore resource: " + storePath);
- }
- ks.load(in, storePassword.toCharArray());
- }
- finally
- {
- if (in != null)
- {
- //noinspection EmptyCatchBlock
- try
- {
- in.close();
- }
- catch (IOException ignored)
- {
- }
- }
- }
- return ks;
- }
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
index 74064c9d11..d5f97f48a8 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
@@ -181,10 +181,25 @@ public class ClientDelegate extends ConnectionDelegate
@Override public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
{
SaslClient sc = conn.getSaslClient();
- if (sc != null && sc.getMechanismName().equals("GSSAPI") && getUserID() != null)
+ if (sc != null)
{
- conn.setUserID(getUserID());
+ if (sc.getMechanismName().equals("GSSAPI"))
+ {
+ String id = getKerberosUser();
+ if (id != null)
+ {
+ conn.setUserID(id);
+ }
+ }
+ else if (sc.getMechanismName().equals("EXTERNAL"))
+ {
+ if (conn.getSecurityLayer() != null)
+ {
+ conn.setUserID(conn.getSecurityLayer().getUserID());
+ }
+ }
}
+
conn.setState(OPEN);
}
@@ -245,7 +260,7 @@ public class ClientDelegate extends ConnectionDelegate
}
- private String getUserID()
+ private String getKerberosUser()
{
log.debug("Obtaining userID from kerberos");
String service = conSettings.getSaslProtocol() + "@" + conSettings.getSaslServerName();
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 8c2da9d77a..2ca5d28f42 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
@@ -25,14 +25,7 @@ import static org.apache.qpid.transport.Connection.State.CLOSING;
import static org.apache.qpid.transport.Connection.State.NEW;
import static org.apache.qpid.transport.Connection.State.OPEN;
import static org.apache.qpid.transport.Connection.State.OPENING;
-import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.network.io.IoTransport;
-import org.apache.qpid.transport.util.Logger;
-import org.apache.qpid.transport.util.Waiter;
-import org.apache.qpid.util.Strings;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslServer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -40,6 +33,14 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.transport.network.security.SecurityLayer;
+import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
+import org.apache.qpid.util.Strings;
+
/**
* Connection
@@ -109,7 +110,8 @@ public class Connection extends ConnectionInvoker
private Map<String,Object> _serverProperties;
private String userID;
private ConnectionSettings conSettings;
-
+ private SecurityLayer securityLayer;
+
// want to make this final
private int _connectionId;
@@ -215,10 +217,17 @@ public class Connection extends ConnectionInvoker
userID = settings.getUsername();
delegate = new ClientDelegate(settings);
- IoTransport.connect(settings.getHost(),
+ /*IoTransport.connect(settings.getHost(),
settings.getPort(),
ConnectionBinding.get(this),
- settings.isUseSSL());
+ settings.isUseSSL());*/
+
+ TransportBuilder transport = new TransportBuilder();
+ transport.init(this);
+ this.sender = transport.buildSenderPipe();
+ transport.buildReceiverPipe(this);
+ this.securityLayer = transport.getSecurityLayer();
+
send(new ProtocolHeader(1, 0, 10));
Waiter w = new Waiter(lock, timeout);
@@ -633,5 +642,10 @@ public class Connection extends ConnectionInvoker
{
return conSettings;
}
+
+ public SecurityLayer getSecurityLayer()
+ {
+ return securityLayer;
+ }
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
index c063ef5e6f..08678b213b 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
@@ -22,6 +22,12 @@ package org.apache.qpid.transport;
import java.util.Map;
+/**
+ * A ConnectionSettings object can only be associated with
+ * one Connection object. I have added an assertion that will
+ * throw an exception if it is used by more than on Connection
+ *
+ */
public class ConnectionSettings
{
String protocol = "tcp";
@@ -29,18 +35,34 @@ public class ConnectionSettings
String vhost;
String username = "guest";
String password = "guest";
- String saslMechs = "PLAIN";
- String saslProtocol = "AMQP";
- String saslServerName = "localhost";
int port = 5672;
+ boolean tcpNodelay = Boolean.getBoolean("amqj.tcp_nodelay");
int maxChannelCount = 32767;
int maxFrameSize = 65535;
int heartbeatInterval;
+ int readBufferSize = 65535;
+ int writeBufferSize = 65535;
+ long transportTimeout = 60000;
+
+ // SSL props
boolean useSSL;
+ String keyStorePath = System.getProperty("javax.net.ssl.keyStore");
+ String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
+ String keyStoreCertType = System.getProperty("qpid.ssl.keyStoreCertType","SunX509");;
+ String trustStoreCertType = System.getProperty("qpid.ssl.trustStoreCertType","SunX509");;
+ String trustStorePath = System.getProperty("javax.net.ssl.trustStore");;
+ String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");;
+ String certAlias;
+ boolean verifyHostname;
+
+ // SASL props
+ String saslMechs = System.getProperty("qpid.sasl_mechs", "PLAIN");
+ String saslProtocol = System.getProperty("qpid.sasl_protocol", "AMQP");
+ String saslServerName = System.getProperty("qpid.sasl_server_name", "localhost");
boolean useSASLEncryption;
- boolean tcpNodelay;
+
private Map<String, Object> _clientProperties;
-
+
public boolean isTcpNodelay()
{
return tcpNodelay;
@@ -200,4 +222,115 @@ public class ConnectionSettings
{
return _clientProperties;
}
+
+ public String getKeyStorePath()
+ {
+ return keyStorePath;
+ }
+
+ public void setKeyStorePath(String keyStorePath)
+ {
+ this.keyStorePath = keyStorePath;
+ }
+
+ public String getKeyStorePassword()
+ {
+ return keyStorePassword;
+ }
+
+ public void setKeyStorePassword(String keyStorePassword)
+ {
+ this.keyStorePassword = keyStorePassword;
+ }
+
+ public String getTrustStorePath()
+ {
+ return trustStorePath;
+ }
+
+ public void setTrustStorePath(String trustStorePath)
+ {
+ this.trustStorePath = trustStorePath;
+ }
+
+ public String getTrustStorePassword()
+ {
+ return trustStorePassword;
+ }
+
+ public void setTrustStorePassword(String trustStorePassword)
+ {
+ this.trustStorePassword = trustStorePassword;
+ }
+
+ public String getCertAlias()
+ {
+ return certAlias;
+ }
+
+ public void setCertAlias(String certAlias)
+ {
+ this.certAlias = certAlias;
+ }
+
+ public boolean isVerifyHostname()
+ {
+ return verifyHostname;
+ }
+
+ public void setVerifyHostname(boolean verifyHostname)
+ {
+ this.verifyHostname = verifyHostname;
+ }
+
+ public String getKeyStoreCertType()
+ {
+ return keyStoreCertType;
+ }
+
+ public void setKeyStoreCertType(String keyStoreCertType)
+ {
+ this.keyStoreCertType = keyStoreCertType;
+ }
+
+ public String getTrustStoreCertType()
+ {
+ return trustStoreCertType;
+ }
+
+ public void setTrustStoreCertType(String trustStoreCertType)
+ {
+ this.trustStoreCertType = trustStoreCertType;
+ }
+
+ public int getReadBufferSize()
+ {
+ return readBufferSize;
+ }
+
+ public void setReadBufferSize(int readBufferSize)
+ {
+ this.readBufferSize = readBufferSize;
+ }
+
+ public int getWriteBufferSize()
+ {
+ return writeBufferSize;
+ }
+
+ public void setWriteBufferSize(int writeBufferSize)
+ {
+ this.writeBufferSize = writeBufferSize;
+ }
+
+ public long getTransportTimeout()
+ {
+ return transportTimeout;
+ }
+
+ public void setTransportTimeout(long transportTimeout)
+ {
+ this.transportTimeout = transportTimeout;
+ }
+
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java
new file mode 100644
index 0000000000..d1ae95a3bb
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transport;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.network.Assembler;
+import org.apache.qpid.transport.network.Disassembler;
+import org.apache.qpid.transport.network.InputHandler;
+import org.apache.qpid.transport.network.NetworkTransport;
+import org.apache.qpid.transport.network.Transport;
+import org.apache.qpid.transport.network.security.SecurityLayer;
+
+public class TransportBuilder
+{
+ private Connection con;
+ private ConnectionSettings settings;
+ private NetworkTransport transport;
+ private SecurityLayer securityLayer = new SecurityLayer();
+
+ public void init(Connection con) throws TransportException
+ {
+ this.con = con;
+ this.settings = con.getConnectionSettings();
+ transport = Transport.getTransport();
+ transport.init(settings);
+ securityLayer.init(con);
+ }
+
+ public Sender<ProtocolEvent> buildSenderPipe()
+ {
+ ConnectionSettings settings = con.getConnectionSettings();
+
+ // Io layer
+ Sender<ByteBuffer> sender = transport.sender();
+
+ // Security layer
+ sender = securityLayer.sender(sender);
+
+ Disassembler dis = new Disassembler(sender, settings.getMaxFrameSize());
+ return dis;
+ }
+
+ public void buildReceiverPipe(Receiver<ProtocolEvent> delegate)
+ {
+ ConnectionSettings settings = con.getConnectionSettings();
+
+ Receiver<ByteBuffer> receiver = new InputHandler(new Assembler(delegate));
+
+ // Security layer
+ receiver = securityLayer.receiver(receiver);
+
+ //Io layer
+ transport.receiver(receiver);
+ }
+
+ public SecurityLayer getSecurityLayer()
+ {
+ return securityLayer;
+ }
+
+} \ No newline at end of file
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java
new file mode 100644
index 0000000000..5e12d7e7c6
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.network;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.ConnectionSettings;
+
+public interface NetworkTransport
+{
+ public void init(ConnectionSettings settings);
+
+ public Sender<ByteBuffer> sender();
+
+ public void receiver(Receiver<ByteBuffer> delegate);
+
+ public void close();
+} \ No newline at end of file
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java
new file mode 100644
index 0000000000..f0bf04d04f
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java
@@ -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.
+ *
+ */
+
+package org.apache.qpid.transport.network;
+
+import org.apache.qpid.transport.TransportException;
+
+public class Transport
+{
+ private final static Class<?> transportClass;
+
+ static
+ {
+ try
+ {
+ transportClass =
+ Class.forName(System.getProperty("qpid.transport",
+ "org.apache.qpid.transport.network.io.IoNetworkTransport"));
+
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error occured while loading Qpid Transport",e);
+ }
+ }
+
+ public static NetworkTransport getTransport() throws TransportException
+ {
+ try
+ {
+ return (NetworkTransport)transportClass.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error while creating a new transport instance",e);
+ }
+ }
+} \ No newline at end of file
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java
new file mode 100644
index 0000000000..72520c64ef
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java
@@ -0,0 +1,15 @@
+package org.apache.qpid.transport.network.io;
+
+import java.net.Socket;
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.Sender;
+
+public interface IoContext
+{
+ Sender<ByteBuffer> getSender();
+
+ IoReceiver getReceiver();
+
+ Socket getSocket();
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
new file mode 100644
index 0000000000..4e6d2130ae
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -0,0 +1,120 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transport.network.io;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.ConnectionSettings;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.network.NetworkTransport;
+import org.apache.qpid.transport.util.Logger;
+
+public class IoNetworkTransport implements NetworkTransport, IoContext
+{
+ static
+ {
+ org.apache.mina.common.ByteBuffer.setAllocator
+ (new org.apache.mina.common.SimpleByteBufferAllocator());
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers
+ (Boolean.getBoolean("amqj.enableDirectBuffers"));
+ }
+
+ private static final Logger log = Logger.get(IoNetworkTransport.class);
+
+ private Socket socket;
+ private Sender<ByteBuffer> sender;
+ private IoReceiver receiver;
+ private long timeout = 60000;
+ private ConnectionSettings settings;
+
+ @Override
+ public void init(ConnectionSettings settings)
+ {
+ try
+ {
+ this.settings = settings;
+ InetAddress address = InetAddress.getByName(settings.getHost());
+ socket = new Socket();
+ socket.setReuseAddress(true);
+ socket.setTcpNoDelay(settings.isTcpNodelay());
+
+ log.debug("default-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("default-SO_SNDBUF : %s", socket.getSendBufferSize());
+
+ socket.setSendBufferSize(settings.getWriteBufferSize());
+ socket.setReceiveBufferSize(settings.getReadBufferSize());
+
+ log.debug("new-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("new-SO_SNDBUF : %s", socket.getSendBufferSize());
+
+ socket.connect(new InetSocketAddress(address, settings.getPort()));
+ }
+ catch (SocketException e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ catch (IOException e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ }
+
+ @Override
+ public void receiver(Receiver<ByteBuffer> delegate)
+ {
+ receiver = new IoReceiver(this, delegate,
+ 2*settings.getReadBufferSize() , timeout);
+ }
+
+ @Override
+ public Sender<ByteBuffer> sender()
+ {
+ return new IoSender(this, 2*settings.getWriteBufferSize(), timeout);
+ }
+
+ @Override
+ public void close()
+ {
+
+ }
+
+ public Sender<ByteBuffer> getSender()
+ {
+ return sender;
+ }
+
+ public IoReceiver getReceiver()
+ {
+ return receiver;
+ }
+
+ public Socket getSocket()
+ {
+ return socket;
+ }
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
index e0e06d22ec..19a683d505 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
@@ -42,7 +42,7 @@ final class IoReceiver implements Runnable
private static final Logger log = Logger.get(IoReceiver.class);
- private final IoTransport transport;
+ private final IoContext ioCtx;
private final Receiver<ByteBuffer> receiver;
private final int bufferSize;
private final Socket socket;
@@ -52,13 +52,13 @@ final class IoReceiver implements Runnable
private final boolean shutdownBroken =
((String) System.getProperties().get("os.name")).matches("(?i).*windows.*");
- public IoReceiver(IoTransport transport, Receiver<ByteBuffer> receiver,
+ public IoReceiver(IoContext ioCtx, Receiver<ByteBuffer> receiver,
int bufferSize, long timeout)
{
- this.transport = transport;
+ this.ioCtx = ioCtx;
this.receiver = receiver;
this.bufferSize = bufferSize;
- this.socket = transport.getSocket();
+ this.socket = ioCtx.getSocket();
this.timeout = timeout;
try
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
index 383fd6131a..66b97e8225 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
@@ -43,7 +43,7 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
// we can test other cases as well
private final static int START = Integer.MAX_VALUE - 10;
- private final IoTransport transport;
+ private final IoContext ioCtx;
private final long timeout;
private final Socket socket;
private final OutputStream out;
@@ -60,10 +60,10 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
private volatile Throwable exception = null;
- public IoSender(IoTransport transport, int bufferSize, long timeout)
+ public IoSender(IoContext ioCtx, int bufferSize, long timeout)
{
- this.transport = transport;
- this.socket = transport.getSocket();
+ this.ioCtx = ioCtx;
+ this.socket = ioCtx.getSocket();
this.buffer = new byte[pof2(bufferSize)]; // buffer size must be a power of 2
this.timeout = timeout;
@@ -207,7 +207,7 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
throw new SenderException("join timed out");
}
}
- transport.getReceiver().close(false);
+ ioCtx.getReceiver().close(false);
}
catch (InterruptedException e)
{
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
index b648ba4858..bfdbb34978 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
@@ -38,8 +38,8 @@ import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.network.ssl.SSLReceiver;
-import org.apache.qpid.transport.network.ssl.SSLSender;
+import org.apache.qpid.transport.network.security.ssl.SSLReceiver;
+import org.apache.qpid.transport.network.security.ssl.SSLSender;
import org.apache.qpid.transport.util.Logger;
/**
@@ -51,7 +51,7 @@ import org.apache.qpid.transport.util.Logger;
* SO_RCVBUF - amqj.receiveBufferSize
* SO_SNDBUF - amqj.sendBufferSize
*/
-public final class IoTransport<E>
+public final class IoTransport<E> implements IoContext
{
static
@@ -119,17 +119,17 @@ public final class IoTransport<E>
}
}
- Sender<ByteBuffer> getSender()
+ public Sender<ByteBuffer> getSender()
{
return sender;
}
- IoReceiver getReceiver()
+ public IoReceiver getReceiver()
{
return receiver;
}
- Socket getSocket()
+ public Socket getSocket()
{
return socket;
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java
new file mode 100644
index 0000000000..3f0966903d
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java
@@ -0,0 +1,185 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transport.network.security;
+
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionListener;
+import org.apache.qpid.transport.ConnectionSettings;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.network.security.sasl.SASLReceiver;
+import org.apache.qpid.transport.network.security.sasl.SASLSender;
+import org.apache.qpid.transport.network.security.ssl.SSLReceiver;
+import org.apache.qpid.transport.network.security.ssl.SSLSender;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
+
+public class SecurityLayer
+{
+ ConnectionSettings settings;
+ Connection con;
+ SSLSecurityLayer sslLayer;
+ SASLSecurityLayer saslLayer;
+
+ public void init(Connection con) throws TransportException
+ {
+ this.con = con;
+ this.settings = con.getConnectionSettings();
+ if (settings.isUseSSL())
+ {
+ sslLayer = new SSLSecurityLayer();
+ }
+ if (settings.isUseSASLEncryption())
+ {
+ saslLayer = new SASLSecurityLayer();
+ }
+
+ }
+
+ public Sender<ByteBuffer> sender(Sender<ByteBuffer> delegate)
+ {
+ Sender<ByteBuffer> sender = delegate;
+
+ if (settings.isUseSSL())
+ {
+ sender = sslLayer.sender(sender);
+ }
+
+ if (settings.isUseSASLEncryption())
+ {
+ sender = saslLayer.sender(sender);
+ }
+
+ return sender;
+ }
+
+ public Receiver<ByteBuffer> receiver(Receiver<ByteBuffer> delegate)
+ {
+ Receiver<ByteBuffer> receiver = delegate;
+
+ if (settings.isUseSSL())
+ {
+ receiver = sslLayer.receiver(receiver);
+ }
+
+ if (settings.isUseSASLEncryption())
+ {
+ receiver = saslLayer.receiver(receiver);
+ }
+
+ return receiver;
+ }
+
+ public String getUserID()
+ {
+ if (settings.isUseSSL())
+ {
+ return sslLayer.getUserID();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ class SSLSecurityLayer
+ {
+ SSLEngine engine;
+ SSLSender sender;
+
+ public SSLSecurityLayer()
+ {
+ SSLContext sslCtx;
+ try
+ {
+ sslCtx = SSLUtil.createSSLContext(settings);
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error creating SSL Context", e);
+ }
+
+ try
+ {
+ engine = sslCtx.createSSLEngine();
+ engine.setUseClientMode(true);
+ }
+ catch(Exception e)
+ {
+ throw new TransportException("Error creating SSL Engine", e);
+ }
+ }
+
+ public SSLSender sender(Sender<ByteBuffer> delegate)
+ {
+ sender = new SSLSender(engine,delegate);
+ sender.setConnectionSettings(settings);
+ return sender;
+ }
+
+ public SSLReceiver receiver(Receiver<ByteBuffer> delegate)
+ {
+ if (sender == null)
+ {
+ throw new
+ IllegalStateException("SecurityLayer.sender method should be " +
+ "invoked before SecurityLayer.receiver");
+ }
+
+ SSLReceiver receiver = new SSLReceiver(engine,delegate,sender);
+ receiver.setConnectionSettings(settings);
+ return receiver;
+ }
+
+ public String getUserID()
+ {
+ return SSLUtil.retriveIdentity(engine);
+ }
+
+ }
+
+ class SASLSecurityLayer
+ {
+ public SASLSecurityLayer()
+ {
+ }
+
+ public SASLSender sender(Sender<ByteBuffer> delegate)
+ {
+ SASLSender sender = new SASLSender(delegate);
+ con.addConnectionListener((ConnectionListener)sender);
+ return sender;
+ }
+
+ public SASLReceiver receiver(Receiver<ByteBuffer> delegate)
+ {
+ SASLReceiver receiver = new SASLReceiver(delegate);
+ con.addConnectionListener((ConnectionListener)receiver);
+ return receiver;
+ }
+
+ }
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
new file mode 100644
index 0000000000..2a3aba9a95
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
@@ -0,0 +1,80 @@
+package org.apache.qpid.transport.network.security.ssl;
+
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+
+import org.apache.qpid.transport.util.Logger;
+
+public class QpidClientX509KeyManager extends X509ExtendedKeyManager
+{
+ private static final Logger log = Logger.get(QpidClientX509KeyManager.class);
+
+ X509ExtendedKeyManager delegate;
+ String alias;
+
+ public QpidClientX509KeyManager(String alias, String keyStorePath,
+ String keyStorePassword,String keyStoreCertType) throws Exception
+ {
+ this.alias = alias;
+ KeyStore ks = SSLUtil.getInitializedKeyStore(keyStorePath,keyStorePassword);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreCertType);
+ kmf.init(ks, keyStorePassword.toCharArray());
+ this.delegate = (X509ExtendedKeyManager)kmf.getKeyManagers()[0];
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
+ {
+ log.debug("chooseClientAlias:Returning alias " + alias);
+ return alias;
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
+ {
+ return delegate.chooseServerAlias(keyType, issuers, socket);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias)
+ {
+ return delegate.getCertificateChain(alias);
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers)
+ {
+ log.debug("getClientAliases:Returning alias " + alias);
+ return new String[]{alias};
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias)
+ {
+ return delegate.getPrivateKey(alias);
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers)
+ {
+ return delegate.getServerAliases(keyType, issuers);
+ }
+
+ public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
+ {
+ log.debug("chooseEngineClientAlias:Returning alias " + alias);
+ return alias;
+ }
+
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
+ {
+ return delegate.chooseEngineServerAlias(keyType, issuers, engine);
+ }
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java
index e6e6c5f791..082ae9e8ec 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java
@@ -18,7 +18,7 @@
* under the License.
*
*/
-package org.apache.qpid.transport.network.ssl;
+package org.apache.qpid.transport.network.security.ssl;
import java.nio.ByteBuffer;
@@ -28,6 +28,7 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
+import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
@@ -42,7 +43,8 @@ public class SSLReceiver implements Receiver<ByteBuffer>
private ByteBuffer localBuffer;
private boolean dataCached = false;
private final Object notificationToken;
-
+ private ConnectionSettings settings;
+
private static final Logger log = Logger.get(SSLReceiver.class);
public SSLReceiver(SSLEngine engine, Receiver<ByteBuffer> delegate,SSLSender sender)
@@ -56,6 +58,11 @@ public class SSLReceiver implements Receiver<ByteBuffer>
notificationToken = sender.getNotificationToken();
}
+ public void setConnectionSettings(ConnectionSettings settings)
+ {
+ this.settings = settings;
+ }
+
public void closed()
{
delegate.closed();
@@ -159,8 +166,13 @@ public class SSLReceiver implements Receiver<ByteBuffer>
sender.doTasks();
handshakeStatus = engine.getHandshakeStatus();
- case NEED_WRAP:
case FINISHED:
+ if (this.settings != null && this.settings.isVerifyHostname() )
+ {
+ SSLUtil.verifyHostname(engine, this.settings.getHost());
+ }
+
+ case NEED_WRAP:
case NOT_HANDSHAKING:
synchronized(notificationToken)
{
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java
index bd5662a5fb..24cedcc75a 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java
@@ -17,7 +17,7 @@
* under the License.
*
*/
-package org.apache.qpid.transport.network.ssl;
+package org.apache.qpid.transport.network.security.ssl;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -28,6 +28,7 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
+import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.SenderException;
import org.apache.qpid.transport.util.Logger;
@@ -39,7 +40,8 @@ public class SSLSender implements Sender<ByteBuffer>
private int sslBufSize;
private ByteBuffer netData;
private long timeout = 30000;
-
+ private ConnectionSettings settings;
+
private final Object engineState = new Object();
private final AtomicBoolean closed = new AtomicBoolean(false);
@@ -53,6 +55,11 @@ public class SSLSender implements Sender<ByteBuffer>
netData = ByteBuffer.allocate(sslBufSize);
timeout = Long.getLong("qpid.ssl_timeout", 60000);
}
+
+ public void setConnectionSettings(ConnectionSettings settings)
+ {
+ this.settings = settings;
+ }
public void close()
{
@@ -225,6 +232,11 @@ public class SSLSender implements Sender<ByteBuffer>
break;
case FINISHED:
+ if (this.settings != null && this.settings.isVerifyHostname() )
+ {
+ SSLUtil.verifyHostname(engine, this.settings.getHost());
+ }
+
case NOT_HANDSHAKING:
break; //do nothing
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
new file mode 100644
index 0000000000..6c5c56a175
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
@@ -0,0 +1,177 @@
+package org.apache.qpid.transport.network.security.ssl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLPeerUnverifiedException;
+
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.ConnectionSettings;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.util.Logger;
+
+public class SSLUtil
+{
+ private static final Logger log = Logger.get(SSLUtil.class);
+
+ public static void verifyHostname(SSLEngine engine,String hostnameExpected)
+ {
+ try
+ {
+ Certificate cert = engine.getSession().getPeerCertificates()[0];
+ Principal p = ((X509Certificate)cert).getSubjectDN();
+ String dn = p.getName();
+ String hostname = null;
+
+ if (dn.contains("CN="))
+ {
+ hostname = dn.substring(3,
+ dn.indexOf(",") == -1? dn.length(): dn.indexOf(","));
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("Hostname expected : " + hostnameExpected);
+ log.debug("Distinguished Name for server certificate : " + dn);
+ log.debug("Host Name obtained from DN : " + hostname);
+ }
+
+ if (hostname != null && !(hostname.equalsIgnoreCase(hostnameExpected) ||
+ hostname.equalsIgnoreCase(hostnameExpected + ".localdomain")))
+ {
+ throw new TransportException("SSL hostname verification failed." +
+ " Expected : " + hostnameExpected +
+ " Found in cert : " + hostname);
+ }
+
+ }
+ catch(SSLPeerUnverifiedException e)
+ {
+ log.warn("Exception received while trying to verify hostname",e);
+ // For some reason the SSL engine sets the handshake status to FINISH twice
+ // in succession. The first time the peer certificate
+ // info is not available. The second time it works !
+ // Therefore have no choice but to ignore the exception here.
+ }
+ }
+
+ public static String retriveIdentity(SSLEngine engine)
+ {
+ StringBuffer id = new StringBuffer();
+ try
+ {
+ Certificate cert = engine.getSession().getLocalCertificates()[0];
+ Principal p = ((X509Certificate)cert).getSubjectDN();
+ String dn = p.getName();
+
+ if (dn.contains("CN="))
+ {
+ id.append(dn.substring(3,
+ dn.indexOf(",") == -1? dn.length(): dn.indexOf(",")));
+ }
+
+ if (dn.contains("DC="))
+ {
+ id.append("@");
+ int c = 0;
+ for (String toks : dn.split(","))
+ {
+ if (toks.contains("DC"))
+ {
+ if (c > 0) {id.append(".");}
+ id.append(toks.substring(
+ toks.indexOf("=")+1,
+ toks.indexOf(",") == -1? toks.length(): toks.indexOf(",")));
+ c++;
+ }
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ log.info("Exception received while trying to retrive client identity from SSL cert",e);
+ }
+
+ log.debug("Extracted Identity from client certificate : " + id);
+ return id.toString();
+ }
+
+ public static SSLContext createSSLContext(ConnectionSettings settings) throws Exception
+ {
+ SSLContextFactory sslContextFactory;
+
+ if (settings.getCertAlias() == null)
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType());
+
+ } else
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ new QpidClientX509KeyManager(settings.getCertAlias(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType()));
+
+ log.debug("Using custom key manager");
+ }
+
+ return sslContextFactory.buildServerContext();
+
+ }
+
+ public static KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
+ {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ InputStream in = null;
+ try
+ {
+ File f = new File(storePath);
+ if (f.exists())
+ {
+ in = new FileInputStream(f);
+ }
+ else
+ {
+ in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
+ }
+ if (in == null)
+ {
+ throw new IOException("Unable to load keystore resource: " + storePath);
+ }
+ ks.load(in, storePassword.toCharArray());
+ }
+ finally
+ {
+ if (in != null)
+ {
+ //noinspection EmptyCatchBlock
+ try
+ {
+ in.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ }
+ return ks;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
new file mode 100644
index 0000000000..74326c02ec
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
@@ -0,0 +1,161 @@
+package org.apache.qpid.client.ssl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTestConnection_0_10;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.Connection;
+
+public class SSLTest extends QpidTestCase
+{
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ System.setProperty("javax.net.debug", "ssl");
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ System.setProperty("javax.net.debug", "");
+ super.tearDown();
+ }
+
+ public void testCreateSSLContextFromConnectionURLParams()
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" +
+ "?ssl='true'&ssl_verify_hostname='true'" +
+ "&key_store='%s'&key_store_password='%s'" +
+ "&trust_store='%s'&trust_store_password='%s'" +
+ "'";
+
+ String keyStore = System.getProperty("javax.net.ssl.keyStore");
+ String keyStorePass = System.getProperty("javax.net.ssl.keyStorePassword");
+ String trustStore = System.getProperty("javax.net.ssl.trustStore");
+ String trustStorePass = System.getProperty("javax.net.ssl.trustStorePassword");
+
+ url = String.format(url,System.getProperty("test.port.ssl"),
+ keyStore,keyStorePass,trustStore,trustStorePass);
+
+ // temporarily set the trust/key store jvm args to something else
+ // to ensure we only read from the connection URL param.
+ System.setProperty("javax.net.ssl.trustStore","fessgsdgd");
+ System.setProperty("javax.net.ssl.trustStorePassword","fessgsdgd");
+ System.setProperty("javax.net.ssl.keyStore","fessgsdgd");
+ System.setProperty("javax.net.ssl.keyStorePassword","fessgsdgd");
+ try
+ {
+ AMQConnection con = new AMQConnection(url);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ }
+ catch (Exception e)
+ {
+ fail("SSL Connection should be successful");
+ }
+ finally
+ {
+ System.setProperty("javax.net.ssl.trustStore",trustStore);
+ System.setProperty("javax.net.ssl.trustStorePassword",trustStorePass);
+ System.setProperty("javax.net.ssl.keyStore",keyStore);
+ System.setProperty("javax.net.ssl.keyStorePassword",keyStorePass);
+ }
+ }
+ }
+
+ public void testMultipleCertsInSingleStore() throws Exception
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_cert_alias='app1''";
+
+ AMQTestConnection_0_10 con = new AMQTestConnection_0_10(url);
+ Connection transportCon = con.getConnection();
+ String userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app1@acme.org",userID);
+ con.close();
+
+ url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_cert_alias='app2''";
+
+ con = new AMQTestConnection_0_10(url);
+ transportCon = con.getConnection();
+ userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app2@acme.org",userID);
+ con.close();
+ }
+ }
+
+ public void testVerifyHostName()
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_verify_hostname='true''";
+
+ try
+ {
+ AMQConnection con = new AMQConnection(url);
+ fail("Hostname verification failed. No exception was thrown");
+ }
+ catch (Exception e)
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ e.printStackTrace(new PrintStream(bout));
+ String strace = bout.toString();
+ assertTrue("Correct exception not thrown",strace.contains("SSL hostname verification failed"));
+ }
+
+ }
+ }
+
+ public void testVerifyLocalHost()
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_verify_hostname='true''";
+
+ try
+ {
+ AMQConnection con = new AMQConnection(url);
+ }
+ catch (Exception e)
+ {
+ fail("Hostname verification should succeed");
+ }
+ }
+ }
+
+ public void testVerifyLocalHostLocalDomain()
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost.localdomain:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_verify_hostname='true''";
+
+ try
+ {
+ AMQConnection con = new AMQConnection(url);
+ }
+ catch (Exception e)
+ {
+ fail("Hostname verification should succeed");
+ }
+
+ }
+ }
+}
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 aeddfd00fe..732a28553c 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
@@ -77,7 +77,7 @@ public class AddressBasedDestinationTest extends QpidTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getMessage().contains("The name 'testQueue1' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
@@ -140,7 +140,7 @@ public class AddressBasedDestinationTest extends QpidTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
@@ -150,7 +150,7 @@ public class AddressBasedDestinationTest extends QpidTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
@@ -167,7 +167,7 @@ public class AddressBasedDestinationTest extends QpidTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
assertFalse("Queue should not be created",(
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
index 91bb5d2529..cafd212dd3 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
@@ -334,6 +334,7 @@ public class DurableSubscriptionTest extends QpidTestCase
{
_logger.info("Receive message on consumer 3 :expecting B");
msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull(msg);
assertEquals("B", ((TextMessage) msg).getText());
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
index 1e5932b6db..47705f8105 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
@@ -339,7 +339,7 @@ public class FaultTest extends AbstractXATestCase
{
assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode);
}
- }
+ }
/**
* Strategy:
@@ -355,7 +355,7 @@ public class FaultTest extends AbstractXATestCase
_xaResource.end(xid, XAResource.TMSUCCESS);
xid = getNewXid();
_xaResource.start(xid, XAResource.TMNOFLAGS);
- assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 0);
+ assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 1000);
}
/**
@@ -381,5 +381,29 @@ public class FaultTest extends AbstractXATestCase
assertEquals("Wrong error code: ", XAException.XA_RBTIMEOUT, e.errorCode);
}
}
+
+ /**
+ * Strategy:
+ * Set the transaction timeout to 1000
+ */
+ public void testTransactionTimeoutAfterCommit() throws Exception
+ {
+ Xid xid = getNewXid();
+
+ _xaResource.start(xid, XAResource.TMNOFLAGS);
+ _xaResource.setTransactionTimeout(1000);
+ assertEquals("Wrong timeout", 1000,_xaResource.getTransactionTimeout());
+
+ //_xaResource.prepare(xid);
+ _xaResource.end(xid, XAResource.TMSUCCESS);
+ _xaResource.commit(xid, true);
+
+ _xaResource.setTransactionTimeout(2000);
+ assertEquals("Wrong timeout", 2000,_xaResource.getTransactionTimeout());
+
+ xid = getNewXid();
+ _xaResource.start(xid, XAResource.TMNOFLAGS);
+ assertEquals("Wrong timeout", 2000, _xaResource.getTransactionTimeout());
+ }
}
diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes
index ec3649fe98..d38e895ee9 100755
--- a/qpid/java/test-profiles/CPPExcludes
+++ b/qpid/java/test-profiles/CPPExcludes
@@ -56,10 +56,13 @@ org.apache.qpid.test.client.timeouts.SyncWaitDelayTest#*
// QPID-1262, QPID-1119 : This test fails occasionally due to potential protocol issue.
org.apache.qpid.test.client.timeouts.SyncWaitTimeoutDelayTest#*
-// c++ broker doesn't support priorities, TTL or message bouncing
+// c++ broker doesn't support priorities, message bouncing
org.apache.qpid.server.exchange.ReturnUnroutableMandatoryMessageTest#*
org.apache.qpid.server.queue.PriorityTest#*
+
+// c++ broker expires messages on delivery or when the queue cleaner thread runs.
org.apache.qpid.server.queue.TimeToLiveTest#testActiveTTL
+org.apache.qpid.server.queue.TimeToLiveTest#testActiveTTLwithDurableSubscription
// QPID-1727 , QPID-1726 :c++ broker does not support flow to disk on transient queues. Also it requries a persistent store impl. for Apache
org.apache.qpid.test.client.QueueBrowsingFlowToDiskTest#*
diff --git a/qpid/java/test-profiles/test_resources/ssl/CA_db/cert8.db b/qpid/java/test-profiles/test_resources/ssl/CA_db/cert8.db
new file mode 100644
index 0000000000..846e59e82d
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/CA_db/cert8.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/CA_db/key3.db b/qpid/java/test-profiles/test_resources/ssl/CA_db/key3.db
new file mode 100644
index 0000000000..dd60e1e05e
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/CA_db/key3.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/CA_db/rootca.crt b/qpid/java/test-profiles/test_resources/ssl/CA_db/rootca.crt
new file mode 100644
index 0000000000..d9cdd9891c
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/CA_db/rootca.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICDDCCAXWgAwIBAgIFAJBNP3QwDQYJKoZIhvcNAQEFBQAwQTELMAkGA1UEBhMC
+Q0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxETAPBgNVBAMTCE15
+Um9vdENBMB4XDTEwMDMyMjIxMDAyMloXDTE1MDMyMjIxMDAyMlowQTELMAkGA1UE
+BhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxETAPBgNVBAMT
+CE15Um9vdENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDICe+SkXU9NRCk
+s+Tmai/j+3uDfJ4mVEt4PRkRWTVVHvuMvbPfKhdBRYRM5wmQmSCOi25Xd9jnh3PF
+BwE+pfaSgVqQiilUYqYak56ZR1Ll0nGwyXZQnW3lTf9VboEl0p67qckcd8SmaJf2
+0lAlTu2W7kJ8whYYyYRqaw+3yA6dGQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4GBADUbCNoxvFbPv+vqfQJ59p8P0cArEPajHR51omE1BbLc
+TfouOIidiBORf1n8DzE7k2Pf//nUHWhJLBP7J7CMs18UYsDD+0aa9A3BZi4wcsYX
+AW9EiXAIhnCk2+yyZyI1gdOnRS/9aOBRFSa1ngCb9GLm4kFzakiDQ1iX7k9dk17p
+-----END CERTIFICATE-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/CA_db/secmod.db b/qpid/java/test-profiles/test_resources/ssl/CA_db/secmod.db
new file mode 100644
index 0000000000..a13e3e602c
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/CA_db/secmod.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/app1.crt b/qpid/java/test-profiles/test_resources/ssl/app1.crt
new file mode 100644
index 0000000000..1f67a0d152
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/app1.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIFAJBNWvMwDQYJKoZIhvcNAQEFBQAwQTELMAkGA1UEBhMC
+Q0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxETAPBgNVBAMTCE15
+Um9vdENBMB4XDTEwMDMyMjIyMDE0MloXDTEwMDYyMjIyMDE0MlowbTEPMA0GA1UE
+BhMGQ2FuYWRhMQswCQYDVQQIEwJPTjEQMA4GA1UEBxMHVG9yb250bzERMA8GA1UE
+ChMIYWNtZS5vcmcxEDAOBgNVBAsTB1Vua25vd24xFjAUBgNVBAMMDWFwcDFAYWNt
+ZS5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKPmoysNdOgH/XMircR7
+aQxWKqe3tzwREdHdLUmWqanlyfL7zi9P6P3CyMQQsKpM6FkQQlZ+WpE9IIAqP+g1
+3zbFtqdqhfQwsEovcFOLAdDfm6W5YSPN7dPEgf6+DEtTb/9fxWqdtEiXc+PhRd+9
+Inzo2C33gqDjFcA2LcM37zgPAgMBAAGjIjAgMAkGA1UdEwQCMAAwEwYDVR0lBAww
+CgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAs4IQUMJOlAEG7OVLoazgn8ea
+qOPFZ/Y8CYK0yoVZ+QF3aIFx5plj9Rol9Cf96eL6Ta/ff/fvFzUCGceY1TriHxqv
+9/8IR9LdmOaCC3Er2hRjuPumuwimpNGQqsrONPfBrhHVuQXOJYOWRYwuLEG3bQR5
+tP8zTMkBo3/FrX6nZks=
+-----END CERTIFICATE-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/app1.req b/qpid/java/test-profiles/test_resources/ssl/app1.req
new file mode 100644
index 0000000000..b1889d15e1
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/app1.req
@@ -0,0 +1,10 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIIBrTCCARYCAQAwbTEPMA0GA1UEBhMGQ2FuYWRhMQswCQYDVQQIEwJPTjEQMA4GA1UEBxMHVG9y
+b250bzERMA8GA1UEChMIYWNtZS5vcmcxEDAOBgNVBAsTB1Vua25vd24xFjAUBgNVBAMMDWFwcDFA
+YWNtZS5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKPmoysNdOgH/XMircR7aQxWKqe3
+tzwREdHdLUmWqanlyfL7zi9P6P3CyMQQsKpM6FkQQlZ+WpE9IIAqP+g13zbFtqdqhfQwsEovcFOL
+AdDfm6W5YSPN7dPEgf6+DEtTb/9fxWqdtEiXc+PhRd+9Inzo2C33gqDjFcA2LcM37zgPAgMBAAGg
+ADANBgkqhkiG9w0BAQQFAAOBgQBnPCA6n+5y1azadoDcmttFJP6P+jfqp069UIi8zhuIVccJXYkL
+pmp9kWolbvj5niVyFTcMnlH7uKMCoUP8sTdCfoSFr3BgkfCV8Wb/P2vl5J/BVCwSt0Uhsue95aAn
+8A0tCdyTRWRnLeCmFJ/OiG6vbsBtbjXTxQIJsLr6hLcMKg==
+-----END NEW CERTIFICATE REQUEST-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/app2.crt b/qpid/java/test-profiles/test_resources/ssl/app2.crt
new file mode 100644
index 0000000000..ec4d40f0ce
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/app2.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICRzCCAbCgAwIBAgIFAJBNWx4wDQYJKoZIhvcNAQEFBQAwQTELMAkGA1UEBhMC
+Q0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxETAPBgNVBAMTCE15
+Um9vdENBMB4XDTEwMDMyMjIyMDIwNFoXDTEwMDYyMjIyMDIwNFowajELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9yZDERMA8GA1UEChMI
+YWNtZS5vcmcxEDAOBgNVBAsTB1Vua25vd24xFjAUBgNVBAMMDWFwcDJAYWNtZS5v
+cmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ9hkHkiTpwQ0cViMyfs9PgU
+5wZRTo2OGHxmw+EBlOvLBPamZ0zF2Rnqc/BRTCkoGQIF0nTFFyALsCxnmyZyje00
+ht0zOtc91aQl5W/c1ShEt7YlcSkDNDVxzouG1Nf7VZSbVbRtUkhhRRqAw84IV0GA
+1kRmZ8oEkvdeBULOYncrAgMBAAGjIjAgMAkGA1UdEwQCMAAwEwYDVR0lBAwwCgYI
+KwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAWFNqhydLqg6SXo9IrOwSxAw3zNoz
+sX4ARdMP1LdqLmpiZ1Qr5C54o19bR7UJfyzsYMuXDg6wy/l0JTcs62qDwD6IdEg1
+ZPkAfoVw4eiCorjM02fFTAvPX6jyYJ/3oQI1POoxhdqhll70WSSaKoSooJFcOG74
+xpacadqA8A0ICAc=
+-----END CERTIFICATE-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/app2.req b/qpid/java/test-profiles/test_resources/ssl/app2.req
new file mode 100644
index 0000000000..7e5282d8b5
--- /dev/null
+++ b/qpid/java/test-profiles/test_resources/ssl/app2.req
@@ -0,0 +1,10 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIIBqjCCARMCAQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y
+ZDERMA8GA1UEChMIYWNtZS5vcmcxEDAOBgNVBAsTB1Vua25vd24xFjAUBgNVBAMMDWFwcDJAYWNt
+ZS5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ9hkHkiTpwQ0cViMyfs9PgU5wZRTo2O
+GHxmw+EBlOvLBPamZ0zF2Rnqc/BRTCkoGQIF0nTFFyALsCxnmyZyje00ht0zOtc91aQl5W/c1ShE
+t7YlcSkDNDVxzouG1Nf7VZSbVbRtUkhhRRqAw84IV0GA1kRmZ8oEkvdeBULOYncrAgMBAAGgADAN
+BgkqhkiG9w0BAQQFAAOBgQBmlkaYAYn7h3oN54DljF6OJYqBN3RSd4KBa+oEs+2sEyh7kF6PqQpl
+cVpBOQx+sfUOUzGWML3Jzi4ub6uMmj3ghWGhyiV1hV2/HtYpkLVRedwbidHUUhROQO01ZODZsteZ
+LSMV4KRIENVswp3IsbhghvHTB+BlQV/JufR/m9ORjA==
+-----END NEW CERTIFICATE REQUEST-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/certstore.jks b/qpid/java/test-profiles/test_resources/ssl/certstore.jks
index 57460491fe..d427808eb1 100644
--- a/qpid/java/test-profiles/test_resources/ssl/certstore.jks
+++ b/qpid/java/test-profiles/test_resources/ssl/certstore.jks
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/keystore.jks b/qpid/java/test-profiles/test_resources/ssl/keystore.jks
index 8e033ec932..fd44841028 100644
--- a/qpid/java/test-profiles/test_resources/ssl/keystore.jks
+++ b/qpid/java/test-profiles/test_resources/ssl/keystore.jks
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/server_db/cert8.db b/qpid/java/test-profiles/test_resources/ssl/server_db/cert8.db
index 3063a1fef3..d55f529c52 100644
--- a/qpid/java/test-profiles/test_resources/ssl/server_db/cert8.db
+++ b/qpid/java/test-profiles/test_resources/ssl/server_db/cert8.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/server_db/key3.db b/qpid/java/test-profiles/test_resources/ssl/server_db/key3.db
index be86b4af4b..12f3c394c5 100644
--- a/qpid/java/test-profiles/test_resources/ssl/server_db/key3.db
+++ b/qpid/java/test-profiles/test_resources/ssl/server_db/key3.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/server_db/secmod.db b/qpid/java/test-profiles/test_resources/ssl/server_db/secmod.db
index 9c71db0abe..97a5b9b2fe 100644
--- a/qpid/java/test-profiles/test_resources/ssl/server_db/secmod.db
+++ b/qpid/java/test-profiles/test_resources/ssl/server_db/secmod.db
Binary files differ
diff --git a/qpid/java/test-profiles/test_resources/ssl/server_db/server.crt b/qpid/java/test-profiles/test_resources/ssl/server_db/server.crt
index eb9323ff34..4f1c007d16 100644
--- a/qpid/java/test-profiles/test_resources/ssl/server_db/server.crt
+++ b/qpid/java/test-profiles/test_resources/ssl/server_db/server.crt
@@ -1,12 +1,14 @@
-----BEGIN CERTIFICATE-----
-MIIBuDCCASGgAwIBAgIFAIzxXHYwDQYJKoZIhvcNAQEEBQAwETEPMA0GA1UEAxMG
-Um9vdENBMB4XDTA5MDQxNDIxNTUyOVoXDTEyMDQxNDIxNTUyOVowIDEeMBwGA1UE
-AxMVbG9jYWxob3N0LmxvY2FsZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQDNyXKaIcdDsBrcfsTRhIIsCGPCPKRuzN4w24PjfL72G7v0eyvKuposWDLf
-Os9T5ijaimYkbCyR+evnxFII/lOBFXGtzorTUnfVPvdIr8CEqjdTjJlCjT/rxjd0
-08kiMC9V4ohefnglA3UMBxm1st3IP6JzlUXlZqZdrfq1LLnLqQIDAQABow0wCzAJ
-BgNVHRMEAjAAMA0GCSqGSIb3DQEBBAUAA4GBAKkbAt9ockhmcfLGpyILfTUTqVqU
-Ys2VrOSDaJIxuQEouWNx9bIngKyBV23AvDbQ2Nb9QI8cuzu7laydO//obPrLpvH1
-MbOyd3j+JNNml9mDZw2rR8QpOvC9YDzBVcZgmw8QnHbTHYYdjUIGbXtWvG93gWTj
-QYVlvktPF1aM3RrM
+MIICKzCCAZSgAwIBAgIFAJBNUhEwDQYJKoZIhvcNAQEFBQAwQTELMAkGA1UEBhMC
+Q0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxETAPBgNVBAMTCE15
+Um9vdENBMB4XDTEwMDMyMjIxNDE0OVoXDTE1MDMyMjIxNDE0OVowTjELMAkGA1UE
+BhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDTALBgNVBAoTBEFDTUUxHjAcBgNVBAMT
+FWxvY2FsaG9zdC5sb2NhbGRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEAtmFy+0IIn6otWu2TCJ3fN2UDA//EVDWpiozzvd/My31XpPQ8jhuvsZ2//xvG
+OKqDfgQ80OE6BiGmR2zxPKFfsgxhU+0g8132focOzd0MhmGpyhdQdogXQ2cCcvjB
+CvgaugIjTmk3MX9njD7np8TQQ7wW1Wuk/c99tuvlexjEoWkCAwEAAaMiMCAwCQYD
+VR0TBAIwADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQDH
+iOxUWKllSUgCcAij0Gb4qDo/YDoatWyzE8pNZR7OgSOJ8zEVJcB/7YW//frd2dMS
+lz6c38vqbGwyblw+b64SvBKI3WK0jyO4Ft9FGpNIEfc9Q5G0MFiGilv+GDIZ/asE
+KnsZNy4z4gs3KFSf96k1AV1YQ1tVpFcUrI+3QqdWfQ==
-----END CERTIFICATE-----
diff --git a/qpid/java/test-profiles/test_resources/ssl/server_db/server.req b/qpid/java/test-profiles/test_resources/ssl/server_db/server.req
index a5a3fb2e35..5551516586 100644
--- a/qpid/java/test-profiles/test_resources/ssl/server_db/server.req
+++ b/qpid/java/test-profiles/test_resources/ssl/server_db/server.req
@@ -4,17 +4,18 @@ Phone: (not specified)
Common Name: localhost.localdomain
Email: (not specified)
-Organization: (not specified)
-State: (not specified)
-Country: (not specified)
+Organization: ACME
+State: Ontario
+Country: CA
-----BEGIN NEW CERTIFICATE REQUEST-----
-MIIBXzCByQIBADAgMR4wHAYDVQQDExVsb2NhbGhvc3QubG9jYWxkb21haW4wgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3Jcpohx0OwGtx+xNGEgiwIY8I8pG7M
-3jDbg+N8vvYbu/R7K8q6mixYMt86z1PmKNqKZiRsLJH56+fEUgj+U4EVca3OitNS
-d9U+90ivwISqN1OMmUKNP+vGN3TTySIwL1XiiF5+eCUDdQwHGbWy3cg/onOVReVm
-pl2t+rUsucupAgMBAAGgADANBgkqhkiG9w0BAQQFAAOBgQCD9+h4+q7Snw4F5E4i
-oCu9SvUgTpMs6ClZUoaCJzjVmkygZwyq38iZV0W6I94MXZ9PFbvyiZkKy0t2oMNk
-J33NOmaHoKOylYBkVlhHjknyYbvcL0Uwoj0/fyRbSZdllhAHUJgrjMBwPKks8+UJ
-0crBkyRYg2gSCLQaPwJPm4ddpw==
+MIIBjTCB9wIBADBOMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzENMAsG
+A1UEChMEQUNNRTEeMBwGA1UEAxMVbG9jYWxob3N0LmxvY2FsZG9tYWluMIGfMA0G
+CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2YXL7Qgifqi1a7ZMInd83ZQMD/8RUNamK
+jPO938zLfVek9DyOG6+xnb//G8Y4qoN+BDzQ4ToGIaZHbPE8oV+yDGFT7SDzXfZ+
+hw7N3QyGYanKF1B2iBdDZwJy+MEK+Bq6AiNOaTcxf2eMPuenxNBDvBbVa6T9z322
+6+V7GMShaQIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEAJGqdJVTScR4rzusrf6dE
+Snz/PtKcl8ZqXfHMPhj5uqUACcj3AxvlerIrpIGG9YT5cX4cOa92plpearMAC1TW
+fksbpsJR174WnAbBETrNbOX55igS/KDkW+RJCn7GGOvcSza+nJ880/lZ0iC63bgY
+SmvSnp3ub1CBX0grWl4bzTw=
-----END NEW CERTIFICATE REQUEST-----
diff --git a/qpid/python/examples/pubsub/verify.in b/qpid/python/examples/pubsub/verify.in
index 1b74acd832..ac1506b324 100644
--- a/qpid/python/examples/pubsub/verify.in
+++ b/qpid/python/examples/pubsub/verify.in
@@ -1,5 +1,18 @@
==== topic_publisher.py.out
==== topic_subscriber.py.out | remove_uuid | sort
+Messages on 'europe' queue:
+Messages on 'news' queue:
+Messages on 'usa' queue:
+Messages on 'weather' queue:
+Queues created - please start the topic producer
+Subscribing local queue 'local_europe' to europe-'
+Subscribing local queue 'local_news' to news-'
+Subscribing local queue 'local_usa' to usa-'
+Subscribing local queue 'local_weather' to weather-'
+That's all, folks!
+That's all, folks!
+That's all, folks!
+That's all, folks!
europe.news 0
europe.news 0
europe.news 1
@@ -20,19 +33,6 @@ europe.weather 3
europe.weather 3
europe.weather 4
europe.weather 4
-Messages on 'europe' queue:
-Messages on 'news' queue:
-Messages on 'usa' queue:
-Messages on 'weather' queue:
-Queues created - please start the topic producer
-Subscribing local queue 'local_europe' to europe-'
-Subscribing local queue 'local_news' to news-'
-Subscribing local queue 'local_usa' to usa-'
-Subscribing local queue 'local_weather' to weather-'
-That's all, folks!
-That's all, folks!
-That's all, folks!
-That's all, folks!
usa.news 0
usa.news 0
usa.news 1
diff --git a/qpid/python/qpid/brokertest.py b/qpid/python/qpid/brokertest.py
index 4feb7413d1..192228a74a 100644
--- a/qpid/python/qpid/brokertest.py
+++ b/qpid/python/qpid/brokertest.py
@@ -38,11 +38,10 @@ EXPECT_EXIT_FAIL=2 # Expect to exit with non-0 status before end of test
EXPECT_RUNNING=3 # Expect to still be running at end of test
EXPECT_UNKNOWN=4 # No expectation, don't check exit status.
-def is_exe(fpath):
- return os.path.exists(fpath) and os.access(fpath, os.X_OK)
-
def find_exe(program):
"""Find an executable in the system PATH"""
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
dir, name = os.path.split(program)
if dir:
if is_exe(program): return program
@@ -144,13 +143,13 @@ class Popen(popen2.Popen3):
expect - if set verify expectation at end of test.
drain - if true (default) drain stdout/stderr to files.
"""
- assert find_exe(cmd[0])
+ 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 ]
popen2.Popen3.__init__(self, self.cmd, True)
self.expect = expect
self.was_shutdown = False # Set if we deliberately kill/terminate the process
- self.pname = "%s-%d" % (os.path.split(self.cmd[0])[-1], self.pid)
+ self.pname = "%s-%d" % (os.path.split(self.cmd[0])[1], self.pid)
msg = "Process %s" % self.pname
self.stdin = ExceptionWrapper(self.tochild, msg)
self.stdout = Popen.OutStream(self.fromchild, self.outfile("out"), msg)
@@ -179,6 +178,7 @@ class Popen(popen2.Popen3):
def stop(self): # Clean up at end of test.
self.drain()
+ self.stdin.close()
if self.expect == EXPECT_UNKNOWN:
try: self.kill() # Just make sure its dead
except: pass
@@ -267,8 +267,9 @@ class Broker(Popen):
cmd += ["--data-dir", self.datadir]
Popen.__init__(self, cmd, expect, drain=False)
test.cleanup_stop(self)
- self._host = "localhost"
+ self._host = "127.0.0.1"
log.debug("Started broker %s (%s, %s)" % (self.name, self.pname, self.log))
+ self._log_ready = False
def host(self): return self._host
@@ -302,8 +303,8 @@ class Broker(Popen):
c.close()
def _prep_sender(self, queue, durable, xprops):
- s = queue + "; {create:always, node-properties:{durable:" + str(durable)
- if xprops != None: s += ", x-properties:{" + xprops + "}"
+ s = queue + "; {create:always, node:{durable:" + str(durable)
+ if xprops != None: s += ", x-declare:{" + xprops + "}"
return s + "}}"
def send_message(self, queue, message, durable=True, xprops=None, session=None):
@@ -344,16 +345,17 @@ 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
if not os.path.exists(self.log): return False
- ready_msg = re.compile("notice Broker running")
f = file(self.log)
try:
for l in f:
- if ready_msg.search(l): return True
+ if "notice Broker running" in l:
+ self._log_ready = True
+ return True
return False
finally: f.close()
- # FIXME aconway 2010-03-02: rename to wait_ready
def ready(self):
"""Wait till broker is ready to serve clients"""
# First make sure the broker is listening by checking the log.
@@ -361,7 +363,7 @@ class Broker(Popen):
raise Exception("Timed out waiting for broker %s" % self.name)
# Make a connection, this will wait for extended cluster init to finish.
try: self.connect().close()
- except: raise RethrownException("Broker %s failed ready test %s"%self.name)
+ except: raise RethrownException("Broker %s failed ready test"%self.name)
class Cluster:
"""A cluster of brokers in a test."""
@@ -427,6 +429,7 @@ class BrokerTest(TestCase):
for p in self.stopem:
try: p.stop()
except Exception, e: err.append(str(e))
+
if err: raise Exception("Unexpected process status:\n "+"\n ".join(err))
def cleanup_stop(self, stopable):
@@ -446,7 +449,7 @@ class BrokerTest(TestCase):
if (wait):
try: b.ready()
except Exception, e:
- raise Exception("Failed to start broker %s: %s" % ( b.name, e))
+ raise Exception("Failed to start broker %s(%s): %s" % (b.name, b.log, e))
return b
def cluster(self, count=0, args=[], expect=EXPECT_RUNNING, wait=True):
diff --git a/qpid/python/qpid/messaging/constants.py b/qpid/python/qpid/messaging/constants.py
index cad47bd52a..f230c4def8 100644
--- a/qpid/python/qpid/messaging/constants.py
+++ b/qpid/python/qpid/messaging/constants.py
@@ -17,11 +17,16 @@
# under the License.
#
+__SELF__ = object()
+
class Constant:
- def __init__(self, name, value=None):
+ def __init__(self, name, value=__SELF__):
self.name = name
- self.value = value
+ if value is __SELF__:
+ self.value = self
+ else:
+ self.value = value
def __repr__(self):
return self.name
@@ -30,3 +35,6 @@ AMQP_PORT = 5672
AMQPS_PORT = 5671
UNLIMITED = Constant("UNLIMITED", 0xFFFFFFFFL)
+
+REJECTED = Constant("REJECTED")
+RELEASED = Constant("RELEASED")
diff --git a/qpid/python/qpid/messaging/driver.py b/qpid/python/qpid/messaging/driver.py
index d0f5b746f3..ba53d94e33 100644
--- a/qpid/python/qpid/messaging/driver.py
+++ b/qpid/python/qpid/messaging/driver.py
@@ -18,7 +18,7 @@
#
import socket, struct, sys, time
-from logging import getLogger
+from logging import getLogger, DEBUG
from qpid import compat
from qpid import sasl
from qpid.concurrency import synchronized
@@ -27,13 +27,13 @@ from qpid.exceptions import Timeout, VersionError
from qpid.framing import OpEncoder, SegmentEncoder, FrameEncoder, \
FrameDecoder, SegmentDecoder, OpDecoder
from qpid.messaging import address
-from qpid.messaging.constants import UNLIMITED
+from qpid.messaging.constants import UNLIMITED, REJECTED, RELEASED
from qpid.messaging.exceptions import ConnectError
-from qpid.messaging.message import get_codec, Message
+from qpid.messaging.message import get_codec, Disposition, Message
from qpid.ops import *
from qpid.selector import Selector
from qpid.util import connect
-from qpid.validator import And, Context, Map, Types, Values
+from qpid.validator import And, Context, List, Map, Types, Values
from threading import Condition, Thread
log = getLogger("qpid.messaging")
@@ -78,9 +78,8 @@ class Pattern:
sst.write_cmd(ExchangeBind(exchange=exchange, queue=queue,
binding_key=self.value.replace("*", "#")))
-FILTER_DEFAULTS = {
- "topic": Pattern("*"),
- "amq.failover": Pattern("DUMMY")
+SUBJECT_DEFAULTS = {
+ "topic": "#"
}
# XXX
@@ -130,7 +129,14 @@ class SessionState:
id = self.sent
self.write_cmd(query, lambda: handler(self.results.pop(id)))
- def write_cmd(self, cmd, action=noop):
+ def apply_overrides(self, cmd, overrides):
+ for k, v in overrides.items():
+ cmd[k.replace('-', '_')] = v
+
+ def write_cmd(self, cmd, action=noop, overrides=None):
+ if overrides:
+ self.apply_overrides(cmd, overrides)
+
if action != noop:
cmd.sync = True
if self.detached:
@@ -154,28 +160,36 @@ class SessionState:
self.driver.write_op(op)
POLICIES = Values("always", "sender", "receiver", "never")
+RELIABILITY = Values("unreliable", "at-most-once", "at-least-once",
+ "exactly-once")
-class Bindings:
-
- def validate(self, o, ctx):
- t = ctx.containers[1].get("type", "queue")
- if t != "queue":
- return "bindings are only permitted on nodes of type queue"
+DECLARE = Map({}, restricted=False)
+BINDINGS = List(Map({
+ "exchange": Types(basestring),
+ "queue": Types(basestring),
+ "key": Types(basestring),
+ "arguments": Map({}, restricted=False)
+ }))
COMMON_OPTS = {
- "create": POLICIES,
- "delete": POLICIES,
- "assert": POLICIES,
- "node-properties": Map({
- "type": Values("queue", "topic"),
- "durable": Types(bool),
- "x-properties": Map({
- "type": Types(basestring),
- "bindings": And(Types(list), Bindings())
- },
- restricted=False)
- })
- }
+ "create": POLICIES,
+ "delete": POLICIES,
+ "assert": POLICIES,
+ "node": Map({
+ "type": Values("queue", "topic"),
+ "durable": Types(bool),
+ "x-declare": DECLARE,
+ "x-bindings": BINDINGS
+ }),
+ "link": Map({
+ "name": Types(basestring),
+ "durable": Types(bool),
+ "reliability": RELIABILITY,
+ "x-declare": DECLARE,
+ "x-bindings": BINDINGS,
+ "x-subscribe": Map({}, restricted=False)
+ })
+ }
RECEIVE_MODES = Values("browse", "consume")
@@ -196,36 +210,46 @@ class LinkIn:
_rcv.destination = str(rcv.id)
sst.destinations[_rcv.destination] = _rcv
_rcv.draining = False
+ _rcv.on_unlink = []
def do_link(self, sst, rcv, _rcv, type, subtype, action):
+ link_opts = _rcv.options.get("link", {})
+ # XXX: default?
+ reliability = link_opts.get("reliability", "unreliable")
+ declare = link_opts.get("x-declare", {})
+ subscribe = link_opts.get("x-subscribe", {})
acq_mode = acquire_mode.pre_acquired
if type == "topic":
- _rcv._queue = "%s.%s" % (rcv.session.name, _rcv.destination)
- sst.write_cmd(QueueDeclare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True))
- filter = _rcv.options.get("filter")
- if _rcv.subject is None and filter is None:
- f = FILTER_DEFAULTS[subtype]
- elif _rcv.subject and filter:
- # XXX
- raise Exception("can't supply both subject and filter")
- elif _rcv.subject:
- # XXX
- f = Pattern(_rcv.subject)
- else:
- f = filter
- f._bind(sst, _rcv.name, _rcv._queue)
+ default_name = "%s.%s" % (rcv.session.name, _rcv.destination)
+ _rcv._queue = link_opts.get("name", default_name)
+ sst.write_cmd(QueueDeclare(queue=_rcv._queue,
+ durable=link_opts.get("durable", False),
+ exclusive=True,
+ auto_delete=(reliability == "unreliable")),
+ overrides=declare)
+ _rcv.on_unlink = [QueueDelete(_rcv._queue)]
+ subject = _rcv.subject or SUBJECT_DEFAULTS.get(subtype)
+ sst.write_cmd(ExchangeBind(_rcv._queue, _rcv.name, subject))
+ bindings = get_bindings(link_opts, _rcv._queue, _rcv.name, subject)
elif type == "queue":
_rcv._queue = _rcv.name
if _rcv.options.get("mode", "consume") == "browse":
acq_mode = acquire_mode.not_acquired
+ bindings = get_bindings(link_opts, queue=_rcv._queue)
+ sst.write_cmds(bindings)
sst.write_cmd(MessageSubscribe(queue=_rcv._queue, destination=_rcv.destination,
- acquire_mode = acq_mode))
+ acquire_mode = acq_mode),
+ overrides=subscribe)
sst.write_cmd(MessageSetFlowMode(_rcv.destination, flow_mode.credit), action)
def do_unlink(self, sst, rcv, _rcv, action=noop):
- sst.write_cmd(MessageCancel(_rcv.destination), action)
+ link_opts = _rcv.options.get("link", {})
+ reliability = link_opts.get("reliability")
+ cmds = [MessageCancel(_rcv.destination)]
+ cmds.extend(_rcv.on_unlink)
+ sst.write_cmds(cmds, action)
def del_link(self, sst, rcv, _rcv):
del sst.destinations[_rcv.destination]
@@ -240,13 +264,16 @@ class LinkOut:
_snd.closing = False
def do_link(self, sst, snd, _snd, type, subtype, action):
+ link_opts = _snd.options.get("link", {})
if type == "topic":
_snd._exchange = _snd.name
_snd._routing_key = _snd.subject
+ bindings = get_bindings(link_opts, exchange=_snd.name, key=_snd.subject)
elif type == "queue":
_snd._exchange = ""
_snd._routing_key = _snd.name
- action()
+ bindings = get_bindings(link_opts, queue=_snd.name)
+ sst.write_cmds(bindings, action)
def do_unlink(self, sst, snd, _snd, action=noop):
action()
@@ -435,6 +462,19 @@ class Driver:
self._host = (self._host + 1) % len(self._hosts)
self.close_engine(e)
+DEFAULT_DISPOSITION = Disposition(None)
+
+def get_bindings(opts, queue=None, exchange=None, key=None):
+ bindings = opts.get("x-bindings", [])
+ cmds = []
+ for b in bindings:
+ exchange = b.get("exchange", exchange)
+ queue = b.get("queue", queue)
+ key = b.get("key", key)
+ args = b.get("arguments", {})
+ cmds.append(ExchangeBind(queue, exchange, key, args))
+ return cmds
+
class Engine:
def __init__(self, connection):
@@ -783,12 +823,6 @@ class Engine:
err = self.declare(sst, lnk, action)
else:
err = ("no such queue: %s" % lnk.name,)
- elif type == "queue":
- try:
- cmds = self.bindings(lnk)
- sst.write_cmds(cmds, lambda: action(type, subtype))
- except address.ParseError, e:
- err = (e,)
else:
action(type, subtype)
@@ -829,23 +863,21 @@ class Engine:
def declare(self, sst, lnk, action):
name = lnk.name
- props = lnk.options.get("node-properties", {})
+ props = lnk.options.get("node", {})
durable = props.get("durable", DURABLE_DEFAULT)
type = props.get("type", "queue")
- xprops = props.get("x-properties", {})
+ declare = props.get("x-declare", {})
if type == "topic":
cmd = ExchangeDeclare(exchange=name, durable=durable)
+ bindings = get_bindings(props, exchange=name)
elif type == "queue":
cmd = QueueDeclare(queue=name, durable=durable)
+ bindings = get_bindings(props, queue=name)
else:
raise ValueError(type)
- for f in cmd.FIELDS:
- if f.name != "arguments" and xprops.has_key(f.name):
- cmd[f.name] = xprops.pop(f.name)
- if xprops:
- cmd.arguments = xprops
+ sst.apply_overrides(cmd, declare)
if type == "topic":
if cmd.type is None:
@@ -855,11 +887,7 @@ class Engine:
subtype = None
cmds = [cmd]
- if type == "queue":
- try:
- cmds.extend(self.bindings(lnk))
- except address.ParseError, e:
- return (e,)
+ cmds.extend(bindings)
def declared():
self.address_cache[name] = (type, subtype)
@@ -867,16 +895,6 @@ class Engine:
sst.write_cmds(cmds, declared)
- def bindings(self, lnk):
- props = lnk.options.get("node-properties", {})
- xprops = props.get("x-properties", {})
- bindings = xprops.get("bindings", [])
- cmds = []
- for b in bindings:
- n, s, o = address.parse(b)
- cmds.append(ExchangeBind(lnk.name, n, s, o))
- return cmds
-
def delete(self, sst, name, action):
def deleted():
del self.address_cache[name]
@@ -915,19 +933,49 @@ class Engine:
if ssn.acked:
messages = [m for m in ssn.acked if m not in sst.acked]
if messages:
- # XXX: we're ignoring acks that get lost when disconnected,
- # could we deal this via some message-id based purge?
- ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
+ ids = RangedSet()
+
+ disposed = [(DEFAULT_DISPOSITION, [])]
+ for m in messages:
+ # XXX: we're ignoring acks that get lost when disconnected,
+ # could we deal this via some message-id based purge?
+ if m._transfer_id is None:
+ continue
+ ids.add(m._transfer_id)
+ disp = m._disposition or DEFAULT_DISPOSITION
+ last, msgs = disposed[-1]
+ if disp.type is last.type and disp.options == last.options:
+ msgs.append(m)
+ else:
+ disposed.append((disp, [m]))
+
for range in ids:
sst.executed.add_range(range)
sst.write_op(SessionCompleted(sst.executed))
- def ack_ack():
- for m in messages:
- ssn.acked.remove(m)
- if not ssn.transactional:
- sst.acked.remove(m)
- sst.write_cmd(MessageAccept(ids), ack_ack)
- log.debug("SACK[%s]: %s", ssn.log_id, m)
+
+ def ack_acker(msgs):
+ def ack_ack():
+ for m in msgs:
+ ssn.acked.remove(m)
+ if not ssn.transactional:
+ sst.acked.remove(m)
+ return ack_ack
+
+ for disp, msgs in disposed:
+ if not msgs: continue
+ if disp.type is None:
+ op = MessageAccept
+ elif disp.type is RELEASED:
+ op = MessageRelease
+ elif disp.type is REJECTED:
+ op = MessageReject
+ sst.write_cmd(op(RangedSet(*[m._transfer_id for m in msgs]),
+ **disp.options),
+ ack_acker(msgs))
+ if log.isEnabledFor(DEBUG):
+ for m in msgs:
+ log.debug("SACK[%s]: %s, %s", ssn.log_id, m, m._disposition)
+
sst.acked.extend(messages)
if ssn.committing and not sst.committing:
@@ -948,7 +996,7 @@ class Engine:
for range in ids:
sst.executed.add_range(range)
sst.write_op(SessionCompleted(sst.executed))
- sst.write_cmd(MessageRelease(ids))
+ sst.write_cmd(MessageRelease(ids, True))
sst.write_cmd(TxRollback(), do_rb_ok)
def do_rb_ok():
@@ -1055,8 +1103,11 @@ class Engine:
if mp.application_headers is None:
mp.application_headers = {}
mp.application_headers[TO] = msg.to
- if msg.durable:
- dp.delivery_mode = delivery_mode.persistent
+ if msg.durable is not None:
+ if msg.durable:
+ dp.delivery_mode = delivery_mode.persistent
+ else:
+ dp.delivery_mode = delivery_mode.non_persistent
if msg.priority is not None:
dp.priority = msg.priority
if msg.ttl is not None:
@@ -1109,7 +1160,8 @@ class Engine:
if mp.reply_to is not None:
msg.reply_to = reply_to2addr(mp.reply_to)
msg.correlation_id = mp.correlation_id
- msg.durable = dp.delivery_mode == delivery_mode.persistent
+ if dp.delivery_mode is not None:
+ msg.durable = dp.delivery_mode == delivery_mode.persistent
msg.priority = dp.priority
msg.ttl = dp.ttl
msg.redelivered = dp.redelivered
diff --git a/qpid/python/qpid/messaging/endpoints.py b/qpid/python/qpid/messaging/endpoints.py
index 004cee5f88..af2b1a8007 100644
--- a/qpid/python/qpid/messaging/endpoints.py
+++ b/qpid/python/qpid/messaging/endpoints.py
@@ -295,14 +295,29 @@ class Session:
create: <create-policy>,
delete: <delete-policy>,
assert: <assert-policy>,
- node-properties: {
+ node: {
type: <node-type>,
durable: <node-durability>,
- x-properties: {
- bindings: ["<exchange>/<key>", ...],
- <passthrough-key>: <passthrough-value>
- }
+ x-declare: { ... <queue-declare overrides> ... }
+ x-bindings: [<binding_1>, ... <binding_n>]
}
+ link: {
+ name: <link-name>,
+ durable: <link-durability>,
+ reliability: <link-reliability>,
+ x-declare: { ... <queue-declare overrides> ... }
+ x-bindings: [<binding_1>, ... <binding_n>]
+ x-subscribe: { ... <message-subscribe overrides> ... }
+ }
+ }
+
+ Bindings are specified as a map with the following options::
+
+ {
+ exchange: <exchange>,
+ queue: <queue>,
+ key: <key>,
+ arguments: <arguments>
}
The create, delete, and assert policies specify who should perfom
@@ -316,14 +331,12 @@ class Session:
The node-type is one of:
- I{topic}: a topic node will default to the topic exchange,
- x-properties may be used to specify other exchange types
+ x-declare may be used to specify other exchange types
- I{queue}: this is the default node-type
- The x-properties map permits arbitrary additional keys and values to
- be specified. These keys and values are passed through when creating
- a node or asserting facts about an existing node. Any passthrough
- keys and values that do not match a standard field of the underlying
- exchange or queue declare command will be sent in the arguments map.
+ The x-declare map permits protocol specific keys and values to be
+ specified. These keys and values are passed through when creating a
+ node or asserting facts about an existing node.
Examples
--------
@@ -353,18 +366,18 @@ class Session:
You can customize the properties of the queue::
- my-queue; {create: always, node-properties: {durable: True}}
+ my-queue; {create: always, node: {durable: True}}
You can create a topic instead if you want::
- my-queue; {create: always, node-properties: {type: topic}}
+ my-queue; {create: always, node: {type: topic}}
You can assert that the address resolves to a node with particular
properties::
my-transient-topic; {
assert: always,
- node-properties: {
+ node: {
type: topic,
durable: False
}
@@ -508,7 +521,7 @@ class Session:
raise Empty
@synchronized
- def acknowledge(self, message=None, sync=True):
+ def acknowledge(self, message=None, disposition=None, sync=True):
"""
Acknowledge the given L{Message}. If message is None, then all
unacknowledged messages on the session are acknowledged.
@@ -530,6 +543,7 @@ class Session:
raise InsufficientCapacity("ack_capacity = %s" % self.ack_capacity)
self._wakeup()
self._ewait(lambda: len(self.acked) < self.ack_capacity)
+ m._disposition = disposition
self.unacked.remove(m)
self.acked.append(m)
diff --git a/qpid/python/qpid/messaging/message.py b/qpid/python/qpid/messaging/message.py
index 46494e428e..a9660b05b1 100644
--- a/qpid/python/qpid/messaging/message.py
+++ b/qpid/python/qpid/messaging/message.py
@@ -129,7 +129,7 @@ class Message:
"correlation_id", "priority", "ttl"]:
value = self.__dict__[name]
if value is not None: args.append("%s=%r" % (name, value))
- for name in ["durable", "properties"]:
+ for name in ["durable", "redelivered", "properties"]:
value = self.__dict__[name]
if value: args.append("%s=%r" % (name, value))
if self.content_type != get_type(self.content):
@@ -141,4 +141,15 @@ class Message:
args.append(repr(self.content))
return "Message(%s)" % ", ".join(args)
-__all__ = ["Message"]
+class Disposition:
+
+ def __init__(self, type, **options):
+ self.type = type
+ self.options = options
+
+ def __repr__(self):
+ args = [str(self.type)] + \
+ ["%s=%r" % (k, v) for k, v in self.options.items()]
+ return "Disposition(%s)" % ", ".join(args)
+
+__all__ = ["Message", "Disposition"]
diff --git a/qpid/python/qpid/tests/messaging/__init__.py b/qpid/python/qpid/tests/messaging/__init__.py
index eb8ff87391..c3581efb9d 100644
--- a/qpid/python/qpid/tests/messaging/__init__.py
+++ b/qpid/python/qpid/tests/messaging/__init__.py
@@ -59,6 +59,9 @@ class Base(Test):
else:
return "%s[%s, %s]" % (base, count, self.test_id)
+ def message(self, base, count = None, **kwargs):
+ return Message(content=self.content(base, count), **kwargs)
+
def ping(self, ssn):
PING_Q = 'ping-queue; {create: always, delete: always}'
# send a message
@@ -70,16 +73,52 @@ class Base(Test):
ssn.acknowledge()
assert msg.content == content, "expected %r, got %r" % (content, msg.content)
- def drain(self, rcv, limit=None, timeout=0, expected=None):
- contents = []
+ def drain(self, rcv, limit=None, timeout=0, expected=None, redelivered=False):
+ messages = []
try:
- while limit is None or len(contents) < limit:
- contents.append(rcv.fetch(timeout=timeout).content)
+ while limit is None or len(messages) < limit:
+ messages.append(rcv.fetch(timeout=timeout))
except Empty:
pass
if expected is not None:
- assert expected == contents, "expected %s, got %s" % (expected, contents)
- return contents
+ self.assertEchos(expected, messages, redelivered)
+ return messages
+
+ def diff(self, m1, m2):
+ result = {}
+ for attr in ("id", "subject", "user_id", "to", "reply_to",
+ "correlation_id", "durable", "priority", "ttl",
+ "redelivered", "properties", "content_type",
+ "content"):
+ a1 = getattr(m1, attr)
+ a2 = getattr(m2, attr)
+ if a1 != a2:
+ result[attr] = (a1, a2)
+ return result
+
+ def assertEcho(self, msg, echo, redelivered=False):
+ if not isinstance(msg, Message) or not isinstance(echo, Message):
+ if isinstance(msg, Message):
+ msg = msg.content
+ if isinstance(echo, Message):
+ echo = echo.content
+ assert msg == echo, "expected %s, got %s" % (msg, echo)
+ else:
+ delta = self.diff(msg, echo)
+ mttl, ettl = delta.pop("ttl", (0, 0))
+ if redelivered:
+ assert echo.redelivered, \
+ "expected %s to be redelivered: %s" % (msg, echo)
+ if delta.has_key("redelivered"):
+ del delta["redelivered"]
+ assert mttl is not None and ettl is not None, "%s, %s" % (mttl, ettl)
+ assert mttl >= ettl, "%s, %s" % (mttl, ettl)
+ assert not delta, "expected %s, got %s, delta %s" % (msg, echo, delta)
+
+ def assertEchos(self, msgs, echoes, redelivered=False):
+ assert len(msgs) == len(echoes), "%s, %s" % (msgs, echoes)
+ for m, e in zip(msgs, echoes):
+ self.assertEcho(m, e, redelivered)
def assertEmpty(self, rcv):
contents = self.drain(rcv)
diff --git a/qpid/python/qpid/tests/messaging/endpoints.py b/qpid/python/qpid/tests/messaging/endpoints.py
index 6bc52d962d..5d4fc1646b 100644
--- a/qpid/python/qpid/tests/messaging/endpoints.py
+++ b/qpid/python/qpid/tests/messaging/endpoints.py
@@ -227,21 +227,60 @@ class SessionTests(Base):
def testAcknowledgeAsyncAckCapUNLIMITED(self):
self.ackTest(lambda ssn: ssn.acknowledge(sync=False), UNLIMITED)
- def send(self, ssn, queue, base, count=1):
- snd = ssn.sender(queue, durable=self.durable())
- contents = []
+ def testRelease(self):
+ msgs = [self.message("testRelease", i) for i in range(3)]
+ snd = self.ssn.sender("test-release-queue; {create: always, delete: always}")
+ for m in msgs:
+ snd.send(m)
+ rcv = self.ssn.receiver(snd.target)
+ echos = self.drain(rcv, expected=msgs)
+ self.ssn.acknowledge(echos[0])
+ self.ssn.acknowledge(echos[1], Disposition(RELEASED, set_redelivered=True))
+ self.ssn.acknowledge(echos[2], Disposition(RELEASED))
+ self.drain(rcv, limit=1, expected=msgs[1:2], redelivered=True)
+ self.drain(rcv, expected=msgs[2:3])
+ self.ssn.acknowledge()
+
+ def testReject(self):
+ msgs = [self.message("testReject", i) for i in range(3)]
+ snd = self.ssn.sender("""
+ test-reject-queue; {
+ create: always,
+ delete: always,
+ node: {
+ x-declare: {
+ alternate-exchange: 'amq.topic'
+ }
+ }
+ }
+""")
+ for m in msgs:
+ snd.send(m)
+ rcv = self.ssn.receiver(snd.target)
+ rej = self.ssn.receiver("amq.topic")
+ echos = self.drain(rcv, expected=msgs)
+ self.ssn.acknowledge(echos[0])
+ self.ssn.acknowledge(echos[1], Disposition(REJECTED))
+ self.ssn.acknowledge(echos[2],
+ Disposition(REJECTED, code=3, text="test-reject"))
+ self.drain(rej, expected=msgs[1:])
+ self.ssn.acknowledge()
+
+ def send(self, ssn, target, base, count=1):
+ snd = ssn.sender(target, durable=self.durable())
+ messages = []
for i in range(count):
- c = self.content(base, i)
+ c = self.message(base, i)
snd.send(c)
- contents.append(c)
+ messages.append(c)
snd.close()
- return contents
+ return messages
def txTest(self, commit):
TX_Q = 'test-tx-queue; {create: sender, delete: receiver}'
TX_Q_COPY = 'test-tx-queue-copy; {create: always, delete: always}'
txssn = self.conn.session(transactional=True)
- contents = self.send(self.ssn, TX_Q, "txTest", 3)
+ messages = self.send(self.ssn, TX_Q, "txTest", 3)
txrcv = txssn.receiver(TX_Q)
txsnd = txssn.sender(TX_Q_COPY, durable=self.durable())
rcv = self.ssn.receiver(txrcv.source)
@@ -255,10 +294,10 @@ class SessionTests(Base):
if commit:
txssn.commit()
self.assertEmpty(rcv)
- assert contents == self.drain(copy_rcv)
+ self.drain(copy_rcv, expected=messages)
else:
txssn.rollback()
- assert contents == self.drain(rcv)
+ self.drain(rcv, expected=messages, redelivered=True)
self.assertEmpty(copy_rcv)
self.ssn.acknowledge()
@@ -271,13 +310,13 @@ class SessionTests(Base):
def txTestSend(self, commit):
TX_SEND_Q = 'test-tx-send-queue; {create: sender, delete: receiver}'
txssn = self.conn.session(transactional=True)
- contents = self.send(txssn, TX_SEND_Q, "txTestSend", 3)
+ messages = self.send(txssn, TX_SEND_Q, "txTestSend", 3)
rcv = self.ssn.receiver(TX_SEND_Q)
self.assertEmpty(rcv)
if commit:
txssn.commit()
- assert contents == self.drain(rcv)
+ self.drain(rcv, expected=messages)
self.ssn.acknowledge()
else:
txssn.rollback()
@@ -297,18 +336,17 @@ class SessionTests(Base):
txssn = self.conn.session(transactional=True)
txrcv = txssn.receiver(TX_ACK_QC)
self.assertEmpty(txrcv)
- contents = self.send(self.ssn, TX_ACK_QC, "txTestAck", 3)
- assert contents == self.drain(txrcv)
+ messages = self.send(self.ssn, TX_ACK_QC, "txTestAck", 3)
+ self.drain(txrcv, expected=messages)
if commit:
txssn.acknowledge()
else:
txssn.rollback()
- drained = self.drain(txrcv)
- assert contents == drained, "expected %s, got %s" % (contents, drained)
+ self.drain(txrcv, expected=messages, redelivered=True)
txssn.acknowledge()
txssn.rollback()
- assert contents == self.drain(txrcv)
+ self.drain(txrcv, expected=messages, redelivered=True)
txssn.commit() # commit without ack
self.assertEmpty(txrcv)
@@ -316,7 +354,7 @@ class SessionTests(Base):
txssn = self.conn.session(transactional=True)
txrcv = txssn.receiver(TX_ACK_QC)
- assert contents == self.drain(txrcv)
+ self.drain(txrcv, expected=messages, redelivered=True)
txssn.acknowledge()
txssn.commit()
rcv = self.ssn.receiver(TX_ACK_QD)
@@ -477,7 +515,7 @@ class ReceiverTests(Base):
snd = self.ssn.sender("""test-double-close; {
create: always,
delete: sender,
- node-properties: {
+ node: {
type: topic
}
}
@@ -533,9 +571,9 @@ class AddressTests(Base):
assert "error in options: %s" % error == str(e), e
def testIllegalKey(self):
- self.badOption("{create: always, node-properties: "
+ self.badOption("{create: always, node: "
"{this-property-does-not-exist: 3}}",
- "node-properties: this-property-does-not-exist: "
+ "node: this-property-does-not-exist: "
"illegal key")
def testWrongValue(self):
@@ -543,23 +581,17 @@ class AddressTests(Base):
"('always', 'sender', 'receiver', 'never')")
def testWrongType1(self):
- self.badOption("{node-properties: asdf}",
- "node-properties: asdf is not a map")
+ self.badOption("{node: asdf}",
+ "node: asdf is not a map")
def testWrongType2(self):
- self.badOption("{node-properties: {durable: []}}",
- "node-properties: durable: [] is not a bool")
-
- def testNonQueueBindings(self):
- self.badOption("{node-properties: {type: topic, x-properties: "
- "{bindings: []}}}",
- "node-properties: x-properties: bindings: "
- "bindings are only permitted on nodes of type queue")
+ self.badOption("{node: {durable: []}}",
+ "node: durable: [] is not a bool")
def testCreateQueue(self):
snd = self.ssn.sender("test-create-queue; {create: always, delete: always, "
- "node-properties: {type: queue, durable: False, "
- "x-properties: {auto_delete: true}}}")
+ "node: {type: queue, durable: False, "
+ "x-declare: {auto_delete: true}}}")
content = self.content("testCreateQueue")
snd.send(content)
rcv = self.ssn.receiver("test-create-queue")
@@ -569,10 +601,10 @@ class AddressTests(Base):
addr = """test-create-exchange; {
create: always,
delete: always,
- node-properties: {
+ node: {
type: topic,
durable: False,
- x-properties: {auto_delete: true, %s}
+ x-declare: {auto_delete: true, %s}
}
}""" % props
snd = self.ssn.sender(addr)
@@ -639,15 +671,15 @@ class AddressTests(Base):
# XXX: need to figure out close after error
self.conn._remove_session(self.ssn)
- def testBindings(self):
+ def testNodeBindingsQueue(self):
snd = self.ssn.sender("""
-test-bindings-queue; {
+test-node-bindings-queue; {
create: always,
delete: always,
- node-properties: {
- x-properties: {
- bindings: ["amq.topic/a.#", "amq.direct/b", "amq.topic/c.*"]
- }
+ node: {
+ x-bindings: [{exchange: "amq.topic", key: "a.#"},
+ {exchange: "amq.direct", key: "b"},
+ {exchange: "amq.topic", key: "c.*"}]
}
}
""")
@@ -658,49 +690,80 @@ test-bindings-queue; {
snd_a.send("two")
snd_b.send("three")
snd_c.send("four")
- rcv = self.ssn.receiver("test-bindings-queue")
+ rcv = self.ssn.receiver("test-node-bindings-queue")
self.drain(rcv, expected=["one", "two", "three", "four"])
- def testBindingsAdditive(self):
- m1 = self.content("testBindingsAdditive", 1)
- m2 = self.content("testBindingsAdditive", 2)
- m3 = self.content("testBindingsAdditive", 3)
- m4 = self.content("testBindingsAdditive", 4)
-
+ def testNodeBindingsTopic(self):
+ rcv = self.ssn.receiver("test-node-bindings-topic-queue; {create: always, delete: always}")
+ rcv_a = self.ssn.receiver("test-node-bindings-topic-queue-a; {create: always, delete: always}")
+ rcv_b = self.ssn.receiver("test-node-bindings-topic-queue-b; {create: always, delete: always}")
+ rcv_c = self.ssn.receiver("test-node-bindings-topic-queue-c; {create: always, delete: always}")
snd = self.ssn.sender("""
-test-bindings-additive-queue; {
+test-node-bindings-topic; {
create: always,
delete: always,
- node-properties: {
- x-properties: {
- bindings: ["amq.topic/a"]
- }
+ node: {
+ type: topic,
+ x-bindings: [{queue: test-node-bindings-topic-queue, key: "#"},
+ {queue: test-node-bindings-topic-queue-a, key: "a.#"},
+ {queue: test-node-bindings-topic-queue-b, key: "b"},
+ {queue: test-node-bindings-topic-queue-c, key: "c.*"}]
}
}
""")
+ m1 = Message("one")
+ m2 = Message(subject="a.foo", content="two")
+ m3 = Message(subject="b", content="three")
+ m4 = Message(subject="c.bar", content="four")
+ snd.send(m1)
+ snd.send(m2)
+ snd.send(m3)
+ snd.send(m4)
+ self.drain(rcv, expected=[m1, m2, m3, m4])
+ self.drain(rcv_a, expected=[m2])
+ self.drain(rcv_b, expected=[m3])
+ self.drain(rcv_c, expected=[m4])
+
+ def testLinkBindings(self):
+ m_a = self.message("testLinkBindings", 1, subject="a")
+ m_b = self.message("testLinkBindings", 2, subject="b")
+
+ self.ssn.sender("test-link-bindings-queue; {create: always, delete: always}")
+ snd = self.ssn.sender("amq.topic")
+
+ snd.send(m_a)
+ snd.send(m_b)
+ snd.close()
- snd_a = self.ssn.sender("amq.topic/a")
- snd_b = self.ssn.sender("amq.topic/b")
+ rcv = self.ssn.receiver("test-link-bindings-queue")
+ self.assertEmpty(rcv)
+
+ snd = self.ssn.sender("""
+amq.topic; {
+ link: {
+ x-bindings: [{queue: test-link-bindings-queue, key: a}]
+ }
+}
+""")
- snd_a.send(m1)
- snd_b.send(m2)
+ snd.send(m_a)
+ snd.send(m_b)
- rcv = self.ssn.receiver("test-bindings-additive-queue")
- self.drain(rcv, expected=[m1])
+ self.drain(rcv, expected=[m_a])
+ rcv.close()
- new_snd = self.ssn.sender("""
-test-bindings-additive-queue; {
- node-properties: {
- x-properties: {
- bindings: ["amq.topic/b"]
- }
+ rcv = self.ssn.receiver("""
+test-link-bindings-queue; {
+ link: {
+ x-bindings: [{exchange: "amq.topic", key: b}]
}
}
""")
- new_snd.send(m3)
- snd_b.send(m4)
- self.drain(rcv, expected=[m3, m4])
+ snd.send(m_a)
+ snd.send(m_b)
+
+ self.drain(rcv, expected=[m_a, m_b])
def testSubjectOverride(self):
snd = self.ssn.sender("amq.topic/a")
@@ -726,6 +789,32 @@ test-bindings-additive-queue; {
assert e2.subject == "b", "subject: %s" % e2.subject
self.assertEmpty(rcv)
+ def doReliabilityTest(self, reliability, messages, expected):
+ snd = self.ssn.sender("amq.topic")
+ rcv = self.ssn.receiver("amq.topic; {link: {reliability: %s}}" % reliability)
+ for m in messages:
+ snd.send(m)
+ self.conn.disconnect()
+ self.conn.connect()
+ self.drain(rcv, expected=expected)
+
+ def testReliabilityUnreliable(self):
+ msgs = [self.message("testReliabilityUnreliable", i) for i in range(3)]
+ self.doReliabilityTest("unreliable", msgs, [])
+
+ def testReliabilityAtLeastOnce(self):
+ msgs = [self.message("testReliabilityAtLeastOnce", i) for i in range(3)]
+ self.doReliabilityTest("at-least-once", msgs, msgs)
+
+ def testLinkName(self):
+ msgs = [self.message("testLinkName", i) for i in range(3)]
+ snd = self.ssn.sender("amq.topic")
+ trcv = self.ssn.receiver("amq.topic; {link: {name: test-link-name}}")
+ qrcv = self.ssn.receiver("test-link-name")
+ for m in msgs:
+ snd.send(m)
+ self.drain(qrcv, expected=msgs)
+
NOSUCH_Q = "this-queue-should-not-exist"
UNPARSEABLE_ADDR = "name/subject; {bad options"
UNLEXABLE_ADDR = "\0x0\0x1\0x2\0x3"
@@ -838,8 +927,7 @@ class SenderTests(Base):
msgs = [self.content("asyncTest", i) for i in range(15)]
for m in msgs:
self.snd.send(m, sync=False)
- drained = self.drain(self.rcv, timeout=self.delay())
- assert msgs == drained, "expected %s, got %s" % (msgs, drained)
+ self.drain(self.rcv, timeout=self.delay(), expected=msgs)
self.ssn.acknowledge()
def testSendAsyncCapacity0(self):
diff --git a/qpid/python/qpid/tests/messaging/message.py b/qpid/python/qpid/tests/messaging/message.py
index 930c031abb..654076588b 100644
--- a/qpid/python/qpid/tests/messaging/message.py
+++ b/qpid/python/qpid/tests/messaging/message.py
@@ -68,20 +68,7 @@ class MessageEchoTests(Base):
def check(self, msg):
self.snd.send(msg)
echo = self.rcv.fetch(0)
-
- assert msg.id == echo.id
- assert msg.subject == echo.subject
- assert msg.user_id == echo.user_id
- assert msg.to == echo.to
- assert msg.reply_to == echo.reply_to
- assert msg.correlation_id == echo.correlation_id
- assert msg.durable == echo.durable
- assert msg.priority == echo.priority
- assert msg.ttl == echo.ttl
- assert msg.properties == echo.properties
- assert msg.content_type == echo.content_type
- assert msg.content == echo.content, "%s, %s" % (msg, echo)
-
+ self.assertEcho(msg, echo)
self.ssn.acknowledge(echo)
def testStringContent(self):
diff --git a/qpid/python/qpid/validator.py b/qpid/python/qpid/validator.py
index 7bd62b68f8..d234642b3e 100644
--- a/qpid/python/qpid/validator.py
+++ b/qpid/python/qpid/validator.py
@@ -54,6 +54,20 @@ class Types:
else:
return "%s is not one of: %s" % (o, ", ".join([t.__name__ for t in self.types]))
+class List:
+
+ def __init__(self, condition):
+ self.condition = condition
+
+ def validate(self, o, ctx):
+ if not isinstance(o, list):
+ return "%s is not a list" % o
+
+ ctx.push(o)
+ for v in o:
+ err = self.condition.validate(v, ctx)
+ if err: return err
+
class Map:
def __init__(self, map, restricted=True):
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 0ac78a4799..9a4cfd37d6 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
@@ -430,6 +430,16 @@ class HeadersExchangeTests(TestHelper):
self.myBasicPublish({"irrelevant":0})
self.assertEmpty(self.q)
+ def testMatchVoidValue(self):
+ self.session.exchange_bind(queue="q", exchange="amq.match", arguments={ 'x-match':'any', "name":None})
+ self.myAssertPublishGet({"name":"fred"})
+ self.myAssertPublishGet({"name":"bob"})
+
+ # Wont match
+ self.myBasicPublish({})
+ self.myBasicPublish({"irrelevant":0})
+ self.assertEmpty(self.q)
+
class MiscellaneousErrorsTests(TestHelper):
"""
diff --git a/qpid/tools/.gitignore b/qpid/tools/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/qpid/tools/.gitignore
@@ -0,0 +1 @@
+/build