summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2009-10-05 12:51:57 +0000
committerRobert Godfrey <rgodfrey@apache.org>2009-10-05 12:51:57 +0000
commitf67026b148b3429ca9731bce94a0bd3ff2981ce5 (patch)
tree95e7dfcfff6640d83b4171520bffb4d4b2304b9a
parent69e05a6b0979d2e12588635a4ed46a09a87cdec0 (diff)
downloadqpid-python-f67026b148b3429ca9731bce94a0bd3ff2981ce5.tar.gz
Merged from trunk up to r816580
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/java-broker-0-10@821779 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/bindings/qmf/Makefile.am10
-rw-r--r--qpid/cpp/bindings/qmf/python/Makefile.am11
-rw-r--r--qpid/cpp/bindings/qmf/python/python.i120
-rw-r--r--qpid/cpp/bindings/qmf/python/qmf.py858
-rw-r--r--qpid/cpp/bindings/qmf/qmfengine.i4
-rw-r--r--qpid/cpp/bindings/qmf/ruby/qmf.rb1405
-rw-r--r--qpid/cpp/bindings/qmf/tests/Makefile.am8
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/agent_ruby.rb87
-rw-r--r--qpid/cpp/bindings/qmf/tests/python_agent.py194
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/python_console.py12
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/ruby_console.rb133
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/run_interop_tests64
-rw-r--r--qpid/cpp/configure.ac1
-rw-r--r--qpid/cpp/examples/messaging/server.cpp4
-rw-r--r--qpid/cpp/include/qmf/QmfImportExport.h2
-rw-r--r--qpid/cpp/include/qpid/framing/FieldTable.h3
-rw-r--r--qpid/cpp/include/qpid/framing/List.h1
-rw-r--r--qpid/cpp/include/qpid/framing/Uuid.h27
-rw-r--r--qpid/cpp/include/qpid/management/Manageable.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Connection.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Message.h8
-rw-r--r--qpid/cpp/include/qpid/messaging/Receiver.h33
-rw-r--r--qpid/cpp/include/qpid/messaging/Sender.h21
-rw-r--r--qpid/cpp/include/qpid/messaging/Session.h18
-rw-r--r--qpid/cpp/include/qpid/messaging/Variant.h30
-rwxr-xr-xqpid/cpp/include/qpid/sys/windows/Condition.h1
-rwxr-xr-xqpid/cpp/include/qpid/sys/windows/Mutex.h1
-rw-r--r--qpid/cpp/src/CMakeLists.txt9
-rw-r--r--qpid/cpp/src/Makefile.am15
-rw-r--r--qpid/cpp/src/qmf.mk8
-rw-r--r--qpid/cpp/src/qmf/AgentEngine.cpp249
-rw-r--r--qpid/cpp/src/qmf/AgentEngine.h6
-rw-r--r--qpid/cpp/src/qmf/BrokerProxyImpl.cpp663
-rw-r--r--qpid/cpp/src/qmf/BrokerProxyImpl.h222
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngine.h201
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngineImpl.cpp361
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngineImpl.h133
-rw-r--r--qpid/cpp/src/qmf/Object.h4
-rw-r--r--qpid/cpp/src/qmf/ObjectId.h1
-rw-r--r--qpid/cpp/src/qmf/ObjectIdImpl.cpp21
-rw-r--r--qpid/cpp/src/qmf/ObjectIdImpl.h3
-rw-r--r--qpid/cpp/src/qmf/ObjectImpl.cpp104
-rw-r--r--qpid/cpp/src/qmf/ObjectImpl.h18
-rw-r--r--qpid/cpp/src/qmf/Protocol.cpp (renamed from qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java)55
-rw-r--r--qpid/cpp/src/qmf/Protocol.h67
-rw-r--r--qpid/cpp/src/qmf/Query.h70
-rw-r--r--qpid/cpp/src/qmf/QueryImpl.cpp85
-rw-r--r--qpid/cpp/src/qmf/QueryImpl.h78
-rw-r--r--qpid/cpp/src/qmf/ResilientConnection.cpp65
-rw-r--r--qpid/cpp/src/qmf/ResilientConnection.h11
-rw-r--r--qpid/cpp/src/qmf/Schema.h23
-rw-r--r--qpid/cpp/src/qmf/SchemaImpl.cpp471
-rw-r--r--qpid/cpp/src/qmf/SchemaImpl.h47
-rw-r--r--qpid/cpp/src/qmf/SequenceManager.cpp96
-rw-r--r--qpid/cpp/src/qmf/SequenceManager.h66
-rw-r--r--qpid/cpp/src/qmf/Value.h3
-rw-r--r--qpid/cpp/src/qmf/ValueImpl.cpp354
-rw-r--r--qpid/cpp/src/qmf/ValueImpl.h3
-rw-r--r--qpid/cpp/src/qpid/acl/AclData.cpp91
-rw-r--r--qpid/cpp/src/qpid/acl/AclData.h12
-rw-r--r--qpid/cpp/src/qpid/acl/AclReader.cpp227
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp4
-rw-r--r--qpid/cpp/src/qpid/broker/AclModule.h17
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp6
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.cpp26
-rw-r--r--qpid/cpp/src/qpid/broker/Link.cpp5
-rw-r--r--qpid/cpp/src/qpid/broker/Message.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/Message.h10
-rw-r--r--qpid/cpp/src/qpid/broker/MessageBuilder.cpp28
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/PersistableMessage.h4
-rw-r--r--qpid/cpp/src/qpid/broker/Queue.cpp4
-rw-r--r--qpid/cpp/src/qpid/broker/QueueRegistry.h2
-rw-r--r--qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp24
-rw-r--r--qpid/cpp/src/qpid/client/Dispatcher.cpp11
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp111
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.h85
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp23
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h4
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp30
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h (renamed from qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h)31
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp114
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h26
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp72
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h11
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h4
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp64
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h (renamed from qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp)34
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp179
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h108
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp100
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h90
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp289
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h128
-rw-r--r--qpid/cpp/src/qpid/cluster/Connection.cpp10
-rw-r--r--qpid/cpp/src/qpid/cluster/Quorum_cman.cpp8
-rw-r--r--qpid/cpp/src/qpid/framing/Uuid.cpp31
-rw-r--r--qpid/cpp/src/qpid/management/Manageable.cpp2
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp4
-rw-r--r--qpid/cpp/src/qpid/messaging/Address.cpp3
-rw-r--r--qpid/cpp/src/qpid/messaging/Message.cpp257
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.cpp205
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.h134
-rw-r--r--qpid/cpp/src/qpid/messaging/Receiver.cpp3
-rw-r--r--qpid/cpp/src/qpid/messaging/ReceiverImpl.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/Sender.cpp5
-rw-r--r--qpid/cpp/src/qpid/messaging/SenderImpl.h5
-rw-r--r--qpid/cpp/src/qpid/messaging/Session.cpp12
-rw-r--r--qpid/cpp/src/qpid/messaging/SessionImpl.h8
-rw-r--r--qpid/cpp/src/qpid/messaging/Variant.cpp258
-rw-r--r--qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp26
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp11
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp11
-rw-r--r--qpid/cpp/src/qpid/sys/uuid.h (renamed from qpid/cpp/include/qpid/sys/uuid.h)0
-rw-r--r--qpid/cpp/src/qpid/sys/windows/uuid.h (renamed from qpid/cpp/include/qpid/sys/windows/uuid.h)0
-rw-r--r--qpid/cpp/src/qpid/xml/XmlExchange.cpp46
-rw-r--r--qpid/cpp/src/tests/AccumulatedAckTest.cpp13
-rw-r--r--qpid/cpp/src/tests/Array.cpp11
-rw-r--r--qpid/cpp/src/tests/AsyncCompletion.cpp11
-rw-r--r--qpid/cpp/src/tests/AtomicValue.cpp5
-rw-r--r--qpid/cpp/src/tests/BrokerFixture.h10
-rw-r--r--qpid/cpp/src/tests/CMakeLists.txt2
-rw-r--r--qpid/cpp/src/tests/ClientMessageTest.cpp7
-rw-r--r--qpid/cpp/src/tests/ClientSessionTest.cpp67
-rw-r--r--qpid/cpp/src/tests/ClusterFailover.cpp5
-rw-r--r--qpid/cpp/src/tests/ClusterFixture.cpp5
-rw-r--r--qpid/cpp/src/tests/ClusterFixture.h5
-rw-r--r--qpid/cpp/src/tests/ConnectionOptions.h14
-rw-r--r--qpid/cpp/src/tests/ConsoleTest.cpp9
-rw-r--r--qpid/cpp/src/tests/DeliveryRecordTest.cpp8
-rw-r--r--qpid/cpp/src/tests/DispatcherTest.cpp47
-rw-r--r--qpid/cpp/src/tests/DtxWorkRecordTest.cpp18
-rw-r--r--qpid/cpp/src/tests/ExchangeTest.cpp41
-rw-r--r--qpid/cpp/src/tests/FieldTable.cpp19
-rw-r--r--qpid/cpp/src/tests/FieldValue.cpp13
-rw-r--r--qpid/cpp/src/tests/ForkedBroker.cpp20
-rw-r--r--qpid/cpp/src/tests/ForkedBroker.h17
-rw-r--r--qpid/cpp/src/tests/Frame.cpp9
-rw-r--r--qpid/cpp/src/tests/FrameDecoder.cpp11
-rw-r--r--qpid/cpp/src/tests/FramingTest.cpp25
-rw-r--r--qpid/cpp/src/tests/HeaderTest.cpp18
-rw-r--r--qpid/cpp/src/tests/HeadersExchangeTest.cpp31
-rw-r--r--qpid/cpp/src/tests/IncompleteMessageList.cpp17
-rw-r--r--qpid/cpp/src/tests/InlineAllocator.cpp13
-rw-r--r--qpid/cpp/src/tests/InlineVector.cpp11
-rw-r--r--qpid/cpp/src/tests/Makefile.am5
-rw-r--r--qpid/cpp/src/tests/ManagementTest.cpp9
-rw-r--r--qpid/cpp/src/tests/MessageBuilderTest.cpp46
-rw-r--r--qpid/cpp/src/tests/MessageReplayTracker.cpp21
-rw-r--r--qpid/cpp/src/tests/MessageTest.cpp12
-rw-r--r--qpid/cpp/src/tests/MessageUtils.h13
-rw-r--r--qpid/cpp/src/tests/MessagingSessionTests.cpp152
-rw-r--r--qpid/cpp/src/tests/PartialFailure.cpp5
-rw-r--r--qpid/cpp/src/tests/PollableCondition.cpp18
-rw-r--r--qpid/cpp/src/tests/ProxyTest.cpp11
-rw-r--r--qpid/cpp/src/tests/QueueEvents.cpp17
-rw-r--r--qpid/cpp/src/tests/QueueOptionsTest.cpp27
-rw-r--r--qpid/cpp/src/tests/QueuePolicyTest.cpp45
-rw-r--r--qpid/cpp/src/tests/QueueRegistryTest.cpp17
-rw-r--r--qpid/cpp/src/tests/QueueTest.cpp165
-rw-r--r--qpid/cpp/src/tests/RangeSet.cpp9
-rw-r--r--qpid/cpp/src/tests/RateFlowcontrolTest.cpp19
-rw-r--r--qpid/cpp/src/tests/RefCounted.cpp5
-rw-r--r--qpid/cpp/src/tests/ReplicationTest.cpp13
-rw-r--r--qpid/cpp/src/tests/RetryList.cpp15
-rw-r--r--qpid/cpp/src/tests/SequenceNumberTest.cpp12
-rw-r--r--qpid/cpp/src/tests/SequenceSet.cpp9
-rw-r--r--qpid/cpp/src/tests/SessionState.cpp19
-rw-r--r--qpid/cpp/src/tests/Shlib.cpp9
-rw-r--r--qpid/cpp/src/tests/SocketProxy.h13
-rw-r--r--qpid/cpp/src/tests/TestMessageStore.h13
-rw-r--r--qpid/cpp/src/tests/TestOptions.h6
-rw-r--r--qpid/cpp/src/tests/TimerTest.cpp19
-rw-r--r--qpid/cpp/src/tests/TopicExchangeTest.cpp22
-rw-r--r--qpid/cpp/src/tests/TxBufferTest.cpp9
-rw-r--r--qpid/cpp/src/tests/TxMocks.h49
-rw-r--r--qpid/cpp/src/tests/TxPublishTest.cpp23
-rw-r--r--qpid/cpp/src/tests/Url.cpp5
-rw-r--r--qpid/cpp/src/tests/Uuid.cpp5
-rw-r--r--qpid/cpp/src/tests/Variant.cpp43
-rw-r--r--qpid/cpp/src/tests/XmlClientSessionTest.cpp18
-rwxr-xr-xqpid/cpp/src/tests/acl.py400
-rw-r--r--qpid/cpp/src/tests/client_test.cpp21
-rw-r--r--qpid/cpp/src/tests/cluster_python_tests_failing.txt1
-rw-r--r--qpid/cpp/src/tests/cluster_test.cpp9
-rw-r--r--qpid/cpp/src/tests/consume.cpp21
-rw-r--r--qpid/cpp/src/tests/datagen.cpp19
-rw-r--r--qpid/cpp/src/tests/echotest.cpp21
-rw-r--r--qpid/cpp/src/tests/exception_test.cpp17
-rw-r--r--qpid/cpp/src/tests/failover_soak.cpp124
-rwxr-xr-xqpid/cpp/src/tests/federation.py23
-rw-r--r--qpid/cpp/src/tests/latencytest.cpp55
-rw-r--r--qpid/cpp/src/tests/logging.cpp31
-rw-r--r--qpid/cpp/src/tests/perftest.cpp77
-rw-r--r--qpid/cpp/src/tests/publish.cpp21
-rw-r--r--qpid/cpp/src/tests/qpid_ping.cpp12
-rw-r--r--qpid/cpp/src/tests/qpid_stream.cpp163
-rw-r--r--qpid/cpp/src/tests/qrsh.cpp37
-rw-r--r--qpid/cpp/src/tests/qrsh_server.cpp127
-rw-r--r--qpid/cpp/src/tests/receiver.cpp26
-rw-r--r--qpid/cpp/src/tests/replaying_sender.cpp39
-rw-r--r--qpid/cpp/src/tests/resuming_receiver.cpp45
-rw-r--r--qpid/cpp/src/tests/sender.cpp34
-rw-r--r--qpid/cpp/src/tests/shlibtest.cpp6
-rw-r--r--qpid/cpp/src/tests/test_store.cpp15
-rw-r--r--qpid/cpp/src/tests/test_tools.h6
-rw-r--r--qpid/cpp/src/tests/topic_listener.cpp105
-rw-r--r--qpid/cpp/src/tests/topic_publisher.cpp135
-rw-r--r--qpid/cpp/src/tests/txjob.cpp17
-rw-r--r--qpid/cpp/src/tests/txshift.cpp27
-rw-r--r--qpid/cpp/src/tests/txtest.cpp62
-rw-r--r--qpid/cpp/src/windows/QpiddBroker.cpp9
-rwxr-xr-xqpid/java/broker/bin/qpid-passwd70
-rwxr-xr-xqpid/java/broker/bin/qpid-server9
-rw-r--r--qpid/java/broker/etc/config-systests-derby.xml141
-rw-r--r--qpid/java/broker/etc/config-systests.xml143
-rw-r--r--qpid/java/broker/etc/config.xml132
-rw-r--r--qpid/java/broker/etc/log4j.xml2
-rw-r--r--qpid/java/broker/etc/virtualhosts-systests.xml124
-rw-r--r--qpid/java/broker/etc/virtualhosts.xml123
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java35
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java12
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java55
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java13
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java5
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java51
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java24
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java91
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java54
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java19
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java2
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java11
-rw-r--r--qpid/java/doc/broker-priority-queue-subscription.diabin0 -> 2991 bytes
-rw-r--r--qpid/java/doc/broker-queue-subscription.diabin0 -> 2129 bytes
-rw-r--r--qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml (renamed from qpid/java/broker/etc/persistent_config-config-test.xml)2
-rw-r--r--qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml (renamed from qpid/java/broker/etc/sample-parsed-config.xml)2
-rw-r--r--qpid/java/systests/etc/config-systests-acl-settings.xml (renamed from qpid/java/broker/etc/acl.config.xml)91
-rw-r--r--qpid/java/systests/etc/config-systests-acl.xml30
-rw-r--r--qpid/java/systests/etc/config-systests-derby-settings.xml64
-rw-r--r--qpid/java/systests/etc/config-systests-derby.xml30
-rw-r--r--qpid/java/systests/etc/config-systests-settings.xml29
-rw-r--r--qpid/java/systests/etc/config-systests.xml29
-rw-r--r--qpid/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml (renamed from qpid/java/broker/etc/virtualhosts-config-test.xml)0
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java515
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java14
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java43
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java12
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java79
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java8
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java299
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java157
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java330
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java21
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java306
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java88
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java119
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java208
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java137
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java12
-rw-r--r--qpid/java/test-profiles/010Excludes9
-rw-r--r--qpid/java/test-profiles/08Excludes5
-rw-r--r--qpid/java/test-profiles/Excludes6
-rw-r--r--qpid/java/test-profiles/cpp.testprofile1
-rw-r--r--qpid/java/test-profiles/default.testprofile5
-rw-r--r--qpid/python/Makefile6
-rw-r--r--qpid/python/qpid/concurrency.py65
-rw-r--r--qpid/python/qpid/datatypes.py18
-rw-r--r--qpid/python/qpid/delegates.py8
-rw-r--r--qpid/python/qpid/driver.py444
-rw-r--r--qpid/python/qpid/messaging.py692
-rw-r--r--qpid/python/qpid/ops.py5
-rw-r--r--qpid/python/qpid/tests/messaging.py92
-rw-r--r--qpid/python/qpid/util.py6
-rw-r--r--qpid/python/tests/datatypes.py28
-rw-r--r--qpid/python/tests_0-10/alternate_exchange.py56
-rw-r--r--qpid/python/tests_0-10/management.py22
-rw-r--r--qpid/specs/management-schema.xml2
-rw-r--r--qpid/wcf/QpidWcf.sln114
-rw-r--r--qpid/wcf/ReadMe.txt162
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs68
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj90
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs83
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj85
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln46
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs67
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj90
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs85
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj84
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs68
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj90
-rw-r--r--qpid/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln52
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs57
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs57
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs292
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs91
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs33
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj153
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs57
-rwxr-xr-xqpid/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat19
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs55
-rw-r--r--qpid/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs35
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs60
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs29
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs79
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs115
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs29
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs258
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs98
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs142
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs174
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs145
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs592
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/Channel.csproj102
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs266
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs52
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawMessage.cs374
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs113
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs45
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs102
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs353
-rw-r--r--qpid/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs221
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp165
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.h71
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp76
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.h61
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp287
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h80
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp57
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp145
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h99
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp685
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/InputLink.h85
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj302
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp337
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h131
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp251
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h127
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/OutputLink.cpp251
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/OutputLink.h64
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/QpidException.h37
-rw-r--r--qpid/wcf/src/Apache/Qpid/Interop/QpidMarshal.h53
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs190
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs77
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj110
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs30
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs31
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs34
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs34
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs33
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs135
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs101
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt22
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs131
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs158
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs83
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs55
-rwxr-xr-xqpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat34
-rw-r--r--qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs74
-rw-r--r--qpid/wcf/tools/QCreate/QCreate.cpp65
-rw-r--r--qpid/wcf/tools/QCreate/QCreate.sln40
-rw-r--r--qpid/wcf/tools/QCreate/QCreate.vcproj232
-rw-r--r--qpid/wcf/tools/QCreate/ReadMe.txt52
-rw-r--r--qpid/wcf/tools/QCreate/stdafx.cpp27
-rw-r--r--qpid/wcf/tools/QCreate/stdafx.h34
-rw-r--r--qpid/wcf/tools/QCreate/targetver.h32
383 files changed, 22999 insertions, 5767 deletions
diff --git a/qpid/cpp/bindings/qmf/Makefile.am b/qpid/cpp/bindings/qmf/Makefile.am
index 68312a4208..eebb4b94de 100644
--- a/qpid/cpp/bindings/qmf/Makefile.am
+++ b/qpid/cpp/bindings/qmf/Makefile.am
@@ -20,6 +20,14 @@
if HAVE_SWIG
EXTRA_DIST = qmfengine.i
-SUBDIRS = ruby tests
+SUBDIRS = tests
+
+if HAVE_RUBY_DEVEL
+SUBDIRS += ruby
+endif
+
+if HAVE_PYTHON_DEVEL
+SUBDIRS += python
+endif
endif
diff --git a/qpid/cpp/bindings/qmf/python/Makefile.am b/qpid/cpp/bindings/qmf/python/Makefile.am
index 7b3f4d3be7..55d9079fb7 100644
--- a/qpid/cpp/bindings/qmf/python/Makefile.am
+++ b/qpid/cpp/bindings/qmf/python/Makefile.am
@@ -29,17 +29,18 @@ EXTRA_DIST = python.i
BUILT_SOURCES = $(generated_file_list)
$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmfengine.i
- swig -python -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp $(srcdir)/python.i
+ swig -c++ -python -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp $(srcdir)/python.i
pylibdir = $(PYTHON_LIB)
lib_LTLIBRARIES = _qmfengine.la
-_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
-_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfcommon.la
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so"
+_qmfengine_la_LDFLAGS = -avoid-version -module -shared
+_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfagent.la
_qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC)
-_qmfengine_la_SOURCES = \
- qmfengine.cpp
+nodist__qmfengine_la_SOURCES = qmfengine.cpp
CLEANFILES = $(generated_file_list)
diff --git a/qpid/cpp/bindings/qmf/python/python.i b/qpid/cpp/bindings/qmf/python/python.i
index ea14efd4dd..5e25d155f9 100644
--- a/qpid/cpp/bindings/qmf/python/python.i
+++ b/qpid/cpp/bindings/qmf/python/python.i
@@ -19,17 +19,125 @@
%module qmfengine
-// These are probably wrong.. just to get it to compile for now.
-%typemap (in) void *
-{
- $1 = (void *) $input;
+
+/* unsigned32 Convert from Python --> C */
+%typemap(in) uint32_t {
+ if (PyInt_Check($input)) {
+ $1 = (uint32_t) PyInt_AsUnsignedLongMask($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (uint32_t) PyLong_AsUnsignedLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* unsinged32 Convert from C --> Python */
+%typemap(out) uint32_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* unsigned16 Convert from Python --> C */
+%typemap(in) uint16_t {
+ if (PyInt_Check($input)) {
+ $1 = (uint16_t) PyInt_AsUnsignedLongMask($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (uint16_t) PyLong_AsUnsignedLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* unsigned16 Convert from C --> Python */
+%typemap(out) uint16_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* signed32 Convert from Python --> C */
+%typemap(in) int32_t {
+ if (PyInt_Check($input)) {
+ $1 = (int32_t) PyInt_AsLong($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (int32_t) PyLong_AsLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* signed32 Convert from C --> Python */
+%typemap(out) int32_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* unsigned64 Convert from Python --> C */
+%typemap(in) uint64_t {
+%#ifdef HAVE_LONG_LONG
+ if (PyLong_Check($input)) {
+ $1 = (uint64_t)PyLong_AsUnsignedLongLong($input);
+ } else if (PyInt_Check($input)) {
+ $1 = (uint64_t)PyInt_AsUnsignedLongLongMask($input);
+ } else
+%#endif
+ {
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t input too large");
+ }
+}
+
+/* unsigned64 Convert from C --> Python */
+%typemap(out) uint64_t {
+%#ifdef HAVE_LONG_LONG
+ $result = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)$1);
+%#else
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t output too large");
+%#endif
+}
+
+/* signed64 Convert from Python --> C */
+%typemap(in) int64_t {
+%#ifdef HAVE_LONG_LONG
+ if (PyLong_Check($input)) {
+ $1 = (int64_t)PyLong_AsLongLong($input);
+ } else if (PyInt_Check($input)) {
+ $1 = (int64_t)PyInt_AsLong($input);
+ } else
+%#endif
+ {
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t input too large");
+ }
+}
+
+/* signed64 Convert from C --> Python */
+%typemap(out) int64_t {
+%#ifdef HAVE_LONG_LONG
+ $result = PyLong_FromLongLong((PY_LONG_LONG)$1);
+%#else
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t output too large");
+%#endif
}
-%typemap (out) void *
-{
+
+/* Convert from Python --> C */
+%typemap(in) void * {
+ $1 = (void *)$input;
+}
+
+/* Convert from C --> Python */
+%typemap(out) void * {
$result = (PyObject *) $1;
+ Py_INCREF($result);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT64) uint64_t {
+ $1 = PyLong_Check($input) ? 1 : 0;
}
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT32) uint32_t {
+ $1 = PyInt_Check($input) ? 1 : 0;
+}
+
+
%include "../qmfengine.i"
diff --git a/qpid/cpp/bindings/qmf/python/qmf.py b/qpid/cpp/bindings/qmf/python/qmf.py
new file mode 100644
index 0000000000..4800b327f1
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/python/qmf.py
@@ -0,0 +1,858 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import sys
+import socket
+import os
+from threading import Thread
+from threading import RLock
+import qmfengine
+from qmfengine import (ACCESS_READ_CREATE, ACCESS_READ_ONLY, ACCESS_READ_WRITE)
+from qmfengine import (CLASS_EVENT, CLASS_OBJECT)
+from qmfengine import (DIR_IN, DIR_IN_OUT, DIR_OUT)
+from qmfengine import (TYPE_ABSTIME, TYPE_ARRAY, TYPE_BOOL, TYPE_DELTATIME,
+ TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT16, TYPE_INT32, TYPE_INT64,
+ TYPE_INT8, TYPE_LIST, TYPE_LSTR, TYPE_MAP, TYPE_OBJECT,
+ TYPE_REF, TYPE_SSTR, TYPE_UINT16, TYPE_UINT32, TYPE_UINT64,
+ TYPE_UINT8, TYPE_UUID)
+from qmfengine import (O_EQ, O_NE, O_LT, O_LE, O_GT, O_GE, O_RE_MATCH, O_RE_NOMATCH,
+ E_NOT, E_AND, E_OR, E_XOR)
+
+
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
+
+class ConnectionSettings:
+ #attr_reader :impl
+ def __init__(self, url=None):
+ if url:
+ self.impl = qmfengine.ConnectionSettings(url)
+ else:
+ self.impl = qmfengine.ConnectionSettings()
+
+
+ def set_attr(self, key, val):
+ if type(val) == str:
+ _v = qmfengine.Value(TYPE_LSTR)
+ _v.setString(val)
+ elif type(val) == bool:
+ _v = qmfengine.Value(TYPE_BOOL)
+ _v.setBool(val)
+ elif type(val) == int:
+ _v = qmfengine.Value(TYPE_UINT32)
+ _v.setUint(val)
+ else:
+ raise ArgumentError("Value for attribute '%s' has unsupported type: %s" % ( key, type(val)))
+
+ self.impl.setAttr(key, _v)
+
+
+
+class ConnectionHandler:
+ def conn_event_connected(self): None
+ def conn_event_disconnected(self, error): None
+ def sess_event_session_closed(self, context, error): None
+ def sess_event_recv(self, context, message): None
+
+
+
+class Connection(Thread):
+ def __init__(self, settings):
+ Thread.__init__(self)
+ self._lock = RLock()
+ self.impl = qmfengine.ResilientConnection(settings.impl)
+ self._sockEngine, self._sock = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.impl.setNotifyFd(self._sockEngine.fileno())
+ self._new_conn_handlers = []
+ self._conn_handlers = []
+ self.start()
+
+
+ def add_conn_handler(self, handler):
+ self._lock.acquire()
+ try:
+ self._new_conn_handlers.append(handler)
+ finally:
+ self._lock.release()
+ self._sockEngine.send("x")
+
+
+ def run(self):
+ eventImpl = qmfengine.ResilientConnectionEvent()
+ connected = False
+ new_handlers = []
+ bt_count = 0
+
+ while True:
+ # print "Waiting for socket data"
+ self._sock.recv(1)
+
+ self._lock.acquire()
+ try:
+ new_handlers = self._new_conn_handlers
+ self._new_conn_handlers = []
+ finally:
+ self._lock.release()
+
+ for nh in new_handlers:
+ self._conn_handlers.append(nh)
+ if connected:
+ nh.conn_event_connected()
+
+ new_handlers = []
+
+ valid = self.impl.getEvent(eventImpl)
+ while valid:
+ try:
+ if eventImpl.kind == qmfengine.ResilientConnectionEvent.CONNECTED:
+ connected = True
+ for h in self._conn_handlers:
+ h.conn_event_connected()
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.DISCONNECTED:
+ connected = False
+ for h in self._conn_handlers:
+ h.conn_event_disconnected(eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.SESSION_CLOSED:
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.RECV:
+ eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message)
+
+ except:
+ import traceback
+ print "Event Exception:", sys.exc_info()
+ if bt_count < 2:
+ traceback.print_exc()
+ traceback.print_stack()
+ bt_count += 1
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(eventImpl)
+
+
+
+class Session:
+ def __init__(self, conn, label, handler):
+ self._conn = conn
+ self._label = label
+ self.handler = handler
+ self.handle = qmfengine.SessionHandle()
+ result = self._conn.impl.createSession(label, self, self.handle)
+
+
+ def __del__(self):
+ self._conn.impl.destroySession(self.handle)
+
+
+
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
+
+class QmfObject:
+ # attr_reader :impl, :object_class
+ def __init__(self, cls):
+ self.object_class = cls
+ self.impl = qmfengine.Object(self.object_class.impl)
+
+
+ def __del__(self):
+ self.impl.destroy()
+
+
+ def object_id(self):
+ return ObjectId(self.impl.getObjectId())
+
+
+ def set_object_id(self, oid):
+ self.impl.setObjectId(oid.impl)
+
+
+ def get_attr(self, name):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return val.asObjectId()
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported type for get_attr?", val.getType()
+ return None
+
+
+ def set_attr(self, name, v):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(v)
+ elif vType == TYPE_UINT16: return val.setUint(v)
+ elif vType == TYPE_UINT32: return val.setUint(v)
+ elif vType == TYPE_UINT64: return val.setUint64(v)
+ elif vType == TYPE_SSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_LSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(v)
+ elif vType == TYPE_DELTATIME: return val.setUint64(v)
+ elif vType == TYPE_REF: return val.setObjectId(v.impl)
+ elif vType == TYPE_BOOL: return val.setBool(v)
+ elif vType == TYPE_FLOAT: return val.setFloat(v)
+ elif vType == TYPE_DOUBLE: return val.setDouble(v)
+ elif vType == TYPE_UUID: return val.setUuid(v)
+ elif vType == TYPE_INT8: return val.setInt(v)
+ elif vType == TYPE_INT16: return val.setInt(v)
+ elif vType == TYPE_INT32: return val.setInt(v)
+ elif vType == TYPE_INT64: return val.setInt64(v)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported type for get_attr?", val.getType()
+ return None
+
+
+ def __getitem__(self, name):
+ return self.get_attr(name)
+
+
+ def __setitem__(self, name, value):
+ self.set_attr(name, value)
+
+
+ def inc_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) + by)
+
+
+ def dec_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) - by)
+
+
+ def _value(self, name):
+ val = self.impl.getValue(name)
+ if not val:
+ raise ArgumentError("Attribute '%s' not defined for class %s" % (name, self.object_class.impl.getName()))
+ return val
+
+
+
+class ConsoleObject(QmfObject):
+ # attr_reader :current_time, :create_time, :delete_time
+ def __init__(self, cls):
+ QmfObject.__init__(self, cls)
+
+
+ def update(self): pass
+ def mergeUpdate(self, newObject): pass
+ def is_deleted(self):
+ return self.delete_time > 0
+ def index(self): pass
+ def method_missing(self, name, *args): pass
+
+
+
+class ObjectId:
+ def __init__(self, impl=None):
+ if impl:
+ self.impl = impl
+ else:
+ self.impl = qmfengine.ObjectId()
+
+
+ def object_num_high(self):
+ return self.impl.getObjectNumHi()
+
+
+ def object_num_low(self):
+ return self.impl.getObjectNumLo()
+
+
+ def __eq__(self, other):
+ if self.__class__ != other.__class__: return False
+ return (self.impl.getObjectNumHi() == other.impl.getObjectNumHi() and
+ self.impl.getObjectNumLo() == other.impl.getObjectNumLo())
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+
+class Arguments:
+ def __init__(self, map):
+ self.map = map
+ self._by_hash = {}
+ key_count = self.map.keyCount()
+ a = 0
+ while a < key_count:
+ self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a))
+ a += 1
+
+
+ def __getitem__(self, key):
+ return self._by_hash[key]
+
+
+ def __setitem__(self, key, value):
+ self._by_hash[key] = value
+ self.set(key, value)
+
+
+ def __iter__(self):
+ return _by_hash.__iter__
+
+
+ def by_key(self, key):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return val.asObjectId()
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported Type for Get?", val.getType()
+ return None
+
+
+ def set(self, key, value):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(value)
+ elif vType == TYPE_UINT16: return val.setUint(value)
+ elif vType == TYPE_UINT32: return val.setUint(value)
+ elif vType == TYPE_UINT64: return val.setUint64(value)
+ elif vType == TYPE_SSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_LSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(value)
+ elif vType == TYPE_DELTATIME: return val.setUint64(value)
+ elif vType == TYPE_REF: return val.setObjectId(value.impl)
+ elif vType == TYPE_BOOL: return val.setBool(value)
+ elif vType == TYPE_FLOAT: return val.setFloat(value)
+ elif vType == TYPE_DOUBLE: return val.setDouble(value)
+ elif vType == TYPE_UUID: return val.setUuid(value)
+ elif vType == TYPE_INT8: return val.setInt(value)
+ elif vType == TYPE_INT16: return val.setInt(value)
+ elif vType == TYPE_INT32: return val.setInt(value)
+ elif vType == TYPE_INT64: return val.setInt64(value)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported Type for Set?", val.getType()
+ return None
+
+
+
+class Query:
+ def __init__(self, i=None, package="", cls=None, oid=None):
+ if i:
+ self.impl = i
+ else:
+ if cls:
+ self.impl = qmfengine.Query(cls, package)
+ elif oid:
+ self.impl = qmfengine.Query(oid)
+ else:
+ raise "Argument error"
+
+
+ def package_name(self): return self.impl.getPackage()
+ def class_name(self): return self.impl.getClass()
+ def object_id(self):
+ _objid = self.impl.getObjectId()
+ if _objid:
+ return ObjectId(_objid)
+ else:
+ return None
+
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+
+
+class SchemaArgument:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaArgument(name, typecode)
+ if kwargs.has_key("dir"): self.impl.setDirection(kwargs["dir"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+
+class SchemaMethod:
+ # attr_reader :impl
+ def __init__(self, name, kwargs={}):
+ self.impl = qmfengine.SchemaMethod(name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+ self._arguments = []
+
+
+ def add_argument(self, arg):
+ self._arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+
+class SchemaProperty:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaProperty(name, typecode)
+ if kwargs.has_key("access"): self.impl.setAccess(kwargs["access"])
+ if kwargs.has_key("index"): self.impl.setIndex(kwargs["index"])
+ if kwargs.has_key("optional"): self.impl.setOptional(kwargs["optional"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def name(self):
+ return self.impl.getName()
+
+
+
+class SchemaStatistic:
+ # attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaStatistic(name, typecode)
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+
+class SchemaClassKey:
+ #attr_reader :impl
+ def __init__(self, i):
+ self.impl = i
+
+
+ def get_package(self):
+ self.impl.getPackageName()
+
+
+ def get_class(self):
+ self.impl.getClassName()
+
+
+
+class SchemaObjectClass:
+ # attr_reader :impl
+ def __init__(self, package, name, kwargs={}):
+ self.impl = qmfengine.SchemaObjectClass(package, name)
+ self._properties = []
+ self._statistics = []
+ self._methods = []
+
+
+ def add_property(self, prop):
+ self._properties.append(prop)
+ self.impl.addProperty(prop.impl)
+
+
+ def add_statistic(self, stat):
+ self._statistics.append(stat)
+ self.impl.addStatistic(stat.impl)
+
+
+ def add_method(self, meth):
+ self._methods.append(meth)
+ self.impl.addMethod(meth.impl)
+
+
+ def name(self):
+ return self.impl.getName()
+
+
+ def properties(self):
+ return self._properties
+
+
+class SchemaEventClass:
+ # attr_reader :impl
+ def __init__(self, package, name, kwargs={}):
+ self.impl = qmfengine.SchemaEventClass(package, name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+ self._arguments = []
+
+
+ def add_argument(self, arg):
+ self._arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+
+
+class ConsoleHandler:
+ def agent_added(self, agent): pass
+ def agent_deleted(self, agent): pass
+ def new_package(self, package): pass
+ def new_class(self, class_key): pass
+ def object_update(self, obj, hasProps, hasStats): pass
+ def event_received(self, event): pass
+ def agent_heartbeat(self, agent, timestamp): pass
+ def method_response(self, resp): pass
+ def broker_info(self, broker): pass
+
+
+
+class Console:
+ # attr_reader :impl
+ def initialize(handler=None, kwargs={}):
+ self._handler = handler
+ self.impl = qmfengine.ConsoleEngine()
+ self._event = qmfengine.ConsoleEvent()
+ self._broker_list = []
+
+
+ def add_connection(self, conn):
+ broker = Broker(self, conn)
+ self._broker_list.append(broker)
+ return broker
+
+
+ def del_connection(self, broker): pass
+
+
+ def get_packages(self): pass
+
+
+ def get_classes(self, package): pass
+
+
+ def get_schema(self, class_key): pass
+
+
+ def bind_package(self, package): pass
+
+
+ def bind_class(self, kwargs = {}): pass
+
+
+ def get_agents(self, broker=None): pass
+
+
+ def get_objects(self, query, kwargs = {}): pass
+
+
+ def start_sync(self, query): pass
+
+
+ def touch_sync(self, sync): pass
+
+
+ def end_sync(self, sync): pass
+
+
+ def do_console_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ print "Console Event:", self._event.kind
+ if self._event.kind == qmfengine.ConsoleEvent.AGENT_ADDED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_DELETED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_PACKAGE:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_CLASS:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.OBJECT_UPDATE:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.EVENT_RECEIVED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_HEARTBEAT:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.METHOD_RESPONSE:
+ pass
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+
+class Broker(ConnectionHandler):
+ # attr_reader :impl
+ def __init__(self, console, conn):
+ self._console = console
+ self._conn = conn
+ self._session = None
+ self._event = qmfengine.BrokerEvent()
+ self._xmtMessage = qmfengine.Message()
+ self.impl = qmfengine.BrokerProxy(self._console.impl)
+ self._console.impl.addConnection(self.impl, self)
+ self._conn.add_conn_handler(self)
+
+
+ def do_broker_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ print "Broker Event: ", self._event.kind
+ if self._event.kind == qmfengine.BrokerEvent.BROKER_INFO:
+ pass
+ elif self._event.kind == qmfengine.BrokerEvent.DECLARE_QUEUE:
+ self._conn.impl.declareQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.DELETE_QUEUE:
+ self._conn.impl.deleteQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.BIND:
+ self._conn.impl.bind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.UNBIND:
+ self._conn.impl.unbind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.SETUP_COMPLETE:
+ self.impl.startProtocol()
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+
+ return count
+
+
+ def do_broker_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ self._conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+
+ return count
+
+
+ def do_events(self):
+ while True:
+ ccnt = self._console.do_console_events()
+ bcnt = do_broker_events()
+ mcnt = do_broker_messages()
+ if ccnt == 0 and bcnt == 0 and mcnt == 0:
+ break;
+
+
+ def conn_event_connected(self):
+ print "Console Connection Established..."
+ self._session = Session(self._conn, "qmfc-%s.%d" % (socket.gethostname(), os.getpid()), self)
+ self.impl.sessionOpened(self._session.handle)
+ self.do_events()
+
+
+ def conn_event_disconnected(self, error):
+ print "Console Connection Lost"
+ pass
+
+
+ def sess_event_session_closed(self, context, error):
+ print "Console Session Lost"
+ self.impl.sessionClosed()
+
+
+ def sess_event_recv(self, context, message):
+ self.impl.handleRcvMessage(message)
+ self.do_events()
+
+
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+
+
+class AgentHandler:
+ def get_query(self, context, query, userId): None
+ def method_call(self, context, name, object_id, args, userId): None
+
+
+
+class Agent(ConnectionHandler):
+ def __init__(self, handler, label=""):
+ if label == "":
+ self._agentLabel = "rb-%s.%d" % (socket.gethostname(), os.getpid())
+ else:
+ self._agentLabel = label
+ self._conn = None
+ self._handler = handler
+ self.impl = qmfengine.AgentEngine(self._agentLabel)
+ self._event = qmfengine.AgentEvent()
+ self._xmtMessage = qmfengine.Message()
+
+
+ def set_connection(self, conn):
+ self._conn = conn
+ self._conn.add_conn_handler(self)
+
+
+ def register_class(self, cls):
+ self.impl.registerClass(cls.impl)
+
+
+ def alloc_object_id(self, low = 0, high = 0):
+ return ObjectId(self.impl.allocObjectId(low, high))
+
+
+ def query_response(self, context, obj):
+ self.impl.queryResponse(context, obj.impl)
+
+
+ def query_complete(self, context):
+ self.impl.queryComplete(context)
+
+
+ def method_response(self, context, status, text, arguments):
+ self.impl.methodResponse(context, status, text, arguments.map)
+
+
+ def do_agent_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ if self._event.kind == qmfengine.AgentEvent.GET_QUERY:
+ self._handler.get_query(self._event.sequence,
+ Query(self._event.query),
+ self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.START_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.END_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.METHOD_CALL:
+ args = Arguments(self._event.arguments)
+ self._handler.method_call(self._event.sequence, self._event.name,
+ ObjectId(self._event.objectId),
+ args, self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.DECLARE_QUEUE:
+ self._conn.impl.declareQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.DELETE_QUEUE:
+ self._conn.impl.deleteQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.BIND:
+ self._conn.impl.bind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.UNBIND:
+ self._conn.impl.unbind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.SETUP_COMPLETE:
+ self.impl.startProtocol()
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+ def do_agent_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ self._conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ return count
+
+
+ def do_events(self):
+ while True:
+ ecnt = self.do_agent_events()
+ mcnt = self.do_agent_messages()
+ if ecnt == 0 and mcnt == 0:
+ break
+
+
+ def conn_event_connected(self):
+ print "Agent Connection Established..."
+ self._session = Session(self._conn,
+ "qmfa-%s.%d" % (socket.gethostname(), os.getpid()),
+ self)
+ self.impl.newSession()
+ self.do_events()
+
+
+ def conn_event_disconnected(self, error):
+ print "Agent Connection Lost"
+ pass
+
+
+ def sess_event_session_closed(self, context, error):
+ print "Agent Session Lost"
+ pass
+
+
+ def sess_event_recv(self, context, message):
+ self.impl.handleRcvMessage(message)
+ self.do_events()
+
+
diff --git a/qpid/cpp/bindings/qmf/qmfengine.i b/qpid/cpp/bindings/qmf/qmfengine.i
index 8ae28730e5..d3500c9b8f 100644
--- a/qpid/cpp/bindings/qmf/qmfengine.i
+++ b/qpid/cpp/bindings/qmf/qmfengine.i
@@ -20,7 +20,8 @@
%{
#include "qmf/AgentEngine.h"
-#include <qmf/ResilientConnection.h>
+#include "qmf/ConsoleEngine.h"
+#include "qmf/ResilientConnection.h"
%}
@@ -28,6 +29,7 @@
%include <qmf/Query.h>
%include <qmf/Message.h>
%include <qmf/AgentEngine.h>
+%include <qmf/ConsoleEngine.h>
%include <qmf/ConnectionSettings.h>
%include <qmf/ResilientConnection.h>
%include <qmf/Typecode.h>
diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb
index 79b18423db..12741b45f2 100644
--- a/qpid/cpp/bindings/qmf/ruby/qmf.rb
+++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb
@@ -20,364 +20,565 @@
require 'qmfengine'
require 'thread'
require 'socket'
+require 'monitor'
module Qmf
- # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
- Qmfengine.constants.each do |c|
- if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0
- const_set(c, Qmfengine.const_get(c))
- end
+ # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
+ Qmfengine.constants.each do |c|
+ if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0 or c.index('CLASS_') == 0
+ const_set(c, Qmfengine.const_get(c))
end
+ end
- class ConnectionSettings
- attr_reader :impl
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
- def initialize(url = nil)
- if url
- @impl = Qmfengine::ConnectionSettings.new(url)
- else
- @impl = Qmfengine::ConnectionSettings.new()
- end
+ class ConnectionSettings
+ attr_reader :impl
+
+ def initialize(url = nil)
+ if url
+ @impl = Qmfengine::ConnectionSettings.new(url)
+ else
+ @impl = Qmfengine::ConnectionSettings.new()
end
+ end
- def set_attr(key, val)
- if val.class == String
- v = Qmfengine::Value.new(TYPE_LSTR)
- v.setString(val)
- elsif val.class == TrueClass or val.class == FalseClass
- v = Qmfengine::Value.new(TYPE_BOOL)
- v.setBool(val)
- elsif val.class == Fixnum
- v = Qmfengine::Value.new(TYPE_UINT32)
- v.setUint(val)
- else
- raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}"
- end
+ def set_attr(key, val)
+ if val.class == String
+ v = Qmfengine::Value.new(TYPE_LSTR)
+ v.setString(val)
+ elsif val.class == TrueClass or val.class == FalseClass
+ v = Qmfengine::Value.new(TYPE_BOOL)
+ v.setBool(val)
+ elsif val.class == Fixnum
+ v = Qmfengine::Value.new(TYPE_UINT32)
+ v.setUint(val)
+ else
+ raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}"
+ end
- @impl.setAttr(key, v)
+ @impl.setAttr(key, v)
+ end
+ end
+
+ class ConnectionHandler
+ def conn_event_connected(); end
+ def conn_event_disconnected(error); end
+ def conn_event_visit(); end
+ def sess_event_session_closed(context, error); end
+ def sess_event_recv(context, message); end
+ end
+
+ class Connection
+ include MonitorMixin
+
+ attr_reader :impl
+
+ def initialize(settings)
+ super()
+ @impl = Qmfengine::ResilientConnection.new(settings.impl)
+ @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
+ @impl.setNotifyFd(@sockEngine.fileno)
+ @new_conn_handlers = []
+ @conn_handlers_to_delete = []
+ @conn_handlers = []
+
+ @thread = Thread.new do
+ run
end
end
- class ConnectionHandler
- def conn_event_connected(); end
- def conn_event_disconnected(error); end
- def sess_event_session_closed(context, error); end
- def sess_event_recv(context, message); end
+ def kick
+ @sockEngine.write(".")
+ @sockEngine.flush
end
- class Query
- attr_reader :impl
- def initialize(i)
- @impl = i
+ def add_conn_handler(handler)
+ synchronize do
+ @new_conn_handlers << handler
end
+ kick
+ end
- def package_name
- @impl.getPackage
+ def del_conn_handler(handler)
+ synchronize do
+ @conn_handlers_to_delete << handler
end
+ kick
+ end
- def class_name
- @impl.getClass
- end
+ def run()
+ eventImpl = Qmfengine::ResilientConnectionEvent.new
+ connected = nil
+ new_handlers = nil
+ del_handlers = nil
+ bt_count = 0
+
+ while :true
+ @sock.read(1)
+
+ synchronize do
+ new_handlers = @new_conn_handlers
+ del_handlers = @conn_handlers_to_delete
+ @new_conn_handlers = []
+ @conn_handlers_to_delete = []
+ end
+
+ new_handlers.each do |nh|
+ @conn_handlers << nh
+ nh.conn_event_connected() if connected
+ end
+ new_handlers = nil
- def object_id
- objid = @impl.getObjectId
- if objid.class == NilClass
- return nil
+ del_handlers.each do |dh|
+ d = @conn_handlers.delete(dh)
end
- return ObjectId.new(objid)
+ del_handlers = nil
+
+ valid = @impl.getEvent(eventImpl)
+ while valid
+ begin
+ case eventImpl.kind
+ when Qmfengine::ResilientConnectionEvent::CONNECTED
+ connected = :true
+ @conn_handlers.each { |h| h.conn_event_connected() }
+ when Qmfengine::ResilientConnectionEvent::DISCONNECTED
+ connected = nil
+ @conn_handlers.each { |h| h.conn_event_disconnected(eventImpl.errorText) }
+ when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+ when Qmfengine::ResilientConnectionEvent::RECV
+ eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message)
+ end
+ rescue Exception => ex
+ puts "Event Exception: #{ex}"
+ if bt_count < 2
+ puts ex.backtrace
+ bt_count += 1
+ end
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(eventImpl)
+ end
+ @conn_handlers.each { |h| h.conn_event_visit }
end
end
+ end
- class Connection
- attr_reader :impl
+ class Session
+ attr_reader :handle, :handler
- def initialize(settings)
- @impl = Qmfengine::ResilientConnection.new(settings.impl)
- @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
- @impl.setNotifyFd(@sockEngine.fileno)
- @new_conn_handlers = Array.new
- @conn_handlers = Array.new
- @sess_handlers = Array.new
+ def initialize(conn, label, handler)
+ @conn = conn
+ @label = label
+ @handler = handler
+ @handle = Qmfengine::SessionHandle.new
+ result = @conn.impl.createSession(label, self, @handle)
+ end
- @thread = Thread.new do
- run
- end
+ def destroy()
+ @conn.impl.destroySession(@handle)
+ end
+ end
+
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
+
+ class QmfObject
+ include MonitorMixin
+ attr_reader :impl, :object_class
+ def initialize(cls, kwargs={})
+ super()
+ @cv = new_cond
+ @sync_count = 0
+ @sync_result = nil
+ @allow_sets = :false
+ @broker = kwargs[:broker] if kwargs.include?(:broker)
+
+ if cls:
+ @object_class = cls
+ @impl = Qmfengine::Object.new(@object_class.impl)
+ elsif kwargs.include?(:impl)
+ @impl = Qmfengine::Object.new(kwargs[:impl])
+ @object_class = SchemaObjectClass.new(nil, nil, :impl => @impl.getClass)
end
+ end
+
+ def object_id
+ return ObjectId.new(@impl.getObjectId)
+ end
- def add_conn_handler(handler)
- @new_conn_handlers.push(handler)
- @sockEngine.write("x")
+ def get_attr(name)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
- def add_sess_handler(handler)
- @sess_handlers.push(handler)
+ def set_attr(name, v)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v)
+ when TYPE_UINT64 then val.setUint64(v)
+ when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(v)
+ when TYPE_DELTATIME then val.setUint64(v)
+ when TYPE_REF then val.setObjectId(v.impl)
+ when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(v)
+ when TYPE_DOUBLE then val.setDouble(v)
+ when TYPE_UUID then val.setUuid(v)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v)
+ when TYPE_INT64 then val.setInt64(v)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
- def run()
- event = Qmfengine::ResilientConnectionEvent.new
- connected = nil
- while :true
- @sock.read(1)
+ def [](name)
+ get_attr(name)
+ end
- @new_conn_handlers.each do |nh|
- @conn_handlers.push(nh)
- nh.conn_event_connected() if connected
- end
- @new_conn_handlers = Array.new
-
- valid = @impl.getEvent(event)
- while valid
- begin
- case event.kind
- when Qmfengine::ResilientConnectionEvent::CONNECTED
- connected = :true
- @conn_handlers.each { |h| h.conn_event_connected() }
- when Qmfengine::ResilientConnectionEvent::DISCONNECTED
- connected = nil
- @conn_handlers.each { |h| h.conn_event_disconnected(event.errorText) }
- when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
- event.sessionContext.handler.sess_event_session_closed(event.sessionContext, event.errorText)
- when Qmfengine::ResilientConnectionEvent::RECV
- event.sessionContext.handler.sess_event_recv(event.sessionContext, event.message)
- end
- rescue Exception => ex
- puts "Event Exception: #{ex}"
- puts ex.backtrace
- end
- @impl.popEvent
- valid = @impl.getEvent(event)
- end
- end
- end
+ def []=(name, value)
+ set_attr(name, value)
end
- class Session
- attr_reader :handle, :handler
+ def inc_attr(name, by=1)
+ set_attr(name, get_attr(name) + by)
+ end
- def initialize(conn, label, handler)
- @conn = conn
- @label = label
- @handler = handler
- @handle = Qmfengine::SessionHandle.new
- @conn.add_sess_handler(@handler)
- result = @conn.impl.createSession(label, self, @handle)
- end
+ def dec_attr(name, by=1)
+ set_attr(name, get_attr(name) - by)
end
- class ObjectId
- attr_reader :impl
- def initialize(impl=nil)
- if impl
- @impl = impl
- else
- @impl = Qmfengine::ObjectId.new
+ def method_missing(name_in, *args)
+ #
+ # Convert the name to a string and determine if it represents an
+ # attribute assignment (i.e. "attr=")
+ #
+ name = name_in.to_s
+ attr_set = (name[name.length - 1] == 61)
+ name = name[0..name.length - 2] if attr_set
+ raise "Sets not permitted on this object" if attr_set && !@allow_sets
+
+ #
+ # If the name matches a property name, set or return the value of the property.
+ #
+ @object_class.properties.each do |prop|
+ if prop.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
end
end
- def object_num_high
- return @impl.getObjectNumHi
+ #
+ # Do the same for statistics
+ #
+ @object_class.statistics.each do |stat|
+ if stat.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
+ end
end
- def object_num_low
- return @impl.getObjectNumLo
+ #
+ # If we still haven't found a match for the name, check to see if
+ # it matches a method name. If so, marshall the arguments and invoke
+ # the method.
+ #
+ @object_class.methods.each do |method|
+ if method.name == name
+ raise "Sets not permitted on methods" if attr_set
+ timeout = 30
+ synchronize do
+ @sync_count = 1
+ @impl.invokeMethod(name, _marshall(method, args), self)
+ @broker.conn.kick if @broker
+ unless @cv.wait(timeout) { @sync_count == 0 }
+ raise "Timed out waiting for response"
+ end
+ end
+
+ return @sync_result
+ end
end
- def ==(other)
- return (@impl.getObjectNumHi == other.impl.getObjectNumHi) &&
- (@impl.getObjectNumLo == other.impl.getObjectNumLo)
+ #
+ # This name means nothing to us, pass it up the line to the parent
+ # class's handler.
+ #
+ super.method_missing(name_in, args)
+ end
+
+ def _method_result(result)
+ synchronize do
+ @sync_result = result
+ @sync_count -= 1
+ @cv.signal
end
end
- class Arguments
- attr_reader :map
- def initialize(map)
- @map = map
- @by_hash = {}
- key_count = @map.keyCount
- a = 0
- while a < key_count
- @by_hash[@map.key(a)] = by_key(@map.key(a))
- a += 1
+ #
+ # Convert a Ruby array of arguments (positional) into a Value object of type "map".
+ #
+ private
+ def _marshall(schema, args)
+ map = Qmfengine::Value.new(TYPE_MAP)
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ map.insert(arg.name, Qmfengine::Value.new(arg.typecode))
end
end
- def [] (key)
- return @by_hash[key]
+ marshalled = Arguments.new(map)
+ idx = 0
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ marshalled[arg.name] = args[idx] unless args[idx] == nil
+ idx += 1
+ end
end
- def []= (key, value)
- @by_hash[key] = value
- set(key, value)
- end
+ return marshalled.map
+ end
- def each
- @by_hash.each { |k, v| yield(k, v) }
+ private
+ def value(name)
+ val = @impl.getValue(name.to_s)
+ if val.nil?
+ raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getClassKey.getPackageName}:#{@object_class.impl.getClassKey.getClassName}"
end
+ return val
+ end
+ end
- def by_key(key)
- val = @map.byKey(key)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
- when TYPE_UINT64 then val.asUint64
- when TYPE_SSTR, TYPE_LSTR then val.asString
- when TYPE_ABSTIME then val.asInt64
- when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
- when TYPE_BOOL then val.asBool
- when TYPE_FLOAT then val.asFloat
- when TYPE_DOUBLE then val.asDouble
- when TYPE_UUID then val.asUuid
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
- when TYPE_INT64 then val.asInt64
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
- end
- end
+ class AgentObject < QmfObject
+ def initialize(cls, kwargs={})
+ super(cls, kwargs)
+ @allow_sets = :true
+ end
- def set(key, value)
- val = @map.byKey(key)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
- when TYPE_UINT64 then val.setUint64(value)
- when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
- when TYPE_ABSTIME then val.setInt64(value)
- when TYPE_DELTATIME then val.setUint64(value)
- when TYPE_REF then val.setObjectId(value.impl)
- when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
- when TYPE_FLOAT then val.setFloat(value)
- when TYPE_DOUBLE then val.setDouble(value)
- when TYPE_UUID then val.setUuid(value)
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
- when TYPE_INT64 then val.setInt64(value)
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
- end
- end
+ def destroy
+ @impl.destroy
end
- class AgentHandler
- def get_query(context, query, userId); end
- def method_call(context, name, object_id, args, userId); end
+ def set_object_id(oid)
+ @impl.setObjectId(oid.impl)
end
+ end
- class Agent < ConnectionHandler
- def initialize(handler, label="")
- if label == ""
- @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
- else
- @agentLabel = label
- end
- @conn = nil
- @handler = handler
- @impl = Qmfengine::AgentEngine.new(@agentLabel)
- @event = Qmfengine::AgentEvent.new
- @xmtMessage = Qmfengine::Message.new
- end
+ class ConsoleObject < QmfObject
+ attr_reader :current_time, :create_time, :delete_time
- def set_connection(conn)
- @conn = conn
- @conn.add_conn_handler(self)
- end
+ def initialize(cls, kwargs={})
+ super(cls, kwargs)
+ end
- def register_class(cls)
- @impl.registerClass(cls.impl)
- end
+ def update()
+ end
- def alloc_object_id(low = 0, high = 0)
- ObjectId.new(@impl.allocObjectId(low, high))
- end
+ def mergeUpdate(newObject)
+ end
- def query_response(context, object)
- @impl.queryResponse(context, object.impl)
- end
+ def deleted?()
+ @delete_time > 0
+ end
- def query_complete(context)
- @impl.queryComplete(context)
+ def index()
+ end
+ end
+
+ class ObjectId
+ attr_reader :impl
+ def initialize(impl=nil)
+ if impl
+ @impl = impl
+ else
+ @impl = Qmfengine::ObjectId.new
end
+ end
- def method_response(context, status, text, arguments)
- @impl.methodResponse(context, status, text, arguments.map)
- end
+ def object_num_high
+ return @impl.getObjectNumHi
+ end
- def do_agent_events()
- count = 0
- valid = @impl.getEvent(@event)
- while valid
- count += 1
- case @event.kind
- when Qmfengine::AgentEvent::GET_QUERY
- @handler.get_query(@event.sequence, Query.new(@event.query), @event.authUserId)
- when Qmfengine::AgentEvent::START_SYNC
- when Qmfengine::AgentEvent::END_SYNC
- when Qmfengine::AgentEvent::METHOD_CALL
- args = Arguments.new(@event.arguments)
- @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
- args, @event.authUserId)
- when Qmfengine::AgentEvent::DECLARE_QUEUE
- @conn.impl.declareQueue(@session.handle, @event.name)
- when Qmfengine::AgentEvent::DELETE_QUEUE
- @conn.impl.deleteQueue(@session.handle, @event.name)
- when Qmfengine::AgentEvent::BIND
- @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
- when Qmfengine::AgentEvent::UNBIND
- @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
- when Qmfengine::AgentEvent::SETUP_COMPLETE
- @impl.startProtocol()
- end
- @impl.popEvent
- valid = @impl.getEvent(@event)
- end
- return count
- end
+ def object_num_low
+ return @impl.getObjectNumLo
+ end
- def do_agent_messages()
- count = 0
- valid = @impl.getXmtMessage(@xmtMessage)
- while valid
- count += 1
- @conn.impl.sendMessage(@session.handle, @xmtMessage)
- @impl.popXmt
- valid = @impl.getXmtMessage(@xmtMessage)
- end
- return count
+ def ==(other)
+ return (@impl.getObjectNumHi == other.impl.getObjectNumHi) &&
+ (@impl.getObjectNumLo == other.impl.getObjectNumLo)
+ end
+ end
+
+ class Arguments
+ attr_reader :map
+ def initialize(map)
+ @map = map
+ @by_hash = {}
+ key_count = @map.keyCount
+ a = 0
+ while a < key_count
+ @by_hash[@map.key(a)] = by_key(@map.key(a))
+ a += 1
end
+ end
- def do_events()
- begin
- ecnt = do_agent_events
- mcnt = do_agent_messages
- end until ecnt == 0 and mcnt == 0
- end
+ def [] (key)
+ return @by_hash[key]
+ end
- def conn_event_connected()
- puts "Agent Connection Established..."
- @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self)
- @impl.newSession
- do_events
- end
+ def []= (key, value)
+ @by_hash[key] = value
+ set(key, value)
+ end
- def conn_event_disconnected(error)
- puts "Agent Connection Lost"
+ def each
+ @by_hash.each { |k, v| yield(k, v) }
+ end
+
+ def by_key(key)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
- def sess_event_session_closed(context, error)
- puts "Agent Session Lost"
+ def set(key, value)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
+ when TYPE_UINT64 then val.setUint64(value)
+ when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(value)
+ when TYPE_DELTATIME then val.setUint64(value)
+ when TYPE_REF then val.setObjectId(value.impl)
+ when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(value)
+ when TYPE_DOUBLE then val.setDouble(value)
+ when TYPE_UUID then val.setUuid(value)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
+ when TYPE_INT64 then val.setInt64(value)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
+ end
+
+ class MethodResponse
+ def initialize(impl)
+ puts "start copying..."
+ @impl = Qmfengine::MethodResponse.new(impl)
+ puts "done copying..."
+ end
+
+ def status
+ @impl.getStatus
+ end
- def sess_event_recv(context, message)
- @impl.handleRcvMessage(message)
- do_events
+ def exception
+ @impl.getException
+ end
+ end
+
+ ##==============================================================================
+ ## QUERY
+ ##==============================================================================
+
+ class Query
+ attr_reader :impl
+ def initialize(kwargs = {})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
+ package = ''
+ if kwargs.include?(:key)
+ @impl = Qmfengine::Query.new(kwargs[:key])
+ elsif kwargs.include?(:object_id)
+ @impl = Qmfengine::Query.new(kwargs[:object_id])
+ else
+ package = kwargs[:package] if kwargs.include?(:package)
+ if kwargs.include?(:class)
+ @impl = Qmfengine::Query.new(kwargs[:class], package)
+ else
+ raise ArgumentError, "Invalid arguments, use :key or :class[,:package]"
+ end
+ end
end
end
- class SchemaArgument
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
+ def package_name
+ @impl.getPackage
+ end
+
+ def class_name
+ @impl.getClass
+ end
+
+ def object_id
+ objid = @impl.getObjectId
+ if objid.class == NilClass
+ return nil
+ end
+ return ObjectId.new(objid)
+ end
+ end
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+ class SchemaArgument
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
@impl = Qmfengine::SchemaArgument.new(name, typecode)
@impl.setDirection(kwargs[:dir]) if kwargs.include?(:dir)
@impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
@@ -385,23 +586,51 @@ module Qmf
end
end
- class SchemaMethod
- attr_reader :impl
- def initialize(name, kwargs={})
+ def name
+ @impl.getName
+ end
+
+ def direction
+ @impl.getDirection
+ end
+
+ def typecode
+ @impl.getType
+ end
+ end
+
+ class SchemaMethod
+ attr_reader :impl, :arguments
+ def initialize(name, kwargs={})
+ @arguments = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ arg_count = @impl.getArgumentCount
+ for i in 0...arg_count
+ @arguments << SchemaArgument.new(nil, nil, :impl => @impl.getArgument(i))
+ end
+ else
@impl = Qmfengine::SchemaMethod.new(name)
@impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
- @arguments = []
end
+ end
- def add_argument(arg)
- @arguments << arg
- @impl.addArgument(arg.impl)
- end
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
end
- class SchemaProperty
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
+ def name
+ @impl.getName
+ end
+ end
+
+ class SchemaProperty
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
@impl = Qmfengine::SchemaProperty.new(name, typecode)
@impl.setAccess(kwargs[:access]) if kwargs.include?(:access)
@impl.setIndex(kwargs[:index]) if kwargs.include?(:index)
@@ -409,161 +638,547 @@ module Qmf
@impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
@impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
end
-
- def name
- @impl.getName
- end
end
- class SchemaStatistic
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
+ def name
+ @impl.getName
+ end
+ end
+
+ class SchemaStatistic
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
@impl = Qmfengine::SchemaStatistic.new(name, typecode)
@impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
@impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
end
end
- class SchemaObjectClass
- attr_reader :impl
- def initialize(package, name, kwargs={})
+ def name
+ @impl.getName
+ end
+ end
+
+ class SchemaClassKey
+ attr_reader :impl
+ def initialize(i)
+ @impl = i
+ end
+
+ def get_package()
+ @impl.getPackageName()
+ end
+
+ def get_class()
+ @impl.getClassName()
+ end
+ end
+
+ class SchemaObjectClass
+ attr_reader :impl, :properties, :statistics, :methods
+ def initialize(package, name, kwargs={})
+ @properties = []
+ @statistics = []
+ @methods = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+
+ @impl.getPropertyCount.times do |i|
+ @properties << SchemaProperty.new(nil, nil, :impl => @impl.getProperty(i))
+ end
+
+ @impl.getStatisticCount.times do |i|
+ @statistics << SchemaStatistic.new(nil, nil, :impl => @impl.getStatistic(i))
+ end
+
+ @impl.getMethodCount.times do |i|
+ @methods << SchemaMethod.new(nil, :impl => @impl.getMethod(i))
+ end
+ else
@impl = Qmfengine::SchemaObjectClass.new(package, name)
- @properties = []
- @statistics = []
- @methods = []
end
+ end
- def add_property(prop)
- @properties << prop
- @impl.addProperty(prop.impl)
- end
+ def add_property(prop)
+ @properties << prop
+ @impl.addProperty(prop.impl)
+ end
- def add_statistic(stat)
- @statistics << stat
- @impl.addStatistic(stat.impl)
- end
+ def add_statistic(stat)
+ @statistics << stat
+ @impl.addStatistic(stat.impl)
+ end
- def add_method(meth)
- @methods << meth
- @impl.addMethod(meth.impl)
+ def add_method(meth)
+ @methods << meth
+ @impl.addMethod(meth.impl)
+ end
+
+ def name
+ @impl.getClassKey.getClassName
+ end
+ end
+
+ class SchemaEventClass
+ attr_reader :impl, :arguments
+ def initialize(package, name, kwargs={})
+ @arguments = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ @impl.getArgumentCount.times do |i|
+ @arguments << SchemaArgument.new(nil, nil, :impl => @impl.getArgument(i))
+ end
+ else
+ @impl = Qmfengine::SchemaEventClass.new(package, name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
end
+ end
- def name
- @impl.getName
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+
+ def name
+ @impl.getClassKey.getClassName
+ end
+ end
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+ class ConsoleHandler
+ def agent_added(agent); end
+ def agent_deleted(agent); end
+ def new_package(package); end
+ def new_class(class_key); end
+ def object_update(object, hasProps, hasStats); end
+ def event_received(event); end
+ def agent_heartbeat(agent, timestamp); end
+ def method_response(resp); end
+ def broker_info(broker); end
+ end
+
+ class Console
+ include MonitorMixin
+ attr_reader :impl
+
+ def initialize(handler = nil, kwargs={})
+ super()
+ @handler = handler
+ @impl = Qmfengine::ConsoleEngine.new
+ @event = Qmfengine::ConsoleEvent.new
+ @broker_list = []
+ @cv = new_cond
+ @sync_count = nil
+ @sync_result = nil
+ end
+
+ def add_connection(conn)
+ broker = Broker.new(self, conn)
+ @broker_list << broker
+ return broker
+ end
+
+ def del_connection(broker)
+ broker.shutdown
+ @broker_list.delete(broker)
+ end
+
+ def get_packages()
+ plist = []
+ count = @impl.packageCount
+ for i in 0...count
+ plist << @impl.getPackageName(i)
end
+ return plist
+ end
- def properties
- unless @properties
- @properties = []
- @impl.getPropertyCount.times do |i|
- @properties << @impl.getProperty(i)
+ def get_classes(package, kind=CLASS_OBJECT)
+ clist = []
+ count = @impl.classCount(package)
+ for i in 0...count
+ key = @impl.getClass(package, i)
+ class_kind = @impl.getClassKind(key)
+ if class_kind == kind
+ if kind == CLASS_OBJECT
+ clist << SchemaObjectClass.new(nil, nil, :impl => @impl.getObjectClass(key))
+ elsif kind == CLASS_EVENT
+ clist << SchemaEventClass.new(nil, nil, :impl => @impl.getEventClass(key))
end
end
- return @properties
end
+
+ return clist
end
- class SchemaEventClass
- attr_reader :impl
- def initialize(package, name, kwargs={})
- @impl = Qmfengine::SchemaEventClass.new(package, name)
- @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
- @arguments = []
- end
+ def bind_package(package)
+ @impl.bindPackage(package)
+ end
- def add_argument(arg)
- @arguments << arg
- @impl.addArgument(arg.impl)
+ def bind_class(kwargs = {})
+ if kwargs.include?(:key)
+ @impl.bindClass(kwargs[:key])
+ elsif kwargs.include?(:package)
+ package = kwargs[:package]
+ if kwargs.include?(:class)
+ @impl.bindClass(package, kwargs[:class])
+ else
+ @impl.bindClass(package)
+ end
+ else
+ raise ArgumentError, "Invalid arguments, use :key or :package[,:class]"
end
end
- class QmfObject
- attr_reader :impl, :object_class
- def initialize(cls)
- @object_class = cls
- @impl = Qmfengine::Object.new(@object_class.impl)
+ def get_agents(broker = nil)
+ blist = []
+ if broker
+ blist << broker
+ else
+ blist = @broker_list
end
- def destroy
- @impl.destroy
+ agents = []
+ blist.each do |b|
+ count = b.impl.agentCount
+ for idx in 0...count
+ agents << AgentProxy.new(b.impl.getAgent(idx), b)
+ end
end
- def object_id
- return ObjectId.new(@impl.getObjectId)
+ return agents
+ end
+
+ def get_objects(query, kwargs = {})
+ timeout = 30
+ if kwargs.include?(:timeout)
+ timeout = kwargs[:timeout]
end
+ synchronize do
+ @sync_count = 1
+ @sync_result = []
+ broker = @broker_list[0]
+ broker.send_query(query.impl, nil)
+ unless @cv.wait(timeout) { @sync_count == 0 }
+ raise "Timed out waiting for response"
+ end
- def set_object_id(oid)
- @impl.setObjectId(oid.impl)
+ return @sync_result
end
+ end
- def get_attr(name)
- val = value(name)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
- when TYPE_UINT64 then val.asUint64
- when TYPE_SSTR, TYPE_LSTR then val.asString
- when TYPE_ABSTIME then val.asInt64
- when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
- when TYPE_BOOL then val.asBool
- when TYPE_FLOAT then val.asFloat
- when TYPE_DOUBLE then val.asDouble
- when TYPE_UUID then val.asUuid
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
- when TYPE_INT64 then val.asInt64
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
+ def _get_result(list, context)
+ synchronize do
+ list.each do |item|
+ @sync_result << item
end
+ @sync_count -= 1
+ @cv.signal
end
+ end
+
+ def start_sync(query)
+ end
+
+ def touch_sync(sync)
+ end
+
+ def end_sync(sync)
+ end
- def set_attr(name, v)
- val = value(name)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v)
- when TYPE_UINT64 then val.setUint64(v)
- when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('')
- when TYPE_ABSTIME then val.setInt64(v)
- when TYPE_DELTATIME then val.setUint64(v)
- when TYPE_REF then val.setObjectId(v.impl)
- when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0)
- when TYPE_FLOAT then val.setFloat(v)
- when TYPE_DOUBLE then val.setDouble(v)
- when TYPE_UUID then val.setUuid(v)
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v)
- when TYPE_INT64 then val.setInt64(v)
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
+ def do_console_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ puts "Console Event: #{@event.kind}"
+ case @event.kind
+ when Qmfengine::ConsoleEvent::AGENT_ADDED
+ when Qmfengine::ConsoleEvent::AGENT_DELETED
+ when Qmfengine::ConsoleEvent::NEW_PACKAGE
+ when Qmfengine::ConsoleEvent::NEW_CLASS
+ when Qmfengine::ConsoleEvent::OBJECT_UPDATE
+ when Qmfengine::ConsoleEvent::EVENT_RECEIVED
+ when Qmfengine::ConsoleEvent::AGENT_HEARTBEAT
+ when Qmfengine::ConsoleEvent::METHOD_RESPONSE
end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
end
+ return count
+ end
+ end
- def [](name)
- get_attr(name)
+ class AgentProxy
+ attr_reader :broker
+
+ def initialize(impl, broker)
+ @impl = impl
+ @broker = broker
+ end
+
+ def label
+ @impl.getLabel
+ end
+ end
+
+ class Broker < ConnectionHandler
+ include MonitorMixin
+ attr_reader :impl, :conn
+
+ def initialize(console, conn)
+ super()
+ @console = console
+ @conn = conn
+ @session = nil
+ @cv = new_cond
+ @stable = nil
+ @event = Qmfengine::BrokerEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ @impl = Qmfengine::BrokerProxy.new(@console.impl)
+ @console.impl.addConnection(@impl, self)
+ @conn.add_conn_handler(self)
+ @operational = :true
+ end
+
+ def shutdown()
+ @console.impl.delConnection(@impl)
+ @conn.del_conn_handler(self)
+ @operational = :false
+ end
+
+ def waitForStable(timeout = nil)
+ synchronize do
+ return if @stable
+ if timeout
+ unless @cv.wait(timeout) { @stable }
+ raise "Timed out waiting for broker connection to become stable"
+ end
+ else
+ while not @stable
+ @cv.wait
+ end
+ end
end
+ end
- def []=(name, value)
- set_attr(name, value)
+ def send_query(query, ctx)
+ @impl.sendQuery(query, ctx)
+ @conn.kick
+ end
+
+ def do_broker_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ puts "Broker Event: #{@event.kind}"
+ case @event.kind
+ when Qmfengine::BrokerEvent::BROKER_INFO
+ when Qmfengine::BrokerEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::SETUP_COMPLETE
+ @impl.startProtocol
+ when Qmfengine::BrokerEvent::STABLE
+ synchronize do
+ @stable = :true
+ @cv.signal
+ end
+ when Qmfengine::BrokerEvent::QUERY_COMPLETE
+ result = []
+ for idx in 0...@event.queryResponse.getObjectCount
+ result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx), :broker => self)
+ end
+ @console._get_result(result, @event.context)
+ when Qmfengine::BrokerEvent::METHOD_RESPONSE
+ obj = @event.context
+ obj._method_result(MethodResponse.new(@event.methodResponse))
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
end
+ return count
+ end
- def inc_attr(name, by=1)
- set_attr(name, get_attr(name) + by)
+ def do_broker_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
end
+ return count
+ end
+
+ def do_events()
+ begin
+ ccnt = @console.do_console_events
+ bcnt = do_broker_events
+ mcnt = do_broker_messages
+ end until ccnt == 0 and bcnt == 0 and mcnt == 0
+ end
+
+ def conn_event_connected()
+ puts "Console Connection Established..."
+ @session = Session.new(@conn, "qmfc-%s.%d" % [Socket.gethostname, Process::pid], self)
+ @impl.sessionOpened(@session.handle)
+ do_events
+ end
+
+ def conn_event_disconnected(error)
+ puts "Console Connection Lost"
+ end
- def dec_attr(name, by=1)
- set_attr(name, get_attr(name) - by)
+ def conn_event_visit
+ do_events
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Console Session Lost"
+ @impl.sessionClosed()
+ end
+
+ def sess_event_recv(context, message)
+ puts "Unexpected RECV Event" if not @operational
+ @impl.handleRcvMessage(message)
+ do_events
+ end
+ end
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+ class AgentHandler
+ def get_query(context, query, userId); end
+ def method_call(context, name, object_id, args, userId); end
+ end
+
+ class Agent < ConnectionHandler
+ def initialize(handler, label="")
+ if label == ""
+ @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
+ else
+ @agentLabel = label
end
+ @conn = nil
+ @handler = handler
+ @impl = Qmfengine::AgentEngine.new(@agentLabel)
+ @event = Qmfengine::AgentEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ end
- private
- def value(name)
- val = @impl.getValue(name.to_s)
- if val.nil?
- raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getName}"
- end
- return val
+ def set_connection(conn)
+ @conn = conn
+ @conn.add_conn_handler(self)
+ end
+
+ def register_class(cls)
+ @impl.registerClass(cls.impl)
+ end
+
+ def alloc_object_id(low = 0, high = 0)
+ ObjectId.new(@impl.allocObjectId(low, high))
+ end
+
+ def query_response(context, object)
+ @impl.queryResponse(context, object.impl)
+ end
+
+ def query_complete(context)
+ @impl.queryComplete(context)
+ end
+
+ def method_response(context, status, text, arguments)
+ @impl.methodResponse(context, status, text, arguments.map)
+ end
+
+ def do_agent_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ case @event.kind
+ when Qmfengine::AgentEvent::GET_QUERY
+ @handler.get_query(@event.sequence, Query.new(:impl => @event.query), @event.authUserId)
+ when Qmfengine::AgentEvent::START_SYNC
+ when Qmfengine::AgentEvent::END_SYNC
+ when Qmfengine::AgentEvent::METHOD_CALL
+ args = Arguments.new(@event.arguments)
+ @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
+ args, @event.authUserId)
+ when Qmfengine::AgentEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::SETUP_COMPLETE
+ @impl.startProtocol()
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
+ end
+ return count
+ end
+
+ def do_agent_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
end
+ return count
+ end
+
+ def do_events()
+ begin
+ ecnt = do_agent_events
+ mcnt = do_agent_messages
+ end until ecnt == 0 and mcnt == 0
+ end
+
+ def conn_event_connected()
+ puts "Agent Connection Established..."
+ @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self)
+ @impl.newSession
+ do_events
+ end
+
+ def conn_event_disconnected(error)
+ puts "Agent Connection Lost"
+ end
+
+ def conn_event_visit
+ do_events
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Agent Session Lost"
+ end
+
+ def sess_event_recv(context, message)
+ @impl.handleRcvMessage(message)
+ do_events
end
+ end
end
diff --git a/qpid/cpp/bindings/qmf/tests/Makefile.am b/qpid/cpp/bindings/qmf/tests/Makefile.am
index 1ff8a64bed..182771e16b 100644
--- a/qpid/cpp/bindings/qmf/tests/Makefile.am
+++ b/qpid/cpp/bindings/qmf/tests/Makefile.am
@@ -18,4 +18,10 @@
#
TESTS = run_interop_tests
-EXTRA_DIST = run_interop_tests
+
+EXTRA_DIST = \
+ agent_ruby.rb \
+ python_agent.py \
+ python_console.py \
+ ruby_console.rb \
+ run_interop_tests
diff --git a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
index 0f85c90f37..2f0869ad73 100755
--- a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
+++ b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
@@ -53,7 +53,10 @@ class Model
method = Qmf::SchemaMethod.new("create_child", :desc => "Create a new child object")
method.add_argument(Qmf::SchemaArgument.new("child_name", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN))
method.add_argument(Qmf::SchemaArgument.new("child_ref", Qmf::TYPE_REF, :dir => Qmf::DIR_OUT))
+ @parent_class.add_method(method)
+ method = Qmf::SchemaMethod.new("probe_userid", :desc => "Return the user-id for this method call")
+ method.add_argument(Qmf::SchemaArgument.new("userid", Qmf::TYPE_SSTR, :dir => Qmf::DIR_OUT))
@parent_class.add_method(method)
@child_class = Qmf::SchemaObjectClass.new("org.apache.qpid.qmf", "child")
@@ -69,8 +72,7 @@ end
class App < Qmf::AgentHandler
def get_query(context, query, userId)
-# puts "Query: user=#{userId} context=#{context} class=#{query.class_name} object_num=#{query.object_id.object_num_low if query.object_id}"
- #@parent.inc_attr("queryCount")
+# puts "Query: user=#{userId} context=#{context} class=#{query.class_name} object_num=#{query.object_id.object_num_low if query.object_id}"
if query.class_name == 'parent'
@agent.query_response(context, @parent)
elsif query.object_id == @parent_oid
@@ -90,37 +92,37 @@ class App < Qmf::AgentHandler
retText = "OK"
if args['test'] == "big"
- @parent.set_attr("uint64val", 0x9494949449494949)
- @parent.set_attr("uint32val", 0xa5a55a5a)
- @parent.set_attr("uint16val", 0xb66b)
- @parent.set_attr("uint8val", 0xc7)
+ @parent.uint64val = 0x9494949449494949
+ @parent.uint32val = 0xa5a55a5a
+ @parent.uint16val = 0xb66b
+ @parent.uint8val = 0xc7
- @parent.set_attr("int64val", 1000000000000000000)
- @parent.set_attr("int32val", 1000000000)
- @parent.set_attr("int16val", 10000)
- @parent.set_attr("int8val", 100)
+ @parent.int64val = 1000000000000000000
+ @parent.int32val = 1000000000
+ @parent.int16val = 10000
+ @parent.int8val = 100
elsif args['test'] == "small"
- @parent.set_attr("uint64val", 4)
- @parent.set_attr("uint32val", 5)
- @parent.set_attr("uint16val", 6)
- @parent.set_attr("uint8val", 7)
+ @parent.uint64val = 4
+ @parent.uint32val = 5
+ @parent.uint16val = 6
+ @parent.uint8val = 7
- @parent.set_attr("int64val", 8)
- @parent.set_attr("int32val", 9)
- @parent.set_attr("int16val", 10)
- @parent.set_attr("int8val", 11)
+ @parent.int64val = 8
+ @parent.int32val = 9
+ @parent.int16val = 10
+ @parent.int8val = 11
elsif args['test'] == "negative"
- @parent.set_attr("uint64val", 0)
- @parent.set_attr("uint32val", 0)
- @parent.set_attr("uint16val", 0)
- @parent.set_attr("uint8val", 0)
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
- @parent.set_attr("int64val", -10000000000)
- @parent.set_attr("int32val", -100000)
- @parent.set_attr("int16val", -1000)
- @parent.set_attr("int8val", -100)
+ @parent.int64val = -10000000000
+ @parent.int32val = -100000
+ @parent.int16val = -1000
+ @parent.int8val = -100
else
retCode = 1
@@ -132,10 +134,17 @@ class App < Qmf::AgentHandler
elsif name == "create_child"
oid = @agent.alloc_object_id(2)
args['child_ref'] = oid
- @child = Qmf::QmfObject.new(@model.child_class)
- @child.set_attr("name", args.by_key("child_name"))
+ @child = Qmf::AgentObject.new(@model.child_class)
+ @child.name = args.by_key("child_name")
@child.set_object_id(oid)
@agent.method_response(context, 0, "OK", args)
+
+ elsif name == "probe_userid"
+ args['userid'] = userId
+ @agent.method_response(context, 0, "OK", args)
+
+ else
+ @agent.method_response(context, 1, "Unimplemented Method: #{name}", args)
end
end
@@ -151,19 +160,19 @@ class App < Qmf::AgentHandler
@agent.set_connection(@connection)
- @parent = Qmf::QmfObject.new(@model.parent_class)
- @parent.set_attr("name", "Parent One")
- @parent.set_attr("state", "OPERATIONAL")
+ @parent = Qmf::AgentObject.new(@model.parent_class)
+ @parent.name = "Parent One"
+ @parent.state = "OPERATIONAL"
- @parent.set_attr("uint64val", 0)
- @parent.set_attr("uint32val", 0)
- @parent.set_attr("uint16val", 0)
- @parent.set_attr("uint8val", 0)
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
- @parent.set_attr("int64val", 0)
- @parent.set_attr("int32val", 0)
- @parent.set_attr("int16val", 0)
- @parent.set_attr("int8val", 0)
+ @parent.int64val = 0
+ @parent.int32val = 0
+ @parent.int16val = 0
+ @parent.int8val = 0
@parent_oid = @agent.alloc_object_id(1)
@parent.set_object_id(@parent_oid)
diff --git a/qpid/cpp/bindings/qmf/tests/python_agent.py b/qpid/cpp/bindings/qmf/tests/python_agent.py
new file mode 100644
index 0000000000..d4373d3bb8
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/python_agent.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+import qmf
+import sys
+import time
+
+
+class Model:
+ # attr_reader :parent_class, :child_class
+ def __init__(self):
+ self.parent_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "parent")
+ self.parent_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+ self.parent_class.add_property(qmf.SchemaProperty("state", qmf.TYPE_SSTR))
+
+ self.parent_class.add_property(qmf.SchemaProperty("uint64val", qmf.TYPE_UINT64))
+ self.parent_class.add_property(qmf.SchemaProperty("uint32val", qmf.TYPE_UINT32))
+ self.parent_class.add_property(qmf.SchemaProperty("uint16val", qmf.TYPE_UINT16))
+ self.parent_class.add_property(qmf.SchemaProperty("uint8val", qmf.TYPE_UINT8))
+
+ self.parent_class.add_property(qmf.SchemaProperty("int64val", qmf.TYPE_INT64))
+ self.parent_class.add_property(qmf.SchemaProperty("int32val", qmf.TYPE_INT32))
+ self.parent_class.add_property(qmf.SchemaProperty("int16val", qmf.TYPE_INT16))
+ self.parent_class.add_property(qmf.SchemaProperty("int8val", qmf.TYPE_INT8))
+
+ self.parent_class.add_statistic(qmf.SchemaStatistic("queryCount", qmf.TYPE_UINT32, {"unit":"query", "desc":"Query count"}))
+
+ _method = qmf.SchemaMethod("echo", {"desc":"Check responsiveness of the agent object"})
+ _method.add_argument(qmf.SchemaArgument("sequence", qmf.TYPE_UINT32, {"dir":qmf.DIR_IN_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("set_numerics", {"desc":"Set the numeric values in the object"})
+ _method.add_argument(qmf.SchemaArgument("test", qmf.TYPE_SSTR, {"dir":qmf.DIR_IN}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("create_child", {"desc":"Create a new child object"})
+ _method.add_argument(qmf.SchemaArgument("child_name", qmf.TYPE_LSTR, {"dir":qmf.DIR_IN}))
+ _method.add_argument(qmf.SchemaArgument("child_ref", qmf.TYPE_REF, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("probe_userid", {"desc":"Return the user-id for this method call"})
+ _method.add_argument(qmf.SchemaArgument("userid", qmf.TYPE_SSTR, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ self.child_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "child")
+ self.child_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+
+
+ def register(self, agent):
+ agent.register_class(self.parent_class)
+ agent.register_class(self.child_class)
+
+
+
+class App(qmf.AgentHandler):
+ def get_query(self, context, query, userId):
+ #print "Query: user=%s context=%d class=%s" % (userId, context, query.class_name())
+ #if query.object_id():
+ # print query.object_id().object_num_low()
+ self._parent.inc_attr("queryCount")
+ if query.class_name() == 'parent':
+ self._agent.query_response(context, self._parent)
+ elif query.object_id() == self._parent_oid:
+ self._agent.query_response(context, self._parent)
+ self._agent.query_complete(context)
+
+
+ def method_call(self, context, name, object_id, args, userId):
+ # puts "Method: user=#{userId} context=#{context} method=#{name} object_num=#{object_id.object_num_low if object_id} args=#{args}"
+ # oid = self._agent.alloc_object_id(2)
+ # args['child_ref'] = oid
+ # self._child = qmf.QmfObject(self._model.child_class)
+ # self._child.set_attr("name", args.by_key("child_name"))
+ # self._child.set_object_id(oid)
+ # self._agent.method_response(context, 0, "OK", args)
+ if name == "echo":
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "set_numerics":
+ _retCode = 0
+ _retText = "OK"
+
+ if args['test'] == "big":
+ self._parent.set_attr("uint64val", 0x9494949449494949)
+ self._parent.set_attr("uint32val", 0xa5a55a5a)
+ self._parent.set_attr("uint16val", 0xb66b)
+ self._parent.set_attr("uint8val", 0xc7)
+
+ self._parent.set_attr("int64val", 1000000000000000000)
+ self._parent.set_attr("int32val", 1000000000)
+ self._parent.set_attr("int16val", 10000)
+ self._parent.set_attr("int8val", 100)
+
+ elif args['test'] == "small":
+ self._parent.set_attr("uint64val", 4)
+ self._parent.set_attr("uint32val", 5)
+ self._parent.set_attr("uint16val", 6)
+ self._parent.set_attr("uint8val", 7)
+
+ self._parent.set_attr("int64val", 8)
+ self._parent.set_attr("int32val", 9)
+ self._parent.set_attr("int16val", 10)
+ self._parent.set_attr("int8val", 11)
+
+ elif args['test'] == "negative":
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", -10000000000)
+ self._parent.set_attr("int32val", -100000)
+ self._parent.set_attr("int16val", -1000)
+ self._parent.set_attr("int8val", -100)
+
+ else:
+ _retCode = 1
+ _retText = "Invalid argument value for test"
+
+ self._agent.method_response(context, _retCode, _retText, args)
+
+ elif name == "create_child":
+ _oid = self._agent.alloc_object_id(2)
+ args['child_ref'] = _oid
+ self._child = qmf.QmfObject(self._model.child_class)
+ self._child.set_attr("name", args["child_name"])
+ self._child.set_object_id(_oid)
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "probe_userid":
+ args['userid'] = userId
+ self._agent.method_response(context, 0, "OK", args)
+
+ else:
+ self._agent.method_response(context, 1, "Unimplemented Method: %s" % name, args)
+
+
+ def main(self):
+ self._settings = qmf.ConnectionSettings()
+ if len(sys.argv) > 1:
+ self._settings.set_attr("host", sys.argv[1])
+ if len(sys.argv) > 2:
+ self._settings.set_attr("port", int(sys.argv[2]))
+ self._connection = qmf.Connection(self._settings)
+ self._agent = qmf.Agent(self)
+
+ self._model = Model()
+ self._model.register(self._agent)
+
+ self._agent.set_connection(self._connection)
+
+ self._parent = qmf.QmfObject(self._model.parent_class)
+ self._parent.set_attr("name", "Parent One")
+ self._parent.set_attr("state", "OPERATIONAL")
+
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", 0)
+ self._parent.set_attr("int32val", 0)
+ self._parent.set_attr("int16val", 0)
+ self._parent.set_attr("int8val", 0)
+
+ self._parent_oid = self._agent.alloc_object_id(1)
+ self._parent.set_object_id(self._parent_oid)
+
+ while True: # there may be a better way, but
+ time.sleep(1000) # I'm a python noob...
+
+
+
+app = App()
+app.main()
+
diff --git a/qpid/cpp/bindings/qmf/tests/python_console.py b/qpid/cpp/bindings/qmf/tests/python_console.py
index 365f2ac33a..bcd3063fe3 100755
--- a/qpid/cpp/bindings/qmf/tests/python_console.py
+++ b/qpid/cpp/bindings/qmf/tests/python_console.py
@@ -128,6 +128,18 @@ class QmfInteropTests(TestBase010):
self.assertEqual(parent.int16val, -1000)
self.assertEqual(parent.int8val, -100)
+ def test_D_userid_for_method(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.probe_userid()
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.userid, "guest")
+
def getProperty(self, msg, name):
for h in msg.headers:
if hasattr(h, name): return getattr(h, name)
diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console.rb b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
new file mode 100755
index 0000000000..2f8f633d16
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
@@ -0,0 +1,133 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qmf'
+require 'socket'
+
+class App < Qmf::ConsoleHandler
+
+ def dump_schema
+ packages = @qmfc.get_packages
+ puts "----- Packages -----"
+ packages.each do |p|
+ puts p
+ puts " ----- Object Classes -----"
+ classes = @qmfc.get_classes(p)
+ classes.each do |c|
+ puts " #{c.name}"
+
+ puts " ---- Properties ----"
+ props = c.properties
+ props.each do |prop|
+ puts " #{prop.name}"
+ end
+
+ puts " ---- Statistics ----"
+ stats = c.statistics
+ stats.each do |stat|
+ puts " #{stat.name}"
+ end
+
+ puts " ---- Methods ----"
+ methods = c.methods
+ methods.each do |method|
+ puts " #{method.name}"
+ puts " ---- Args ----"
+ args = method.arguments
+ args.each do |arg|
+ puts " #{arg.name}"
+ end
+ end
+ end
+
+ puts " ----- Event Classes -----"
+ classes = @qmfc.get_classes(p, Qmf::CLASS_EVENT)
+ classes.each do |c|
+ puts " #{c.name}"
+ puts " ---- Args ----"
+ args = c.arguments
+ args.each do |arg|
+ puts " #{arg.name}"
+ end
+ end
+ end
+ puts "-----"
+ end
+
+ def main
+ @settings = Qmf::ConnectionSettings.new
+ @settings.set_attr("host", ARGV[0]) if ARGV.size > 0
+ @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @qmfc = Qmf::Console.new
+
+ @broker = @qmfc.add_connection(@connection)
+ @broker.waitForStable
+
+ dump_schema
+
+ agents = @qmfc.get_agents()
+ puts "---- Agents ----"
+ agents.each do |a|
+ puts " => #{a.label}"
+ end
+ puts "----"
+
+ for idx in 0...20
+ blist = @qmfc.get_objects(Qmf::Query.new(:class => "broker"))
+ puts "---- Brokers ----"
+ blist.each do |b|
+ puts " ---- Broker ----"
+ puts " systemRef: #{b.systemRef}"
+ puts " port : #{b.port}"
+ puts " uptime : #{b.uptime / 1000000000}"
+
+ for rep in 0...0
+ puts " Pinging..."
+ ret = b.echo(45, 'text string')
+ puts " ret=#{ret}"
+ end
+ end
+ puts "----"
+
+ qlist = @qmfc.get_objects(Qmf::Query.new(:package => "org.apache.qpid.broker",
+ :class => "queue"))
+ puts "---- Queues ----"
+ qlist.each do |q|
+ puts " ---- Queue ----"
+ puts " name : #{q.name}"
+ end
+ puts "----"
+ sleep(5)
+ end
+
+ sleep(5)
+ puts "Deleting connection..."
+ @qmfc.del_connection(@broker)
+ puts " done"
+ sleep
+ end
+end
+
+app = App.new
+app.main
+
+
diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests
index e6fc872dbb..01d7221ac6 100755
--- a/qpid/cpp/bindings/qmf/tests/run_interop_tests
+++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests
@@ -28,6 +28,9 @@ BROKER_DIR=${BUILD_DIR}/src
API_DIR=${BUILD_DIR}/bindings/qmf
SPEC_DIR=${QPID_DIR}/specs
+RUBY_LIB_DIR=${API_DIR}/ruby/.libs
+PYTHON_LIB_DIR=${API_DIR}/python/.libs
+
trap stop_broker INT TERM QUIT
start_broker() {
@@ -41,7 +44,7 @@ stop_broker() {
}
start_ruby_agent() {
- ruby -I${MY_DIR}/../ruby -I${API_DIR}/ruby/.libs ${MY_DIR}/agent_ruby.rb localhost $BROKER_PORT &
+ ruby -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/agent_ruby.rb localhost $BROKER_PORT &
AGENT_PID=$!
}
@@ -49,19 +52,62 @@ stop_ruby_agent() {
kill $AGENT_PID
}
+start_python_agent() {
+ PYTHONPATH="${MY_DIR}/../python:${API_DIR}/python:${PYTHON_LIB_DIR}" python ${MY_DIR}/python_agent.py localhost $BROKER_PORT &
+ PY_AGENT_PID=$!
+}
+
+stop_python_agent() {
+ kill $PY_AGENT_PID
+}
+
+TESTS_FAILED=0
+
if test -d ${PYTHON_DIR} ; then
start_broker
echo "Running qmf interop tests using broker on port $BROKER_PORT"
PYTHONPATH=${PYTHON_DIR}:${MY_DIR}
export PYTHONPATH
- echo " Ruby Agent vs. Pure-Python Console"
- start_ruby_agent
- echo " Ruby agent started at pid $AGENT_PID"
- ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
- RETCODE=$?
- stop_ruby_agent
+
+ if test -d ${PYTHON_LIB_DIR} ; then
+ echo " Python Agent (external storage) vs. Pure-Python Console"
+ start_python_agent
+ echo " Python agent started at pid $PY_AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ stop_python_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Python Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ if test -d ${RUBY_LIB_DIR} ; then
+ echo " Ruby Agent (external storage) vs. Pure-Python Console"
+ start_ruby_agent
+ echo " Ruby agent started at pid $AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ stop_ruby_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Ruby Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ # Also against the Pure-Python console:
+ # Ruby agent (internal storage)
+ # Python agent (external and internal)
+ # C++ agent (external and internal)
+ #
+ # Other consoles against the same set of agents:
+ # Wrapped Python console
+ # Ruby console
+ # C++ console
+
stop_broker
- if test x$RETCODE != x0; then
- echo "FAIL qmf interop tests"; exit 1;
+ if test x$TESTS_FAILED != x0; then
+ echo "TEST FAILED!"
+ exit 1
fi
fi
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
index a4e45ad19b..7eb1e99159 100644
--- a/qpid/cpp/configure.ac
+++ b/qpid/cpp/configure.ac
@@ -515,6 +515,7 @@ AC_CONFIG_FILES([
examples/messaging/Makefile
bindings/qmf/Makefile
bindings/qmf/ruby/Makefile
+ bindings/qmf/python/Makefile
bindings/qmf/tests/Makefile
managementgen/Makefile
etc/Makefile
diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp
index 6f0f2af02d..38f4601ff6 100644
--- a/qpid/cpp/examples/messaging/server.cpp
+++ b/qpid/cpp/examples/messaging/server.cpp
@@ -44,9 +44,7 @@ int main(int argc, char** argv) {
try {
Connection connection = Connection::open(url);
Session session = connection.newSession();
- VariantMap options;
- options["auto_acknowledge"] = 0;
- Receiver receiver = session.createReceiver("service_queue", options);
+ Receiver receiver = session.createReceiver("service_queue");
while (true) {
Message request = receiver.fetch();
diff --git a/qpid/cpp/include/qmf/QmfImportExport.h b/qpid/cpp/include/qmf/QmfImportExport.h
index 8353a3cc16..f5e1d9127c 100644
--- a/qpid/cpp/include/qmf/QmfImportExport.h
+++ b/qpid/cpp/include/qmf/QmfImportExport.h
@@ -21,7 +21,7 @@
*/
#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
-# if defined(QMF_EXPORT) || defined (qmf_EXPORTS)
+# if defined(QMF_EXPORT) || defined (qmfcommon_EXPORTS)
# define QMF_EXTERN __declspec(dllexport)
# else
# define QMF_EXTERN __declspec(dllimport)
diff --git a/qpid/cpp/include/qpid/framing/FieldTable.h b/qpid/cpp/include/qpid/framing/FieldTable.h
index b2331cd4e1..fd09cfc6f6 100644
--- a/qpid/cpp/include/qpid/framing/FieldTable.h
+++ b/qpid/cpp/include/qpid/framing/FieldTable.h
@@ -52,6 +52,7 @@ class FieldTable
typedef std::map<std::string, ValuePtr> ValueMap;
typedef ValueMap::iterator iterator;
typedef ValueMap::const_reference const_reference;
+ typedef ValueMap::reference reference;
typedef ValueMap::value_type value_type;
QPID_COMMON_EXTERN FieldTable() {};
@@ -108,7 +109,7 @@ class FieldTable
ValueMap::iterator find(const std::string& s) { return values.find(s); }
std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&);
- ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&);
+ QPID_COMMON_EXTERN ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&);
void clear() { values.clear(); }
// ### Hack Alert
diff --git a/qpid/cpp/include/qpid/framing/List.h b/qpid/cpp/include/qpid/framing/List.h
index cb1129ebf8..0f17c7884c 100644
--- a/qpid/cpp/include/qpid/framing/List.h
+++ b/qpid/cpp/include/qpid/framing/List.h
@@ -44,6 +44,7 @@ class List
typedef Values::const_iterator const_iterator;
typedef Values::iterator iterator;
typedef Values::const_reference const_reference;
+ typedef Values::reference reference;
QPID_COMMON_EXTERN uint32_t encodedSize() const;
QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
diff --git a/qpid/cpp/include/qpid/framing/Uuid.h b/qpid/cpp/include/qpid/framing/Uuid.h
index 0dfa7a58e7..618515622d 100644
--- a/qpid/cpp/include/qpid/framing/Uuid.h
+++ b/qpid/cpp/include/qpid/framing/Uuid.h
@@ -20,7 +20,6 @@
*/
#include "qpid/CommonImportExport.h"
-#include "qpid/sys/uuid.h"
#include "qpid/sys/IntegerTypes.h"
#include <boost/array.hpp>
@@ -38,33 +37,31 @@ class Buffer;
*
* Full value semantics, operators ==, < etc. are provided by
* boost::array so Uuid can be the key type in a map etc.
+ *
+ * TODO: change this implementation as it leaks boost into the
+ * client API
*/
struct Uuid : public boost::array<uint8_t, 16> {
/** If unique is true, generate a unique ID else a null ID. */
- Uuid(bool unique=false) { if (unique) generate(); else clear(); }
+ QPID_COMMON_EXTERN Uuid(bool unique=false);
/** Copy from 16 bytes of data. */
- Uuid(const uint8_t* data) { assign(data); }
+ QPID_COMMON_EXTERN Uuid(const uint8_t* data);
+
+ // Default op= and copy ctor are fine.
+ // boost::array gives us ==, < etc.
/** Copy from 16 bytes of data. */
- void assign(const uint8_t* data) {
- uuid_copy(c_array(), data);
- }
+ void assign(const uint8_t* data);
/** Set to a new unique identifier. */
- void generate() { uuid_generate(c_array()); }
+ QPID_COMMON_EXTERN void generate();
/** Set to all zeros. */
- void clear() { uuid_clear(c_array()); }
+ void clear();
/** Test for null (all zeros). */
- // Force int 0/!0 to false/true; avoids compile warnings.
- bool isNull() {
- return !!uuid_is_null(data());
- }
-
- // Default op= and copy ctor are fine.
- // boost::array gives us ==, < etc.
+ bool isNull();
QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const;
QPID_COMMON_EXTERN void decode(framing::Buffer& buf);
diff --git a/qpid/cpp/include/qpid/management/Manageable.h b/qpid/cpp/include/qpid/management/Manageable.h
index 8062479ac6..7a72cc1592 100644
--- a/qpid/cpp/include/qpid/management/Manageable.h
+++ b/qpid/cpp/include/qpid/management/Manageable.h
@@ -43,7 +43,7 @@ class QPID_COMMON_EXTERN Manageable
static const status_t STATUS_UNKNOWN_OBJECT = 1;
static const status_t STATUS_UNKNOWN_METHOD = 2;
static const status_t STATUS_NOT_IMPLEMENTED = 3;
- static const status_t STATUS_INVALID_PARAMETER = 4;
+ static const status_t STATUS_PARAMETER_INVALID = 4;
static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5;
static const status_t STATUS_FORBIDDEN = 6;
static const status_t STATUS_EXCEPTION = 7;
diff --git a/qpid/cpp/include/qpid/messaging/Connection.h b/qpid/cpp/include/qpid/messaging/Connection.h
index 5517e45af9..19dae586a4 100644
--- a/qpid/cpp/include/qpid/messaging/Connection.h
+++ b/qpid/cpp/include/qpid/messaging/Connection.h
@@ -41,7 +41,7 @@ class Session;
class Connection : public qpid::client::Handle<ConnectionImpl>
{
public:
- static Connection open(const std::string& url, const Variant::Map& options = Variant::Map());
+ static QPID_CLIENT_EXTERN Connection open(const std::string& url, const Variant::Map& options = Variant::Map());
QPID_CLIENT_EXTERN Connection(ConnectionImpl* impl = 0);
QPID_CLIENT_EXTERN Connection(const Connection&);
diff --git a/qpid/cpp/include/qpid/messaging/Message.h b/qpid/cpp/include/qpid/messaging/Message.h
index 39edae3637..e68d8a1141 100644
--- a/qpid/cpp/include/qpid/messaging/Message.h
+++ b/qpid/cpp/include/qpid/messaging/Message.h
@@ -33,9 +33,9 @@ namespace client {
namespace messaging {
-class Address;
+struct Address;
class Codec;
-class MessageImpl;
+struct MessageImpl;
/**
* Representation of a message.
@@ -79,11 +79,9 @@ class Message
QPID_CLIENT_EXTERN void encode(Codec&);
QPID_CLIENT_EXTERN void decode(Codec&);
- //TODO: move this out of the public API
- QPID_CLIENT_EXTERN void setInternalId(void*);
- QPID_CLIENT_EXTERN void* getInternalId();
private:
MessageImpl* impl;
+ friend struct MessageImplAccess;
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/include/qpid/messaging/Receiver.h b/qpid/cpp/include/qpid/messaging/Receiver.h
index e51e1093d1..a4fdd7a34b 100644
--- a/qpid/cpp/include/qpid/messaging/Receiver.h
+++ b/qpid/cpp/include/qpid/messaging/Receiver.h
@@ -40,7 +40,7 @@ class MessageListener;
class ReceiverImpl;
/**
- * A pull style interface for message retrieval.
+ * Interface through which messages are received.
*/
class Receiver : public qpid::client::Handle<ReceiverImpl>
{
@@ -75,7 +75,7 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
QPID_CLIENT_EXTERN bool fetch(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
/**
* 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 throwing an exception.
@@ -87,8 +87,8 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
*/
QPID_CLIENT_EXTERN void start();
/**
- * Stops the message flow for this receiver (without actually
- * cancelling the subscription).
+ * Stops the message flow for this receiver (but does not cancel
+ * the subscription).
*/
QPID_CLIENT_EXTERN void stop();
/**
@@ -97,14 +97,35 @@ class Receiver : public qpid::client::Handle<ReceiverImpl>
* requested by a client via fetch() (or pushed to a listener).
*/
QPID_CLIENT_EXTERN void setCapacity(uint32_t);
+ /**
+ * Returns the capacity of the receiver. The capacity determines
+ * how many incoming messages can be held in the receiver before
+ * being requested by a client via fetch() (or pushed to a
+ * listener).
+ */
+ QPID_CLIENT_EXTERN uint32_t getCapacity();
+ /**
+ * Returns the number of messages received and waiting to be
+ * fetched.
+ */
+ QPID_CLIENT_EXTERN uint32_t available();
+ /**
+ * Returns a count of the number of messages received on this
+ * receiver that have been acknowledged, but for which that
+ * acknowledgement has not yet been confirmed as processed by the
+ * server.
+ */
+ QPID_CLIENT_EXTERN uint32_t pendingAck();
/**
- * Cancels this receiver
+ * Cancels this receiver.
*/
QPID_CLIENT_EXTERN void cancel();
/**
- * Set a message listener for receiving messages asynchronously.
+ * Set a message listener for this receiver.
+ *
+ * @see Session::dispatch()
*/
QPID_CLIENT_EXTERN void setListener(MessageListener* listener);
private:
diff --git a/qpid/cpp/include/qpid/messaging/Sender.h b/qpid/cpp/include/qpid/messaging/Sender.h
index 657c4b8cfe..9b83a04d60 100644
--- a/qpid/cpp/include/qpid/messaging/Sender.h
+++ b/qpid/cpp/include/qpid/messaging/Sender.h
@@ -23,6 +23,7 @@
*/
#include "qpid/client/ClientImportExport.h"
#include "qpid/client/Handle.h"
+#include "qpid/sys/IntegerTypes.h"
namespace qpid {
namespace client {
@@ -47,8 +48,26 @@ class Sender : public qpid::client::Handle<SenderImpl>
QPID_CLIENT_EXTERN ~Sender();
QPID_CLIENT_EXTERN Sender& operator=(const Sender&);
- QPID_CLIENT_EXTERN void send(Message& message);
+ QPID_CLIENT_EXTERN void send(const Message& message);
QPID_CLIENT_EXTERN void cancel();
+
+ /**
+ * Sets the capacity for the sender. The capacity determines how
+ * many outgoing messages can be held pending confirmation of
+ * receipt by the broker.
+ */
+ QPID_CLIENT_EXTERN void setCapacity(uint32_t);
+ /**
+ * Returns the capacity of the sender.
+ * @see setCapacity
+ */
+ QPID_CLIENT_EXTERN uint32_t getCapacity();
+ /**
+ * Returns the number of sent messages pending confirmation of
+ * receipt by the broker. (These are the 'in-doubt' messages).
+ */
+ QPID_CLIENT_EXTERN uint32_t pending();
+
private:
friend class qpid::client::PrivateImplRef<Sender>;
};
diff --git a/qpid/cpp/include/qpid/messaging/Session.h b/qpid/cpp/include/qpid/messaging/Session.h
index 3a354c009f..979e27adae 100644
--- a/qpid/cpp/include/qpid/messaging/Session.h
+++ b/qpid/cpp/include/qpid/messaging/Session.h
@@ -35,8 +35,8 @@ template <class> class PrivateImplRef;
namespace messaging {
-class Address;
-class Filter;
+struct Address;
+struct Filter;
class Message;
class MessageListener;
class Sender;
@@ -75,6 +75,17 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN void sync();
QPID_CLIENT_EXTERN void flush();
+ /**
+ * Returns the number of messages received and waiting to be
+ * fetched.
+ */
+ QPID_CLIENT_EXTERN uint32_t available();
+ /**
+ * Returns a count of the number of messages received this session
+ * that have been acknowledged, but for which that acknowledgement
+ * has not yet been confirmed as processed by the server.
+ */
+ QPID_CLIENT_EXTERN uint32_t pendingAck();
QPID_CLIENT_EXTERN bool fetch(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
QPID_CLIENT_EXTERN Message fetch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
QPID_CLIENT_EXTERN bool dispatch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
@@ -88,9 +99,6 @@ class Session : public qpid::client::Handle<SessionImpl>
QPID_CLIENT_EXTERN Receiver createReceiver(const std::string& address, const Filter& filter, const VariantMap& options = VariantMap());
QPID_CLIENT_EXTERN Address createTempQueue(const std::string& baseName = std::string());
-
- QPID_CLIENT_EXTERN void* getLastConfirmedSent();
- QPID_CLIENT_EXTERN void* getLastConfirmedAcknowledged();
private:
friend class qpid::client::PrivateImplRef<Session>;
};
diff --git a/qpid/cpp/include/qpid/messaging/Variant.h b/qpid/cpp/include/qpid/messaging/Variant.h
index ac000244c2..1e51914794 100644
--- a/qpid/cpp/include/qpid/messaging/Variant.h
+++ b/qpid/cpp/include/qpid/messaging/Variant.h
@@ -44,21 +44,21 @@ struct InvalidConversion : public qpid::Exception
};
enum VariantType {
- VOID = 0,
- BOOL,
- UINT8,
- UINT16,
- UINT32,
- UINT64,
- INT8,
- INT16,
- INT32,
- INT64,
- FLOAT,
- DOUBLE,
- STRING,
- MAP,
- LIST
+ VAR_VOID = 0,
+ VAR_BOOL,
+ VAR_UINT8,
+ VAR_UINT16,
+ VAR_UINT32,
+ VAR_UINT64,
+ VAR_INT8,
+ VAR_INT16,
+ VAR_INT32,
+ VAR_INT64,
+ VAR_FLOAT,
+ VAR_DOUBLE,
+ VAR_STRING,
+ VAR_MAP,
+ VAR_LIST
};
class VariantImpl;
diff --git a/qpid/cpp/include/qpid/sys/windows/Condition.h b/qpid/cpp/include/qpid/sys/windows/Condition.h
index c31f7b4823..979fae9b0a 100755
--- a/qpid/cpp/include/qpid/sys/windows/Condition.h
+++ b/qpid/cpp/include/qpid/sys/windows/Condition.h
@@ -30,7 +30,6 @@
#include <boost/thread/condition.hpp>
#include <boost/thread/thread_time.hpp>
#include <windows.h>
-#undef STATUS_INVALID_PARAMETER // Hack for windows.h namespace pollution
namespace qpid {
namespace sys {
diff --git a/qpid/cpp/include/qpid/sys/windows/Mutex.h b/qpid/cpp/include/qpid/sys/windows/Mutex.h
index 12768640d5..5dcc69e836 100755
--- a/qpid/cpp/include/qpid/sys/windows/Mutex.h
+++ b/qpid/cpp/include/qpid/sys/windows/Mutex.h
@@ -31,7 +31,6 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/tss.hpp>
-#undef STATUS_INVALID_PARAMETER // Hack for windows.h namespace pollution
namespace qpid {
namespace sys {
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index 7456401618..786facced9 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -528,6 +528,8 @@ set (libqpidclient_SOURCES
qpid/messaging/ConnectionImpl.h
qpid/messaging/Filter.cpp
qpid/messaging/Message.cpp
+ qpid/messaging/MessageImpl.h
+ qpid/messaging/MessageImpl.cpp
qpid/messaging/Receiver.cpp
qpid/messaging/ReceiverImpl.h
qpid/messaging/Session.cpp
@@ -535,17 +537,20 @@ set (libqpidclient_SOURCES
qpid/messaging/Sender.cpp
qpid/messaging/SenderImpl.h
qpid/messaging/Variant.cpp
+ qpid/client/amqp0_10/AcceptTracker.h
+ qpid/client/amqp0_10/AcceptTracker.cpp
qpid/client/amqp0_10/AddressResolution.h
qpid/client/amqp0_10/AddressResolution.cpp
qpid/client/amqp0_10/Codecs.cpp
- qpid/client/amqp0_10/CompletionTracker.h
- qpid/client/amqp0_10/CompletionTracker.cpp
+ qpid/client/amqp0_10/CodecsInternal.h
qpid/client/amqp0_10/ConnectionImpl.h
qpid/client/amqp0_10/ConnectionImpl.cpp
qpid/client/amqp0_10/IncomingMessages.h
qpid/client/amqp0_10/IncomingMessages.cpp
qpid/client/amqp0_10/MessageSink.h
qpid/client/amqp0_10/MessageSource.h
+ qpid/client/amqp0_10/OutgoingMessage.h
+ qpid/client/amqp0_10/OutgoingMessage.cpp
qpid/client/amqp0_10/ReceiverImpl.h
qpid/client/amqp0_10/ReceiverImpl.cpp
qpid/client/amqp0_10/SessionImpl.h
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 05b5efc5b5..4988f3f031 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -54,7 +54,7 @@ windows_dist = \
qpid/sys/windows/Time.cpp \
../include/qpid/sys/windows/Time.h \
qpid/sys/windows/uuid.cpp \
- ../include/qpid/sys/windows/uuid.h \
+ qpid/sys/windows/uuid.h \
windows/QpiddBroker.cpp \
qpid/broker/windows/BrokerDefaults.cpp \
qpid/broker/windows/SaslAuthenticator.cpp
@@ -461,7 +461,8 @@ libqpidcommon_la_SOURCES += \
qpid/sys/Timer.cpp \
qpid/sys/Timer.h \
qpid/sys/Waitable.h \
- qpid/sys/alloca.h
+ qpid/sys/alloca.h \
+ qpid/sys/uuid.h
if HAVE_SASL
libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.h
@@ -686,6 +687,8 @@ libqpidclient_la_SOURCES = \
qpid/messaging/Connection.cpp \
qpid/messaging/Filter.cpp \
qpid/messaging/Message.cpp \
+ qpid/messaging/MessageImpl.h \
+ qpid/messaging/MessageImpl.cpp \
qpid/messaging/Sender.cpp \
qpid/messaging/Receiver.cpp \
qpid/messaging/Session.cpp \
@@ -694,17 +697,20 @@ libqpidclient_la_SOURCES = \
qpid/messaging/SenderImpl.h \
qpid/messaging/ReceiverImpl.h \
qpid/messaging/SessionImpl.h \
+ qpid/client/amqp0_10/AcceptTracker.h \
+ qpid/client/amqp0_10/AcceptTracker.cpp \
qpid/client/amqp0_10/AddressResolution.h \
qpid/client/amqp0_10/AddressResolution.cpp \
qpid/client/amqp0_10/Codecs.cpp \
+ qpid/client/amqp0_10/CodecsInternal.h \
qpid/client/amqp0_10/ConnectionImpl.h \
qpid/client/amqp0_10/ConnectionImpl.cpp \
- qpid/client/amqp0_10/CompletionTracker.h \
- qpid/client/amqp0_10/CompletionTracker.cpp \
qpid/client/amqp0_10/IncomingMessages.h \
qpid/client/amqp0_10/IncomingMessages.cpp \
qpid/client/amqp0_10/MessageSink.h \
qpid/client/amqp0_10/MessageSource.h \
+ qpid/client/amqp0_10/OutgoingMessage.h \
+ qpid/client/amqp0_10/OutgoingMessage.cpp \
qpid/client/amqp0_10/ReceiverImpl.h \
qpid/client/amqp0_10/ReceiverImpl.cpp \
qpid/client/amqp0_10/SessionImpl.h \
@@ -780,7 +786,6 @@ nobase_include_HEADERS += \
../include/qpid/sys/SystemInfo.h \
../include/qpid/sys/Thread.h \
../include/qpid/sys/Time.h \
- ../include/qpid/sys/uuid.h \
../include/qpid/messaging/Address.h \
../include/qpid/messaging/Connection.h \
../include/qpid/messaging/Codec.h \
diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk
index 9d24709b6e..65caaedd5c 100644
--- a/qpid/cpp/src/qmf.mk
+++ b/qpid/cpp/src/qmf.mk
@@ -35,8 +35,12 @@ nobase_include_HEADERS += \
../include/qmf/AgentObject.h
libqmfcommon_la_SOURCES = \
+ qmf/BrokerProxyImpl.cpp \
+ qmf/BrokerProxyImpl.h \
qmf/ConnectionSettingsImpl.cpp \
qmf/ConnectionSettingsImpl.h \
+ qmf/ConsoleEngineImpl.cpp \
+ qmf/ConsoleEngineImpl.h \
qmf/ConsoleEngine.h \
qmf/Event.h \
qmf/Message.h \
@@ -48,11 +52,15 @@ libqmfcommon_la_SOURCES = \
qmf/ObjectIdImpl.h \
qmf/ObjectImpl.cpp \
qmf/ObjectImpl.h \
+ qmf/Protocol.cpp \
+ qmf/Protocol.h \
qmf/Query.h \
qmf/QueryImpl.cpp \
qmf/QueryImpl.h \
qmf/ResilientConnection.cpp \
qmf/ResilientConnection.h \
+ qmf/SequenceManager.cpp \
+ qmf/SequenceManager.h \
qmf/Schema.h \
qmf/SchemaImpl.cpp \
qmf/SchemaImpl.h \
diff --git a/qpid/cpp/src/qmf/AgentEngine.cpp b/qpid/cpp/src/qmf/AgentEngine.cpp
index bef8b3d102..9ea3be5907 100644
--- a/qpid/cpp/src/qmf/AgentEngine.cpp
+++ b/qpid/cpp/src/qmf/AgentEngine.cpp
@@ -25,6 +25,7 @@
#include "qmf/ObjectIdImpl.h"
#include "qmf/QueryImpl.h"
#include "qmf/ValueImpl.h"
+#include "qmf/Protocol.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/Uuid.h>
#include <qpid/framing/FieldTable.h>
@@ -56,7 +57,7 @@ namespace qmf {
string name;
Object* object;
boost::shared_ptr<ObjectId> objectId;
- Query query;
+ boost::shared_ptr<Query> query;
boost::shared_ptr<Value> arguments;
string exchange;
string bindingKey;
@@ -85,9 +86,9 @@ namespace qmf {
void setStoreDir(const char* path);
void setTransferDir(const char* path);
void handleRcvMessage(Message& message);
- bool getXmtMessage(Message& item);
+ bool getXmtMessage(Message& item) const;
void popXmt();
- bool getEvent(AgentEvent& event);
+ bool getEvent(AgentEvent& event) const;
void popEvent();
void newSession();
void startProtocol();
@@ -103,7 +104,7 @@ namespace qmf {
void raiseEvent(Event& event);
private:
- Mutex lock;
+ mutable Mutex lock;
Mutex addLock;
string label;
string queueName;
@@ -134,13 +135,13 @@ namespace qmf {
# define MA_BUFFER_SIZE 65536
char outputBuffer[MA_BUFFER_SIZE];
- struct SchemaClassKey {
+ struct AgentClassKey {
string name;
uint8_t hash[16];
- SchemaClassKey(const string& n, const uint8_t* h) : name(n) {
+ AgentClassKey(const string& n, const uint8_t* h) : name(n) {
memcpy(hash, h, 16);
}
- SchemaClassKey(Buffer& buffer) {
+ AgentClassKey(Buffer& buffer) {
buffer.getShortString(name);
buffer.getBin128(hash);
}
@@ -149,8 +150,8 @@ namespace qmf {
}
};
- struct SchemaClassKeyComp {
- bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
+ struct AgentClassKeyComp {
+ bool operator() (const AgentClassKey& lhs, const AgentClassKey& rhs) const
{
if (lhs.name != rhs.name)
return lhs.name < rhs.name;
@@ -162,8 +163,8 @@ namespace qmf {
}
};
- typedef map<SchemaClassKey, SchemaObjectClassImpl*, SchemaClassKeyComp> ObjectClassMap;
- typedef map<SchemaClassKey, SchemaEventClassImpl*, SchemaClassKeyComp> EventClassMap;
+ typedef map<AgentClassKey, SchemaObjectClassImpl*, AgentClassKeyComp> ObjectClassMap;
+ typedef map<AgentClassKey, SchemaEventClassImpl*, AgentClassKeyComp> EventClassMap;
struct ClassMaps {
ObjectClassMap objectClasses;
@@ -172,8 +173,6 @@ namespace qmf {
map<string, ClassMaps> packages;
- bool checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq);
- void encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq = 0);
AgentEventImpl::Ptr eventDeclareQueue(const string& queueName);
AgentEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key);
AgentEventImpl::Ptr eventSetupComplete();
@@ -185,7 +184,7 @@ namespace qmf {
void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
void sendPackageIndicationLH(const string& packageName);
- void sendClassIndicationLH(ClassKind kind, const string& packageName, const SchemaClassKey& key);
+ void sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key);
void sendCommandCompleteLH(const string& exchange, const string& key, uint32_t seq,
uint32_t code = 0, const string& text = "OK");
void sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text="");
@@ -215,7 +214,7 @@ AgentEvent AgentEventImpl::copy()
item.sequence = sequence;
item.object = object;
item.objectId = objectId.get();
- item.query = &query;
+ item.query = query.get();
item.arguments = arguments.get();
item.objectClass = objectClass;
@@ -268,16 +267,20 @@ void AgentEngineImpl::handleRcvMessage(Message& message)
string replyToKey(message.replyKey ? message.replyKey : "");
string userId(message.userId ? message.userId : "");
- if (checkHeader(inBuffer, &opcode, &sequence)) {
- if (opcode == 'a') handleAttachResponse(inBuffer);
- else if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
- else if (opcode == 'x') handleConsoleAddedIndication();
- else if (opcode == 'G') handleGetQuery(inBuffer, sequence, replyToKey, userId);
- else if (opcode == 'M') handleMethodRequest(inBuffer, sequence, replyToKey, userId);
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence)) {
+ if (opcode == Protocol::OP_ATTACH_RESPONSE) handleAttachResponse(inBuffer);
+ else if (opcode == Protocol::OP_SCHEMA_REQUEST) handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
+ else if (opcode == Protocol::OP_CONSOLE_ADDED_INDICATION) handleConsoleAddedIndication();
+ else if (opcode == Protocol::OP_GET_QUERY) handleGetQuery(inBuffer, sequence, replyToKey, userId);
+ else if (opcode == Protocol::OP_METHOD_REQUEST) handleMethodRequest(inBuffer, sequence, replyToKey, userId);
+ else {
+ QPID_LOG(error, "AgentEngineImpl::handleRcvMessage invalid opcode=" << opcode);
+ break;
+ }
}
}
-bool AgentEngineImpl::getXmtMessage(Message& item)
+bool AgentEngineImpl::getXmtMessage(Message& item) const
{
Mutex::ScopedLock _lock(lock);
if (xmtQueue.empty())
@@ -293,7 +296,7 @@ void AgentEngineImpl::popXmt()
xmtQueue.pop_front();
}
-bool AgentEngineImpl::getEvent(AgentEvent& event)
+bool AgentEngineImpl::getEvent(AgentEvent& event) const
{
Mutex::ScopedLock _lock(lock);
if (eventQueue.empty())
@@ -325,7 +328,7 @@ void AgentEngineImpl::startProtocol()
char rawbuffer[512];
Buffer buffer(rawbuffer, 512);
- encodeHeader(buffer, 'A');
+ Protocol::encodeHeader(buffer, Protocol::OP_ATTACH_REQUEST);
buffer.putShortString("qmfa");
systemId.encode(buffer);
buffer.putLong(requestedBrokerBank);
@@ -340,7 +343,7 @@ void AgentEngineImpl::heartbeat()
Mutex::ScopedLock _lock(lock);
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'h');
+ Protocol::encodeHeader(buffer, Protocol::OP_HEARTBEAT_INDICATION);
buffer.putLongLong(uint64_t(Duration(now())));
stringstream key;
key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank;
@@ -349,7 +352,7 @@ void AgentEngineImpl::heartbeat()
}
void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
- const Value& argMap)
+ const Value& argMap)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -359,7 +362,7 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t
contextMap.erase(iter);
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'm', context->sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, context->sequence);
buffer.putLong(status);
buffer.putMediumString(text);
if (status == 0) {
@@ -378,7 +381,7 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t
}
}
sendBufferLH(buffer, context->exchange, context->key);
- QPID_LOG(trace, "SENT MethodResponse");
+ QPID_LOG(trace, "SENT MethodResponse seq=" << context->sequence << " status=" << status << " text=" << text);
}
void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
@@ -390,7 +393,7 @@ void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop
AgentQueryContext::Ptr context = iter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'g', context->sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_OBJECT_INDICATION, context->sequence);
object.impl->encodeSchemaKey(buffer);
object.impl->encodeManagedObjectData(buffer);
@@ -400,7 +403,7 @@ void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop
object.impl->encodeStatistics(buffer);
sendBufferLH(buffer, context->exchange, context->key);
- QPID_LOG(trace, "SENT ContentIndication");
+ QPID_LOG(trace, "SENT ContentIndication seq=" << context->sequence);
}
void AgentEngineImpl::queryComplete(uint32_t sequence)
@@ -423,11 +426,11 @@ void AgentEngineImpl::registerClass(SchemaObjectClass* cls)
map<string, ClassMaps>::iterator iter = packages.find(impl->package);
if (iter == packages.end()) {
packages[impl->package] = ClassMaps();
- iter = packages.find(impl->package);
+ iter = packages.find(impl->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- SchemaClassKey key(impl->name, impl->getHash());
+ AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
iter->second.objectClasses[key] = impl;
// TODO: Indicate this schema if connected.
@@ -441,11 +444,11 @@ void AgentEngineImpl::registerClass(SchemaEventClass* cls)
map<string, ClassMaps>::iterator iter = packages.find(impl->package);
if (iter == packages.end()) {
packages[impl->package] = ClassMaps();
- iter = packages.find(impl->package);
+ iter = packages.find(impl->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- SchemaClassKey key(impl->name, impl->getHash());
+ AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
iter->second.eventClasses[key] = impl;
// TODO: Indicate this schema if connected.
@@ -477,30 +480,6 @@ void AgentEngineImpl::raiseEvent(Event&)
Mutex::ScopedLock _lock(lock);
}
-void AgentEngineImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq)
-{
- buf.putOctet('A');
- buf.putOctet('M');
- buf.putOctet('3');
- buf.putOctet(opcode);
- buf.putLong (seq);
-}
-
-bool AgentEngineImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
-{
- if (buf.getSize() < 8)
- return false;
-
- uint8_t h1 = buf.getOctet();
- uint8_t h2 = buf.getOctet();
- uint8_t h3 = buf.getOctet();
-
- *opcode = buf.getOctet();
- *seq = buf.getLong();
-
- return h1 == 'A' && h2 == 'M' && h3 == '3';
-}
-
AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE));
@@ -532,9 +511,10 @@ AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& user
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::GET_QUERY));
event->sequence = num;
event->authUserId = userId;
- event->query.impl->packageName = package;
- event->query.impl->className = cls;
- event->query.impl->oid = oid;
+ if (oid.get())
+ event->query.reset(new Query(oid.get()));
+ else
+ event->query.reset(new Query(cls.c_str(), package.c_str()));
return event;
}
@@ -570,16 +550,16 @@ void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const
void AgentEngineImpl::sendPackageIndicationLH(const string& packageName)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'p');
+ Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION);
buffer.putShortString(packageName);
sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName);
}
-void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const SchemaClassKey& key)
+void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'q');
+ Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION);
buffer.putOctet((int) kind);
buffer.putShortString(packageName);
buffer.putShortString(key.name);
@@ -592,7 +572,7 @@ void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string
uint32_t sequence, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'z', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_COMMAND_COMPLETE, sequence);
buffer.putLong(code);
buffer.putShortString(text);
sendBufferLH(buffer, exchange, replyToKey);
@@ -602,7 +582,7 @@ void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string
void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'm', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence);
buffer.putLong(code);
string fulltext;
@@ -690,7 +670,7 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
string rKey(replyKey);
string packageName;
inBuffer.getShortString(packageName);
- SchemaClassKey key(inBuffer);
+ AgentClassKey key(inBuffer);
if (rExchange.empty())
rExchange = QMF_EXCHANGE;
@@ -710,7 +690,7 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
if (ocIter != cMap.objectClasses.end()) {
SchemaObjectClassImpl* oImpl = ocIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 's', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
oImpl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name);
@@ -721,7 +701,7 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
if (ecIter != cMap.eventClasses.end()) {
SchemaEventClassImpl* eImpl = ecIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 's', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
eImpl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name);
@@ -744,7 +724,7 @@ void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const
ft.decode(inBuffer);
- QPID_LOG(trace, "RCVD GetQuery: map=" << ft);
+ QPID_LOG(trace, "RCVD GetQuery: seq=" << sequence << " map=" << ft);
value = ft.get("_package");
if (value.get() && value->convertsTo<string>()) {
@@ -791,9 +771,11 @@ void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, con
ObjectIdImpl* oidImpl = new ObjectIdImpl(buffer);
boost::shared_ptr<ObjectId> oid(oidImpl->envelope);
buffer.getShortString(pname);
- SchemaClassKey classKey(buffer);
+ AgentClassKey classKey(buffer);
buffer.getShortString(method);
+ QPID_LOG(trace, "RCVD MethodRequest seq=" << sequence << " method=" << method);
+
map<string, ClassMaps>::const_iterator pIter = packages.find(pname);
if (pIter == packages.end()) {
sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_PACKAGE, pname);
@@ -851,108 +833,25 @@ void AgentEngineImpl::handleConsoleAddedIndication()
// Wrappers
//==================================================================
-AgentEngine::AgentEngine(char* label, bool internalStore)
-{
- impl = new AgentEngineImpl(label, internalStore);
-}
-
-AgentEngine::~AgentEngine()
-{
- delete impl;
-}
-
-void AgentEngine::setStoreDir(const char* path)
-{
- impl->setStoreDir(path);
-}
-
-void AgentEngine::setTransferDir(const char* path)
-{
- impl->setTransferDir(path);
-}
-
-void AgentEngine::handleRcvMessage(Message& message)
-{
- impl->handleRcvMessage(message);
-}
-
-bool AgentEngine::getXmtMessage(Message& item)
-{
- return impl->getXmtMessage(item);
-}
-
-void AgentEngine::popXmt()
-{
- impl->popXmt();
-}
-
-bool AgentEngine::getEvent(AgentEvent& event)
-{
- return impl->getEvent(event);
-}
-
-void AgentEngine::popEvent()
-{
- impl->popEvent();
-}
-
-void AgentEngine::newSession()
-{
- impl->newSession();
-}
-
-void AgentEngine::startProtocol()
-{
- impl->startProtocol();
-}
-
-void AgentEngine::heartbeat()
-{
- impl->heartbeat();
-}
-
-void AgentEngine::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments)
-{
- impl->methodResponse(sequence, status, text, arguments);
-}
-
-void AgentEngine::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
-{
- impl->queryResponse(sequence, object, prop, stat);
-}
-
-void AgentEngine::queryComplete(uint32_t sequence)
-{
- impl->queryComplete(sequence);
-}
-
-void AgentEngine::registerClass(SchemaObjectClass* cls)
-{
- impl->registerClass(cls);
-}
-
-void AgentEngine::registerClass(SchemaEventClass* cls)
-{
- impl->registerClass(cls);
-}
-
-const ObjectId* AgentEngine::addObject(Object& obj, uint64_t persistId)
-{
- return impl->addObject(obj, persistId);
-}
-
-const ObjectId* AgentEngine::allocObjectId(uint64_t persistId)
-{
- return impl->allocObjectId(persistId);
-}
-
-const ObjectId* AgentEngine::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
-{
- return impl->allocObjectId(persistIdLo, persistIdHi);
-}
-
-void AgentEngine::raiseEvent(Event& event)
-{
- impl->raiseEvent(event);
-}
+AgentEngine::AgentEngine(char* label, bool internalStore) { impl = new AgentEngineImpl(label, internalStore); }
+AgentEngine::~AgentEngine() { delete impl; }
+void AgentEngine::setStoreDir(const char* path) { impl->setStoreDir(path); }
+void AgentEngine::setTransferDir(const char* path) { impl->setTransferDir(path); }
+void AgentEngine::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool AgentEngine::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void AgentEngine::popXmt() { impl->popXmt(); }
+bool AgentEngine::getEvent(AgentEvent& event) const { return impl->getEvent(event); }
+void AgentEngine::popEvent() { impl->popEvent(); }
+void AgentEngine::newSession() { impl->newSession(); }
+void AgentEngine::startProtocol() { impl->startProtocol(); }
+void AgentEngine::heartbeat() { impl->heartbeat(); }
+void AgentEngine::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments) { impl->methodResponse(sequence, status, text, arguments); }
+void AgentEngine::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { impl->queryResponse(sequence, object, prop, stat); }
+void AgentEngine::queryComplete(uint32_t sequence) { impl->queryComplete(sequence); }
+void AgentEngine::registerClass(SchemaObjectClass* cls) { impl->registerClass(cls); }
+void AgentEngine::registerClass(SchemaEventClass* cls) { impl->registerClass(cls); }
+const ObjectId* AgentEngine::addObject(Object& obj, uint64_t persistId) { return impl->addObject(obj, persistId); }
+const ObjectId* AgentEngine::allocObjectId(uint64_t persistId) { return impl->allocObjectId(persistId); }
+const ObjectId* AgentEngine::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return impl->allocObjectId(persistIdLo, persistIdHi); }
+void AgentEngine::raiseEvent(Event& event) { impl->raiseEvent(event); }
diff --git a/qpid/cpp/src/qmf/AgentEngine.h b/qpid/cpp/src/qmf/AgentEngine.h
index d18a104e96..c88ef33657 100644
--- a/qpid/cpp/src/qmf/AgentEngine.h
+++ b/qpid/cpp/src/qmf/AgentEngine.h
@@ -101,7 +101,7 @@ namespace qmf {
*@param item The Message structure describing the message to be produced.
*@return true if the Message is valid, false if there are no messages to send.
*/
- bool getXmtMessage(Message& item);
+ bool getXmtMessage(Message& item) const;
/**
* Remove and discard one message from the head of the transmit queue.
@@ -113,7 +113,7 @@ namespace qmf {
*@param event The event iff the return value is true
*@return true if event is valid, false if there are no events to process
*/
- bool getEvent(AgentEvent& event);
+ bool getEvent(AgentEvent& event) const;
/**
* Remove and discard one event from the head of the event queue.
@@ -182,7 +182,7 @@ namespace qmf {
*@return The objectId of the managed object.
*/
const ObjectId* addObject(Object& obj, uint64_t persistId);
- const ObjectId* addObject(Object& obj, uint32_t persistIdLo, uint32_t persistIdHi);
+ // const ObjectId* addObject(Object& obj, uint32_t persistIdLo, uint32_t persistIdHi);
/**
* Allocate an object-id for an object that will be managed by the application.
diff --git a/qpid/cpp/src/qmf/BrokerProxyImpl.cpp b/qpid/cpp/src/qmf/BrokerProxyImpl.cpp
new file mode 100644
index 0000000000..47dca309d7
--- /dev/null
+++ b/qpid/cpp/src/qmf/BrokerProxyImpl.cpp
@@ -0,0 +1,663 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/BrokerProxyImpl.h"
+#include "qmf/ConsoleEngineImpl.h"
+#include "qmf/Protocol.h"
+#include "qpid/Address.h"
+#include "qpid/sys/SystemInfo.h"
+#include <qpid/log/Statement.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+ const char* DIR_EXCHANGE = "amq.direct";
+ const char* BROKER_KEY = "broker";
+ const char* BROKER_PACKAGE = "org.apache.qpid.broker";
+ const char* AGENT_CLASS = "agent";
+ const char* BROKER_AGENT_KEY = "agent.1.0";
+}
+
+const Object* QueryResponseImpl::getObject(uint32_t idx) const
+{
+ vector<ObjectImpl::Ptr>::const_iterator iter = results.begin();
+
+ while (idx > 0) {
+ if (iter == results.end())
+ return 0;
+ iter++;
+ idx--;
+ }
+
+ return (*iter)->envelope;
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+BrokerEvent BrokerEventImpl::copy()
+{
+ BrokerEvent item;
+
+ ::memset(&item, 0, sizeof(BrokerEvent));
+ item.kind = kind;
+
+ STRING_REF(name);
+ STRING_REF(exchange);
+ STRING_REF(bindingKey);
+ item.context = context;
+ item.queryResponse = queryResponse.get() ? queryResponse->envelope : 0;
+ item.methodResponse = methodResponse.get() ? methodResponse->envelope : 0;
+
+ return item;
+}
+
+BrokerProxyImpl::BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console) :
+ envelope(e), console(_console.impl)
+{
+ stringstream qn;
+ qpid::TcpAddress addr;
+
+ SystemInfo::getLocalHostname(addr);
+ qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId();
+ queueName = qn.str();
+
+ seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this)));
+}
+
+void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+ eventQueue.push_back(eventDeclareQueue(queueName));
+ eventQueue.push_back(eventBind(DIR_EXCHANGE, queueName, queueName));
+ eventQueue.push_back(eventSetupComplete());
+
+ // TODO: Store session handle
+}
+
+void BrokerProxyImpl::sessionClosed()
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+}
+
+void BrokerProxyImpl::startProtocol()
+{
+ Mutex::ScopedLock _lock(lock);
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ agentList.push_back(AgentProxyImpl::Ptr(new AgentProxyImpl(console, this, 0, "Agent embedded in broker")));
+
+ requestsOutstanding = 1;
+ topicBound = false;
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence);
+}
+
+void BrokerProxyImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+{
+ uint32_t length = buf.getPosition();
+ MessageImpl::Ptr message(new MessageImpl);
+
+ buf.reset();
+ buf.getRawData(message->body, length);
+ message->destination = destination;
+ message->routingKey = routingKey;
+ message->replyExchange = DIR_EXCHANGE;
+ message->replyKey = queueName;
+
+ xmtQueue.push_back(message);
+}
+
+void BrokerProxyImpl::handleRcvMessage(Message& message)
+{
+ Buffer inBuffer(message.body, message.length);
+ uint8_t opcode;
+ uint32_t sequence;
+
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence))
+ seqMgr.dispatch(opcode, sequence, inBuffer);
+}
+
+bool BrokerProxyImpl::getXmtMessage(Message& item) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (xmtQueue.empty())
+ return false;
+ item = xmtQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popXmt()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!xmtQueue.empty())
+ xmtQueue.pop_front();
+}
+
+bool BrokerProxyImpl::getEvent(BrokerEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+uint32_t BrokerProxyImpl::agentCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return agentList.size();
+}
+
+const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++)
+ if (idx-- == 0)
+ return (*iter)->envelope;
+ return 0;
+}
+
+void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent)
+{
+ SequenceContext::Ptr queryContext(new QueryContext(*this, context));
+ Mutex::ScopedLock _lock(lock);
+ if (agent != 0) {
+ sendGetRequestLH(queryContext, query, agent->impl);
+ } else {
+ // TODO (optimization) only send queries to agents that have the requested class+package
+ for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++) {
+ sendGetRequestLH(queryContext, query, (*iter).get());
+ }
+ }
+}
+
+void BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent)
+{
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(queryContext));
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ query.impl->encode(outBuffer);
+ key << "agent.1." << agent->agentBank;
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str());
+}
+
+string BrokerProxyImpl::encodeMethodArguments(const SchemaMethod* schema, const Value* argmap, Buffer& buffer)
+{
+ int argCount = schema->getArgumentCount();
+
+ if (argmap == 0 || !argmap->isMap())
+ return string("Arguments must be in a map value");
+
+ for (int aIdx = 0; aIdx < argCount; aIdx++) {
+ const SchemaArgument* arg(schema->getArgument(aIdx));
+ if (arg->getDirection() == DIR_IN || arg->getDirection() == DIR_IN_OUT) {
+ if (argmap->keyInMap(arg->getName())) {
+ const Value* argVal(argmap->byKey(arg->getName()));
+ if (argVal->getType() != arg->getType())
+ return string("Argument is the wrong type: ") + arg->getName();
+ argVal->impl->encode(buffer);
+ } else {
+ Value defaultValue(arg->getType());
+ defaultValue.impl->encode(buffer);
+ }
+ }
+ }
+
+ return string();
+}
+
+void BrokerProxyImpl::sendMethodRequest(ObjectIdImpl* oid, const SchemaObjectClass* cls,
+ const string& methodName, const Value* args, void* userContext)
+{
+ int methodCount = cls->getMethodCount();
+ int idx;
+ for (idx = 0; idx < methodCount; idx++) {
+ const SchemaMethod* method = cls->getMethod(idx);
+ if (string(method->getName()) == methodName) {
+ Mutex::ScopedLock _lock(lock);
+ SequenceContext::Ptr methodContext(new MethodContext(*this, userContext, method->impl));
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(methodContext));
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_METHOD_REQUEST, sequence);
+ oid->encode(outBuffer);
+ cls->getClassKey()->impl->encode(outBuffer);
+ outBuffer.putShortString(methodName);
+
+ string argErrorString = encodeMethodArguments(method, args, outBuffer);
+ if (argErrorString.empty()) {
+ key << "agent.1." << oid->getAgentBank();
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT MethodRequest seq=" << sequence << " method=" << methodName << " key=" << key.str());
+ } else {
+ MethodResponseImpl::Ptr argError(new MethodResponseImpl(1, argErrorString));
+ eventQueue.push_back(eventMethodResponse(userContext, argError));
+ }
+ return;
+ }
+ }
+
+ MethodResponseImpl::Ptr error(new MethodResponseImpl(1, string("Unknown method: ") + methodName));
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventMethodResponse(userContext, error));
+}
+
+void BrokerProxyImpl::addBinding(const string& exchange, const string& key)
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventDeclareQueue(const string& queueName)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::DECLARE_QUEUE));
+ event->name = queueName;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventBind(const string& exchange, const string& queue, const string& key)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::BIND));
+ event->name = queue;
+ event->exchange = exchange;
+ event->bindingKey = key;
+
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::SETUP_COMPLETE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventStable()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponseImpl::Ptr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE));
+ event->context = context;
+ event->queryResponse = response;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventMethodResponse(void* context, MethodResponseImpl::Ptr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::METHOD_RESPONSE));
+ event->context = context;
+ event->methodResponse = response;
+ return event;
+}
+
+void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq)
+{
+ brokerId.decode(inBuffer);
+ QPID_LOG(trace, "RCVD BrokerResponse seq=" << seq << " brokerId=" << brokerId);
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_PACKAGE_REQUEST, sequence);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT PackageRequest seq=" << sequence);
+}
+
+void BrokerProxyImpl::handlePackageIndication(Buffer& inBuffer, uint32_t seq)
+{
+ string package;
+
+ inBuffer.getShortString(package);
+ QPID_LOG(trace, "RCVD PackageIndication seq=" << seq << " package=" << package);
+ console->learnPackage(package);
+
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_CLASS_QUERY, sequence);
+ outBuffer.putShortString(package);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT ClassQuery seq=" << sequence << " package=" << package);
+}
+
+void BrokerProxyImpl::handleCommandComplete(Buffer& inBuffer, uint32_t seq)
+{
+ string text;
+ uint32_t code = inBuffer.getLong();
+ inBuffer.getShortString(text);
+ QPID_LOG(trace, "RCVD CommandComplete seq=" << seq << " code=" << code << " text=" << text);
+}
+
+void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq)
+{
+ uint8_t kind = inBuffer.getOctet();
+ SchemaClassKeyImpl classKey(inBuffer);
+
+ QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey.str());
+
+ if (!console->haveClass(classKey)) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence);
+ classKey.encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey.str());
+ }
+}
+
+MethodResponseImpl::Ptr BrokerProxyImpl::handleMethodResponse(Buffer& inBuffer, uint32_t seq, SchemaMethodImpl* schema)
+{
+ MethodResponseImpl::Ptr response(new MethodResponseImpl(inBuffer, schema));
+
+ QPID_LOG(trace, "RCVD MethodResponse seq=" << seq << " status=" << response->getStatus() << " text=" <<
+ response->getException()->asString());
+
+ return response;
+}
+
+void BrokerProxyImpl::handleHeartbeatIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq)
+{
+ SchemaObjectClassImpl::Ptr oClassPtr;
+ SchemaEventClassImpl::Ptr eClassPtr;
+ uint8_t kind = inBuffer.getOctet();
+ const SchemaClassKeyImpl* key;
+ if (kind == CLASS_OBJECT) {
+ oClassPtr.reset(new SchemaObjectClassImpl(inBuffer));
+ console->learnClass(oClassPtr);
+ key = oClassPtr->getClassKey()->impl;
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->str());
+
+ //
+ // If we have just learned about the org.apache.qpid.broker:agent class, send a get
+ // request for the current list of agents so we can have it on-hand before we declare
+ // this session "stable".
+ //
+ if (key->getClassName() == AGENT_CLASS && key->getPackageName() == BROKER_PACKAGE) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ FieldTable ft;
+ ft.setString("_class", AGENT_CLASS);
+ ft.setString("_package", BROKER_PACKAGE);
+ ft.encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY);
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY);
+ }
+ } else if (kind == CLASS_EVENT) {
+ eClassPtr.reset(new SchemaEventClassImpl(inBuffer));
+ console->learnClass(eClassPtr);
+ key = eClassPtr->getClassKey()->impl;
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->str());
+ }
+ else {
+ QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind);
+ }
+}
+
+ObjectImpl::Ptr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat)
+{
+ SchemaClassKeyImpl classKey(inBuffer);
+ QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey.str());
+
+ SchemaObjectClassImpl::Ptr schema = console->getSchema(classKey);
+ if (schema.get() == 0) {
+ QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey.str());
+ return ObjectImpl::Ptr();
+ }
+
+ return ObjectImpl::Ptr(new ObjectImpl(schema->envelope, this, inBuffer, prop, stat, true));
+}
+
+void BrokerProxyImpl::incOutstandingLH()
+{
+ requestsOutstanding++;
+}
+
+void BrokerProxyImpl::decOutstanding()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding--;
+ if (requestsOutstanding == 0 && !topicBound) {
+ topicBound = true;
+ for (vector<pair<string, string> >::const_iterator iter = console->bindingList.begin();
+ iter != console->bindingList.end(); iter++) {
+ string exchange(iter->first.empty() ? QMF_EXCHANGE : iter->first);
+ string key(iter->second);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+ }
+ eventQueue.push_back(eventStable());
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(const MethodResponseImpl& from) :
+ envelope(from.envelope), // !!!! TODO !!!! this is not right
+ status(from.status), schema(from.schema),
+ exception(from.exception.get() ? new Value(*from.exception) : 0),
+ arguments(from.arguments.get() ? new Value(*from.arguments) : 0)
+{
+}
+
+MethodResponseImpl::MethodResponseImpl(Buffer& buf, SchemaMethodImpl* s) :
+ envelope(new MethodResponse(this)), schema(s)
+{
+ string text;
+
+ status = buf.getLong();
+ buf.getMediumString(text);
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+
+ if (status != 0)
+ return;
+
+ arguments.reset(new Value(TYPE_MAP));
+ int argCount(schema->getArgumentCount());
+ for (int idx = 0; idx < argCount; idx++) {
+ const SchemaArgument* arg = schema->getArgument(idx);
+ if (arg->getDirection() == DIR_OUT || arg->getDirection() == DIR_IN_OUT) {
+ ValueImpl* value(new ValueImpl(arg->getType(), buf));
+ arguments->insert(arg->getName(), value->envelope);
+ }
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(uint32_t s, const string& text) : envelope(new MethodResponse(this)), schema(0)
+{
+ status = s;
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+}
+
+bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer)
+{
+ bool completeContext = false;
+ if (opcode == Protocol::OP_BROKER_RESPONSE) {
+ broker.handleBrokerResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_SCHEMA_RESPONSE) {
+ broker.handleSchemaResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_PACKAGE_INDICATION)
+ broker.handlePackageIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_CLASS_INDICATION)
+ broker.handleClassIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_HEARTBEAT_INDICATION)
+ broker.handleHeartbeatIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_EVENT_INDICATION)
+ broker.handleEventIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_PROPERTY_INDICATION)
+ broker.handleObjectIndication(buffer, sequence, true, false);
+ else if (opcode == Protocol::OP_STATISTIC_INDICATION)
+ broker.handleObjectIndication(buffer, sequence, false, true);
+ else if (opcode == Protocol::OP_OBJECT_INDICATION)
+ broker.handleObjectIndication(buffer, sequence, true, true);
+ else {
+ QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void QueryContext::reserve()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding++;
+}
+
+void QueryContext::release()
+{
+ {
+ Mutex::ScopedLock _lock(lock);
+ if (--requestsOutstanding > 0)
+ return;
+ }
+
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse));
+}
+
+bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer)
+{
+ bool completeContext = false;
+ ObjectImpl::Ptr object;
+
+ if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, true);
+ if (object.get() != 0)
+ queryResponse->results.push_back(object);
+ }
+ else {
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void MethodContext::release()
+{
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventMethodResponse(userContext, methodResponse));
+}
+
+bool MethodContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer)
+{
+ if (opcode == Protocol::OP_METHOD_RESPONSE)
+ methodResponse = broker.handleMethodResponse(buffer, sequence, schema);
+ else
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+
+ return true;
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {}
+AgentProxy::~AgentProxy() { delete impl; }
+const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); }
+
+BrokerProxy::BrokerProxy(ConsoleEngine& console) : impl(new BrokerProxyImpl(this, console)) {}
+BrokerProxy::~BrokerProxy() { delete impl; }
+void BrokerProxy::sessionOpened(SessionHandle& sh) { impl->sessionOpened(sh); }
+void BrokerProxy::sessionClosed() { impl->sessionClosed(); }
+void BrokerProxy::startProtocol() { impl->startProtocol(); }
+void BrokerProxy::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool BrokerProxy::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void BrokerProxy::popXmt() { impl->popXmt(); }
+bool BrokerProxy::getEvent(BrokerEvent& event) const { return impl->getEvent(event); }
+void BrokerProxy::popEvent() { impl->popEvent(); }
+uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); }
+const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); }
+void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); }
+
+MethodResponse::MethodResponse(const MethodResponse& from) : impl(new MethodResponseImpl(*(from.impl))) {}
+MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {}
+MethodResponse::~MethodResponse() {}
+uint32_t MethodResponse::getStatus() const { return impl->getStatus(); }
+const Value* MethodResponse::getException() const { return impl->getException(); }
+const Value* MethodResponse::getArgs() const { return impl->getArgs(); }
+
+QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {}
+QueryResponse::~QueryResponse() {}
+uint32_t QueryResponse::getStatus() const { return impl->getStatus(); }
+const Value* QueryResponse::getException() const { return impl->getException(); }
+uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); }
+const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); }
+
diff --git a/qpid/cpp/src/qmf/BrokerProxyImpl.h b/qpid/cpp/src/qmf/BrokerProxyImpl.h
new file mode 100644
index 0000000000..930d8c8995
--- /dev/null
+++ b/qpid/cpp/src/qmf/BrokerProxyImpl.h
@@ -0,0 +1,222 @@
+#ifndef _QmfBrokerProxyImpl_
+#define _QmfBrokerProxyImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/ConsoleEngine.h"
+#include "qmf/ObjectImpl.h"
+#include "qmf/SchemaImpl.h"
+#include "qmf/ValueImpl.h"
+#include "qmf/QueryImpl.h"
+#include "qmf/SequenceManager.h"
+#include "qmf/MessageImpl.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "boost/shared_ptr.hpp"
+#include <memory>
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+
+namespace qmf {
+
+ struct MethodResponseImpl {
+ typedef boost::shared_ptr<MethodResponseImpl> Ptr;
+ MethodResponse* envelope;
+ uint32_t status;
+ SchemaMethodImpl* schema;
+ boost::shared_ptr<Value> exception;
+ boost::shared_ptr<Value> arguments;
+
+ MethodResponseImpl(const MethodResponseImpl& from);
+ MethodResponseImpl(qpid::framing::Buffer& buf, SchemaMethodImpl* schema);
+ MethodResponseImpl(uint32_t status, const std::string& text);
+ ~MethodResponseImpl() { delete envelope; }
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ const Value* getArgs() const { return arguments.get(); }
+ };
+
+ struct QueryResponseImpl {
+ typedef boost::shared_ptr<QueryResponseImpl> Ptr;
+ QueryResponse *envelope;
+ uint32_t status;
+ std::auto_ptr<Value> exception;
+ std::vector<ObjectImpl::Ptr> results;
+
+ QueryResponseImpl() : envelope(new QueryResponse(this)), status(0) {}
+ ~QueryResponseImpl() { delete envelope; }
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ uint32_t getObjectCount() const { return results.size(); }
+ const Object* getObject(uint32_t idx) const;
+ };
+
+ struct BrokerEventImpl {
+ typedef boost::shared_ptr<BrokerEventImpl> Ptr;
+ BrokerEvent::EventKind kind;
+ std::string name;
+ std::string exchange;
+ std::string bindingKey;
+ void* context;
+ QueryResponseImpl::Ptr queryResponse;
+ MethodResponseImpl::Ptr methodResponse;
+
+ BrokerEventImpl(BrokerEvent::EventKind k) : kind(k), context(0) {}
+ ~BrokerEventImpl() {}
+ BrokerEvent copy();
+ };
+
+ struct AgentProxyImpl {
+ typedef boost::shared_ptr<AgentProxyImpl> Ptr;
+ AgentProxy* envelope;
+ ConsoleEngineImpl* console;
+ BrokerProxyImpl* broker;
+ uint32_t agentBank;
+ std::string label;
+
+ AgentProxyImpl(ConsoleEngineImpl* c, BrokerProxyImpl* b, uint32_t ab, const std::string& l) :
+ envelope(new AgentProxy(this)), console(c), broker(b), agentBank(ab), label(l) {}
+ ~AgentProxyImpl() {}
+ const std::string& getLabel() const { return label; }
+ };
+
+ class BrokerProxyImpl {
+ public:
+ typedef boost::shared_ptr<BrokerProxyImpl> Ptr;
+
+ BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console);
+ ~BrokerProxyImpl() {}
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void sendBufferLH(qpid::framing::Buffer& buf, const std::string& destination, const std::string& routingKey);
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+ void sendQuery(const Query& query, void* context, const AgentProxy* agent);
+ void sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent);
+ std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer);
+ void sendMethodRequest(ObjectIdImpl* oid, const SchemaObjectClass* cls, const std::string& method, const Value* args, void* context);
+
+ void addBinding(const std::string& exchange, const std::string& key);
+ void staticRelease() { decOutstanding(); }
+
+ private:
+ friend class StaticContext;
+ friend class QueryContext;
+ friend class MethodContext;
+ mutable qpid::sys::Mutex lock;
+ BrokerProxy* envelope;
+ ConsoleEngineImpl* console;
+ std::string queueName;
+ qpid::framing::Uuid brokerId;
+ SequenceManager seqMgr;
+ uint32_t requestsOutstanding;
+ bool topicBound;
+ std::vector<AgentProxyImpl::Ptr> agentList;
+ std::deque<MessageImpl::Ptr> xmtQueue;
+ std::deque<BrokerEventImpl::Ptr> eventQueue;
+
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ BrokerEventImpl::Ptr eventDeclareQueue(const std::string& queueName);
+ BrokerEventImpl::Ptr eventBind(const std::string& exchange, const std::string& queue, const std::string& key);
+ BrokerEventImpl::Ptr eventSetupComplete();
+ BrokerEventImpl::Ptr eventStable();
+ BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponseImpl::Ptr response);
+ BrokerEventImpl::Ptr eventMethodResponse(void* context, MethodResponseImpl::Ptr response);
+
+ void handleBrokerResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handlePackageIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleCommandComplete(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleClassIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ MethodResponseImpl::Ptr handleMethodResponse(qpid::framing::Buffer& inBuffer, uint32_t seq, SchemaMethodImpl* schema);
+ void handleHeartbeatIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ ObjectImpl::Ptr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat);
+ void incOutstandingLH();
+ void decOutstanding();
+ };
+
+ //
+ // StaticContext is used to handle:
+ //
+ // 1) Responses to console-level requests (for schema info, etc.)
+ // 2) Unsolicited messages from agents (events, published updates, etc.)
+ //
+ struct StaticContext : public SequenceContext {
+ StaticContext(BrokerProxyImpl& b) : broker(b) {}
+ virtual ~StaticContext() {}
+ void reserve() {}
+ void release() { broker.staticRelease(); }
+ bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer);
+ BrokerProxyImpl& broker;
+ };
+
+ //
+ // QueryContext is used to track and handle responses associated with a single Get Query
+ //
+ struct QueryContext : public SequenceContext {
+ QueryContext(BrokerProxyImpl& b, void* u) :
+ broker(b), userContext(u), requestsOutstanding(0), queryResponse(new QueryResponseImpl()) {}
+ virtual ~QueryContext() {}
+ void reserve();
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer);
+
+ mutable qpid::sys::Mutex lock;
+ BrokerProxyImpl& broker;
+ void* userContext;
+ uint32_t requestsOutstanding;
+ QueryResponseImpl::Ptr queryResponse;
+ };
+
+ struct MethodContext : public SequenceContext {
+ MethodContext(BrokerProxyImpl& b, void* u, SchemaMethodImpl* s) : broker(b), userContext(u), schema(s) {}
+ virtual ~MethodContext() {}
+ void reserve() {}
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer);
+
+ BrokerProxyImpl& broker;
+ void* userContext;
+ SchemaMethodImpl* schema;
+ MethodResponseImpl::Ptr methodResponse;
+ };
+
+
+
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/ConsoleEngine.h b/qpid/cpp/src/qmf/ConsoleEngine.h
index 823e281b14..f04bbcea47 100644
--- a/qpid/cpp/src/qmf/ConsoleEngine.h
+++ b/qpid/cpp/src/qmf/ConsoleEngine.h
@@ -20,62 +20,201 @@
* under the License.
*/
-#include <qmf/ManagedConnection.h>
-#include <qmf/Broker.h>
-#include <qmf/Package.h>
-#include <qmf/SchemaClassTable.h>
+#include <qmf/ResilientConnection.h>
+#include <qmf/Schema.h>
+#include <qmf/ObjectId.h>
#include <qmf/Object.h>
-#include <qmf/ConsoleHandler.h>
-#include <set>
-#include <vector>
-#include <string>
+#include <qmf/Event.h>
+#include <qmf/Query.h>
+#include <qmf/Value.h>
+#include <qmf/Message.h>
namespace qmf {
+ class ConsoleEngine;
+ class ConsoleEngineImpl;
+ class BrokerProxyImpl;
+ class AgentProxy;
+ class AgentProxyImpl;
+ class MethodResponseImpl;
+ class QueryResponseImpl;
+ class QueryContext;
+
+ /**
+ *
+ */
+ class MethodResponse {
+ public:
+ MethodResponse(MethodResponseImpl* impl);
+ MethodResponse(const MethodResponse& from);
+ ~MethodResponse();
+ uint32_t getStatus() const;
+ const Value* getException() const;
+ const Value* getArgs() const;
+
+ private:
+ friend class ConsoleEngineImpl;
+ MethodResponseImpl* impl;
+ };
+
+ /**
+ *
+ */
+ class QueryResponse {
+ public:
+ QueryResponse(QueryResponseImpl* impl);
+ ~QueryResponse();
+ uint32_t getStatus() const;
+ const Value* getException() const;
+ uint32_t getObjectCount() const;
+ const Object* getObject(uint32_t idx) const;
+
+ private:
+ friend class QueryContext;
+ QueryResponseImpl *impl;
+ };
+
+ /**
+ *
+ */
+ struct ConsoleEvent {
+ enum EventKind {
+ AGENT_ADDED = 1,
+ AGENT_DELETED = 2,
+ NEW_PACKAGE = 3,
+ NEW_CLASS = 4,
+ OBJECT_UPDATE = 5,
+ EVENT_RECEIVED = 7,
+ AGENT_HEARTBEAT = 8
+ };
+
+ EventKind kind;
+ AgentProxy* agent; // (AGENT_[ADDED|DELETED|HEARTBEAT])
+ char* name; // (NEW_PACKAGE)
+ SchemaClassKey* classKey; // (NEW_CLASS)
+ Object* object; // (OBJECT_UPDATE)
+ void* context; // (OBJECT_UPDATE)
+ Event* event; // (EVENT_RECEIVED)
+ uint64_t timestamp; // (AGENT_HEARTBEAT)
+ QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ };
+
+ /**
+ *
+ */
+ struct BrokerEvent {
+ enum EventKind {
+ BROKER_INFO = 10,
+ DECLARE_QUEUE = 11,
+ DELETE_QUEUE = 12,
+ BIND = 13,
+ UNBIND = 14,
+ SETUP_COMPLETE = 15,
+ STABLE = 16,
+ QUERY_COMPLETE = 17,
+ METHOD_RESPONSE = 18
+ };
+
+ EventKind kind;
+ char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND)
+ char* exchange; // ([UN]BIND)
+ char* bindingKey; // ([UN]BIND)
+ void* context; // (QUERY_COMPLETE, METHOD_RESPONSE)
+ QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ MethodResponse* methodResponse; // (METHOD_RESPONSE)
+ };
+
+ /**
+ *
+ */
+ class AgentProxy {
+ public:
+ AgentProxy(AgentProxyImpl* impl);
+ ~AgentProxy();
+ const char* getLabel() const;
+
+ private:
+ friend class BrokerProxyImpl;
+ AgentProxyImpl* impl;
+ };
+
+ /**
+ *
+ */
+ class BrokerProxy {
+ public:
+ BrokerProxy(ConsoleEngine& console);
+ ~BrokerProxy();
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+ void sendQuery(const Query& query, void* context, const AgentProxy* agent = 0);
+
+ private:
+ friend class ConsoleEngineImpl;
+ BrokerProxyImpl* impl;
+ };
+
+ // TODO - move this to a public header
struct ConsoleSettings {
bool rcvObjects;
bool rcvEvents;
bool rcvHeartbeats;
bool userBindings;
- uint32_t methodTimeout;
- uint32_t getTimeout;
ConsoleSettings() :
rcvObjects(true),
rcvEvents(true),
rcvHeartbeats(true),
- userBindings(false),
- methodTimeout(20),
- getTimeout(20) {}
+ userBindings(false) {}
};
class ConsoleEngine {
public:
- ConsoleEngine(ConsoleHandler* handler = 0, ConsoleSettings settings = ConsoleSettings());
+ ConsoleEngine(const ConsoleSettings& settings = ConsoleSettings());
~ConsoleEngine();
- Broker* addConnection(ManagedConnection& connection);
- void delConnection(Broker* broker);
- void delConnection(ManagedConnection& connection);
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
- const PackageMap& getPackages() const;
+ uint32_t packageCount() const;
+ const char* getPackageName(uint32_t idx) const;
- void bindPackage(const Package& package);
- void bindPackage(const std::string& packageName);
- void bindClass(const SchemaClass& otype);
- void bindClass(const std::string& packageName, const std::string& className);
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
/*
- void getAgents(std::set<Agent>& agents, Broker* = 0);
- void getObjects(std::vector<Object>& objects, const std::string& typeName,
- const std::string& packageName = "",
- Broker* broker = 0,
- Agent* agent = 0);
- void getObjects(std::vector<Object>& objects,
- const std::map<std::string, std::string>& query,
- Broker* broker = 0,
- Agent* agent = 0);
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
*/
+
+ private:
+ friend class BrokerProxyImpl;
+ friend class AgentProxyImpl;
+ ConsoleEngineImpl* impl;
};
}
diff --git a/qpid/cpp/src/qmf/ConsoleEngineImpl.cpp b/qpid/cpp/src/qmf/ConsoleEngineImpl.cpp
new file mode 100644
index 0000000000..d71bf93105
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConsoleEngineImpl.cpp
@@ -0,0 +1,361 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/ConsoleEngineImpl.h"
+#include "qmf/MessageImpl.h"
+#include "qmf/SchemaImpl.h"
+#include "qmf/Typecode.h"
+#include "qmf/ObjectImpl.h"
+#include "qmf/ObjectIdImpl.h"
+#include "qmf/QueryImpl.h"
+#include "qmf/ValueImpl.h"
+#include "qmf/Protocol.h"
+#include "qmf/SequenceManager.h"
+#include "qmf/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/log/Statement.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+ConsoleEvent ConsoleEventImpl::copy()
+{
+ ConsoleEvent item;
+
+ ::memset(&item, 0, sizeof(ConsoleEvent));
+ item.kind = kind;
+ item.agent = agent.get() ? agent->envelope : 0;
+ item.classKey = classKey.get();
+ item.object = object;
+ item.context = context;
+ item.event = event;
+ item.timestamp = timestamp;
+
+ STRING_REF(name);
+
+ return item;
+}
+
+ConsoleEngineImpl::ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& s) :
+ envelope(e), settings(s)
+{
+ bindingList.push_back(pair<string, string>(string(), "schema.#"));
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingList.push_back(pair<string, string>(string(), "console.#"));
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingList.push_back(pair<string, string>(string(), "console.obj.#"));
+ else
+ bindingList.push_back(pair<string, string>(string(), "console.obj.*.*.org.apache.qpid.broker.agent"));
+ if (settings.rcvEvents)
+ bindingList.push_back(pair<string, string>(string(), "console.event.#"));
+ if (settings.rcvHeartbeats)
+ bindingList.push_back(pair<string, string>(string(), "console.heartbeat.#"));
+ }
+}
+
+ConsoleEngineImpl::~ConsoleEngineImpl()
+{
+ // This function intentionally left blank.
+}
+
+bool ConsoleEngineImpl::getEvent(ConsoleEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void ConsoleEngineImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void ConsoleEngineImpl::addConnection(BrokerProxy& broker, void* /*context*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ brokerList.push_back(broker.impl);
+}
+
+void ConsoleEngineImpl::delConnection(BrokerProxy& broker)
+{
+ Mutex::ScopedLock _lock(lock);
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ if (*iter == broker.impl) {
+ brokerList.erase(iter);
+ break;
+ }
+}
+
+uint32_t ConsoleEngineImpl::packageCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return packages.size();
+}
+
+const string& ConsoleEngineImpl::getPackageName(uint32_t idx) const
+{
+ const static string empty;
+
+ Mutex::ScopedLock _lock(lock);
+ if (idx >= packages.size())
+ return empty;
+
+ PackageList::const_iterator iter = packages.begin();
+ for (uint32_t i = 0; i < idx; i++) iter++;
+ return iter->first;
+}
+
+uint32_t ConsoleEngineImpl::classCount(const char* packageName) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.size() + eList.size();
+}
+
+const SchemaClassKey* ConsoleEngineImpl::getClass(const char* packageName, uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+ uint32_t count = 0;
+
+ for (ObjectClassList::const_iterator oIter = oList.begin();
+ oIter != oList.end(); oIter++) {
+ if (count == idx)
+ return oIter->second->getClassKey();
+ count++;
+ }
+
+ for (EventClassList::const_iterator eIter = eList.begin();
+ eIter != eList.end(); eIter++) {
+ if (count == idx)
+ return eIter->second->getClassKey();
+ count++;
+ }
+
+ return 0;
+}
+
+ClassKind ConsoleEngineImpl::getClassKind(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return CLASS_OBJECT;
+
+ const EventClassList& eList = pIter->second.second;
+ if (eList.find(key->impl) != eList.end())
+ return CLASS_EVENT;
+ return CLASS_OBJECT;
+}
+
+const SchemaObjectClass* ConsoleEngineImpl::getObjectClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key->impl);
+ if (iter == oList.end())
+ return 0;
+ return iter->second->envelope;
+}
+
+const SchemaEventClass* ConsoleEngineImpl::getEventClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const EventClassList& eList = pIter->second.second;
+ EventClassList::const_iterator iter = eList.find(key->impl);
+ if (iter == eList.end())
+ return 0;
+ return iter->second->envelope;
+}
+
+void ConsoleEngineImpl::bindPackage(const char* packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleEngineImpl::bindClass(const SchemaClassKey* classKey)
+{
+ stringstream key;
+ key << "console.obj.*.*." << classKey->getPackageName() << "." << classKey->getClassName() << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleEngineImpl::bindClass(const char* packageName, const char* className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+/*
+void ConsoleEngineImpl::startSync(const Query& query, void* context, SyncQuery& sync)
+{
+}
+
+void ConsoleEngineImpl::touchSync(SyncQuery& sync)
+{
+}
+
+void ConsoleEngineImpl::endSync(SyncQuery& sync)
+{
+}
+*/
+
+void ConsoleEngineImpl::learnPackage(const string& packageName)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (packages.find(packageName) == packages.end())
+ packages.insert(pair<string, pair<ObjectClassList, EventClassList> >
+ (packageName, pair<ObjectClassList, EventClassList>(ObjectClassList(), EventClassList())));
+}
+
+void ConsoleEngineImpl::learnClass(SchemaObjectClassImpl::Ptr cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ ObjectClassList& list = pIter->second.first;
+ if (list.find(key->impl) == list.end())
+ list[key->impl] = cls;
+}
+
+void ConsoleEngineImpl::learnClass(SchemaEventClassImpl::Ptr cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ EventClassList& list = pIter->second.second;
+ if (list.find(key->impl) == list.end())
+ list[key->impl] = cls;
+}
+
+bool ConsoleEngineImpl::haveClass(const SchemaClassKeyImpl& key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key.getPackageName());
+ if (pIter == packages.end())
+ return false;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.find(&key) != oList.end() || eList.find(&key) != eList.end();
+}
+
+SchemaObjectClassImpl::Ptr ConsoleEngineImpl::getSchema(const SchemaClassKeyImpl& key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key.getPackageName());
+ if (pIter == packages.end())
+ return SchemaObjectClassImpl::Ptr();
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(&key);
+ if (iter == oList.end())
+ return SchemaObjectClassImpl::Ptr();
+
+ return iter->second;
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+ConsoleEngine::ConsoleEngine(const ConsoleSettings& settings) : impl(new ConsoleEngineImpl(this, settings)) {}
+ConsoleEngine::~ConsoleEngine() { delete impl; }
+bool ConsoleEngine::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); }
+void ConsoleEngine::popEvent() { impl->popEvent(); }
+void ConsoleEngine::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); }
+void ConsoleEngine::delConnection(BrokerProxy& broker) { impl->delConnection(broker); }
+uint32_t ConsoleEngine::packageCount() const { return impl->packageCount(); }
+const char* ConsoleEngine::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); }
+uint32_t ConsoleEngine::classCount(const char* packageName) const { return impl->classCount(packageName); }
+const SchemaClassKey* ConsoleEngine::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); }
+ClassKind ConsoleEngine::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); }
+const SchemaObjectClass* ConsoleEngine::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); }
+const SchemaEventClass* ConsoleEngine::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); }
+void ConsoleEngine::bindPackage(const char* packageName) { impl->bindPackage(packageName); }
+void ConsoleEngine::bindClass(const SchemaClassKey* key) { impl->bindClass(key); }
+void ConsoleEngine::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); }
+//void ConsoleEngine::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); }
+//void ConsoleEngine::touchSync(SyncQuery& sync) { impl->touchSync(sync); }
+//void ConsoleEngine::endSync(SyncQuery& sync) { impl->endSync(sync); }
+
+
diff --git a/qpid/cpp/src/qmf/ConsoleEngineImpl.h b/qpid/cpp/src/qmf/ConsoleEngineImpl.h
new file mode 100644
index 0000000000..b95cb7523a
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConsoleEngineImpl.h
@@ -0,0 +1,133 @@
+#ifndef _QmfConsoleEngineImpl_
+#define _QmfConsoleEngineImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/ConsoleEngine.h"
+#include "qmf/MessageImpl.h"
+#include "qmf/SchemaImpl.h"
+#include "qmf/Typecode.h"
+#include "qmf/ObjectImpl.h"
+#include "qmf/ObjectIdImpl.h"
+#include "qmf/QueryImpl.h"
+#include "qmf/ValueImpl.h"
+#include "qmf/Protocol.h"
+#include "qmf/SequenceManager.h"
+#include "qmf/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+
+namespace qmf {
+
+ struct ConsoleEventImpl {
+ typedef boost::shared_ptr<ConsoleEventImpl> Ptr;
+ ConsoleEvent::EventKind kind;
+ boost::shared_ptr<AgentProxyImpl> agent;
+ std::string name;
+ boost::shared_ptr<SchemaClassKey> classKey;
+ Object* object;
+ void* context;
+ Event* event;
+ uint64_t timestamp;
+
+ ConsoleEventImpl(ConsoleEvent::EventKind k) :
+ kind(k), object(0), context(0), event(0), timestamp(0) {}
+ ~ConsoleEventImpl() {}
+ ConsoleEvent copy();
+ };
+
+ class ConsoleEngineImpl {
+ public:
+ ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& settings = ConsoleSettings());
+ ~ConsoleEngineImpl();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const std::string& getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ ConsoleEngine* envelope;
+ const ConsoleSettings& settings;
+ mutable qpid::sys::Mutex lock;
+ std::deque<ConsoleEventImpl::Ptr> eventQueue;
+ std::vector<BrokerProxyImpl*> brokerList;
+ std::vector<std::pair<std::string, std::string> > bindingList; // exchange/key (empty exchange => QMF_EXCHANGE)
+
+ // Declare a compare class for the class maps that compares the dereferenced
+ // class key pointers. The default behavior would be to compare the pointer
+ // addresses themselves.
+ struct KeyCompare {
+ bool operator()(const SchemaClassKeyImpl* left, const SchemaClassKeyImpl* right) const {
+ return *left < *right;
+ }
+ };
+
+ typedef std::map<const SchemaClassKeyImpl*, SchemaObjectClassImpl::Ptr, KeyCompare> ObjectClassList;
+ typedef std::map<const SchemaClassKeyImpl*, SchemaEventClassImpl::Ptr, KeyCompare> EventClassList;
+ typedef std::map<std::string, std::pair<ObjectClassList, EventClassList> > PackageList;
+
+ PackageList packages;
+
+ void learnPackage(const std::string& packageName);
+ void learnClass(SchemaObjectClassImpl::Ptr cls);
+ void learnClass(SchemaEventClassImpl::Ptr cls);
+ bool haveClass(const SchemaClassKeyImpl& key) const;
+ SchemaObjectClassImpl::Ptr getSchema(const SchemaClassKeyImpl& key) const;
+ };
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/Object.h b/qpid/cpp/src/qmf/Object.h
index eb92cbbe45..db89dbb700 100644
--- a/qpid/cpp/src/qmf/Object.h
+++ b/qpid/cpp/src/qmf/Object.h
@@ -31,13 +31,15 @@ namespace qmf {
public:
Object(const SchemaObjectClass* type);
Object(ObjectImpl* impl);
+ Object(const Object& from);
virtual ~Object();
void destroy();
const ObjectId* getObjectId() const;
void setObjectId(ObjectId* oid);
const SchemaObjectClass* getClass() const;
- Value* getValue(char* key);
+ Value* getValue(char* key) const;
+ void invokeMethod(const char* methodName, const Value* inArgs, void* context) const;
ObjectImpl* impl;
};
diff --git a/qpid/cpp/src/qmf/ObjectId.h b/qpid/cpp/src/qmf/ObjectId.h
index ffd1b6978b..e894e0b39c 100644
--- a/qpid/cpp/src/qmf/ObjectId.h
+++ b/qpid/cpp/src/qmf/ObjectId.h
@@ -30,6 +30,7 @@ namespace qmf {
class ObjectId {
public:
ObjectId();
+ ObjectId(const ObjectId& from);
ObjectId(ObjectIdImpl* impl);
~ObjectId();
diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/ObjectIdImpl.cpp
index 75661fdb47..c0618ccc49 100644
--- a/qpid/cpp/src/qmf/ObjectIdImpl.cpp
+++ b/qpid/cpp/src/qmf/ObjectIdImpl.cpp
@@ -100,6 +100,15 @@ void ObjectIdImpl::fromString(const std::string& repr)
agent = 0;
}
+std::string ObjectIdImpl::asString() const
+{
+ stringstream val;
+
+ val << getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
+ getAgentBank() << "-" << getObjectNum();
+ return val.str();
+}
+
bool ObjectIdImpl::operator==(const ObjectIdImpl& other) const
{
uint64_t otherFirst = agent == 0 ? other.first : other.first & 0xffff000000000000LL;
@@ -126,15 +135,11 @@ bool ObjectIdImpl::operator>(const ObjectIdImpl& other) const
// Wrappers
//==================================================================
-ObjectId::ObjectId()
-{
- impl = new ObjectIdImpl(this);
-}
+ObjectId::ObjectId() : impl(new ObjectIdImpl(this)) {}
-ObjectId::ObjectId(ObjectIdImpl* i)
-{
- impl = i;
-}
+ObjectId::ObjectId(const ObjectId& from) : impl(new ObjectIdImpl(*(from.impl))) {}
+
+ObjectId::ObjectId(ObjectIdImpl* i) : impl(i) {}
ObjectId::~ObjectId()
{
diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.h b/qpid/cpp/src/qmf/ObjectIdImpl.h
index 5d8ee59aee..38d231237f 100644
--- a/qpid/cpp/src/qmf/ObjectIdImpl.h
+++ b/qpid/cpp/src/qmf/ObjectIdImpl.h
@@ -39,13 +39,14 @@ namespace qmf {
uint64_t first;
uint64_t second;
- ObjectIdImpl(ObjectId* e) : envelope(e), agent(0) {}
+ ObjectIdImpl(ObjectId* e) : envelope(e), agent(0), first(0), second(0) {}
ObjectIdImpl(qpid::framing::Buffer& buffer);
ObjectIdImpl(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object);
void decode(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void fromString(const std::string& repr);
+ std::string asString() const;
uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; }
uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; }
uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; }
diff --git a/qpid/cpp/src/qmf/ObjectImpl.cpp b/qpid/cpp/src/qmf/ObjectImpl.cpp
index d3882935e4..216a9d883e 100644
--- a/qpid/cpp/src/qmf/ObjectImpl.cpp
+++ b/qpid/cpp/src/qmf/ObjectImpl.cpp
@@ -19,6 +19,7 @@
#include "qmf/ObjectImpl.h"
#include "qmf/ValueImpl.h"
+#include "qmf/BrokerProxyImpl.h"
#include <qpid/sys/Time.h>
using namespace std;
@@ -27,7 +28,7 @@ using namespace qpid::sys;
using qpid::framing::Buffer;
ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) :
- envelope(e), objectClass(type), createTime(uint64_t(Duration(now()))),
+ envelope(e), objectClass(type), broker(0), createTime(uint64_t(Duration(now()))),
destroyTime(0), lastUpdatedTime(createTime)
{
int propCount = objectClass->getPropertyCount();
@@ -45,30 +46,40 @@ ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) :
}
}
-ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer) :
- envelope(new Object(this)), objectClass(type), createTime(uint64_t(Duration(now()))),
- destroyTime(0), lastUpdatedTime(createTime)
+ObjectImpl::ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed) :
+ envelope(new Object(this)), objectClass(type), broker(b), createTime(0), destroyTime(0), lastUpdatedTime(0)
{
- int propCount = objectClass->getPropertyCount();
- int statCount = objectClass->getStatisticCount();
int idx;
- set<string> excludes;
- parsePresenceMasks(buffer, excludes);
- for (idx = 0; idx < propCount; idx++) {
- const SchemaProperty* prop = objectClass->getProperty(idx);
- if (excludes.count(prop->getName()) != 0) {
- properties[prop->getName()] = ValuePtr(new Value(prop->getType()));
- } else {
- ValueImpl* pval = new ValueImpl(prop->getType(), buffer);
- properties[prop->getName()] = ValuePtr(pval->envelope);
+ if (managed) {
+ lastUpdatedTime = buffer.getLongLong();
+ createTime = buffer.getLongLong();
+ destroyTime = buffer.getLongLong();
+ objectId.reset(new ObjectIdImpl(buffer));
+ }
+
+ if (prop) {
+ int propCount = objectClass->getPropertyCount();
+ set<string> excludes;
+ parsePresenceMasks(buffer, excludes);
+ for (idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ if (excludes.count(prop->getName()) != 0) {
+ properties[prop->getName()] = ValuePtr(new Value(prop->getType()));
+ } else {
+ ValueImpl* pval = new ValueImpl(prop->getType(), buffer);
+ properties[prop->getName()] = ValuePtr(pval->envelope);
+ }
}
}
- for (idx = 0; idx < statCount; idx++) {
- const SchemaStatistic* stat = objectClass->getStatistic(idx);
- ValueImpl* sval = new ValueImpl(stat->getType(), buffer);
- statistics[stat->getName()] = ValuePtr(sval->envelope);
+ if (stat) {
+ int statCount = objectClass->getStatisticCount();
+ for (idx = 0; idx < statCount; idx++) {
+ const SchemaStatistic* stat = objectClass->getStatistic(idx);
+ ValueImpl* sval = new ValueImpl(stat->getType(), buffer);
+ statistics[stat->getName()] = ValuePtr(sval->envelope);
+ }
}
}
@@ -82,7 +93,7 @@ void ObjectImpl::destroy()
// TODO - flag deletion
}
-Value* ObjectImpl::getValue(const string& key)
+Value* ObjectImpl::getValue(const string& key) const
{
map<string, ValuePtr>::const_iterator iter;
@@ -97,6 +108,12 @@ Value* ObjectImpl::getValue(const string& key)
return 0;
}
+void ObjectImpl::invokeMethod(const string& methodName, const Value* inArgs, void* context) const
+{
+ if (broker != 0 && objectId.get() != 0)
+ broker->sendMethodRequest(objectId.get(), objectClass, methodName, inArgs, context);
+}
+
void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList)
{
int propCount = objectClass->getPropertyCount();
@@ -123,9 +140,9 @@ void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList)
void ObjectImpl::encodeSchemaKey(qpid::framing::Buffer& buffer) const
{
- buffer.putShortString(objectClass->getPackage());
- buffer.putShortString(objectClass->getName());
- buffer.putBin128(const_cast<uint8_t*>(objectClass->getHash()));
+ buffer.putShortString(objectClass->getClassKey()->getPackageName());
+ buffer.putShortString(objectClass->getClassKey()->getClassName());
+ buffer.putBin128(const_cast<uint8_t*>(objectClass->getClassKey()->getHash()));
}
void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const
@@ -133,7 +150,7 @@ void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const
buffer.putLongLong(lastUpdatedTime);
buffer.putLongLong(createTime);
buffer.putLongLong(destroyTime);
- objectId->impl->encode(buffer);
+ objectId->encode(buffer);
}
void ObjectImpl::encodeProperties(qpid::framing::Buffer& buffer) const
@@ -187,36 +204,13 @@ void ObjectImpl::encodeStatistics(qpid::framing::Buffer& buffer) const
//==================================================================
Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(this, type)) {}
-
Object::Object(ObjectImpl* i) : impl(i) {}
-
-Object::~Object()
-{
- delete impl;
-}
-
-void Object::destroy()
-{
- impl->destroy();
-}
-
-const ObjectId* Object::getObjectId() const
-{
- return impl->getObjectId();
-}
-
-void Object::setObjectId(ObjectId* oid)
-{
- impl->setObjectId(oid);
-}
-
-const SchemaObjectClass* Object::getClass() const
-{
- return impl->getClass();
-}
-
-Value* Object::getValue(char* key)
-{
- return impl->getValue(key);
-}
+Object::Object(const Object& from) : impl(new ObjectImpl(*(from.impl))) {}
+Object::~Object() { delete impl; }
+void Object::destroy() { impl->destroy(); }
+const ObjectId* Object::getObjectId() const { return impl->getObjectId(); }
+void Object::setObjectId(ObjectId* oid) { impl->setObjectId(oid); }
+const SchemaObjectClass* Object::getClass() const { return impl->getClass(); }
+Value* Object::getValue(char* key) const { return impl->getValue(key); }
+void Object::invokeMethod(const char* m, const Value* a, void* c) const { impl->invokeMethod(m, a, c); }
diff --git a/qpid/cpp/src/qmf/ObjectImpl.h b/qpid/cpp/src/qmf/ObjectImpl.h
index 4dc2170bfc..4ac5a31b54 100644
--- a/qpid/cpp/src/qmf/ObjectImpl.h
+++ b/qpid/cpp/src/qmf/ObjectImpl.h
@@ -21,19 +21,25 @@
*/
#include <qmf/Object.h>
+#include <qmf/ObjectIdImpl.h>
#include <map>
#include <set>
#include <string>
#include <qpid/framing/Buffer.h>
#include <boost/shared_ptr.hpp>
+#include <qpid/sys/Mutex.h>
namespace qmf {
+ class BrokerProxyImpl;
+
struct ObjectImpl {
+ typedef boost::shared_ptr<ObjectImpl> Ptr;
typedef boost::shared_ptr<Value> ValuePtr;
Object* envelope;
const SchemaObjectClass* objectClass;
- boost::shared_ptr<ObjectId> objectId;
+ BrokerProxyImpl* broker;
+ boost::shared_ptr<ObjectIdImpl> objectId;
uint64_t createTime;
uint64_t destroyTime;
uint64_t lastUpdatedTime;
@@ -41,14 +47,16 @@ namespace qmf {
mutable std::map<std::string, ValuePtr> statistics;
ObjectImpl(Object* e, const SchemaObjectClass* type);
- ObjectImpl(const SchemaObjectClass* type, qpid::framing::Buffer& buffer);
+ ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer,
+ bool prop, bool stat, bool managed);
~ObjectImpl();
void destroy();
- const ObjectId* getObjectId() const { return objectId.get(); }
- void setObjectId(ObjectId* oid) { objectId.reset(oid); }
+ const ObjectId* getObjectId() const { return objectId.get() ? objectId->envelope : 0; }
+ void setObjectId(ObjectId* oid) { objectId.reset(oid->impl); }
const SchemaObjectClass* getClass() const { return objectClass; }
- Value* getValue(const std::string& key);
+ Value* getValue(const std::string& key) const;
+ void invokeMethod(const std::string& methodName, const Value* inArgs, void* context) const;
void parsePresenceMasks(qpid::framing::Buffer& buffer, std::set<std::string>& excludeList);
void encodeSchemaKey(qpid::framing::Buffer& buffer) const;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/cpp/src/qmf/Protocol.cpp
index a1a399e5bf..0a3beeb276 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java
+++ b/qpid/cpp/src/qmf/Protocol.cpp
@@ -1,5 +1,4 @@
/*
- *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -7,39 +6,47 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT 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.security.access.plugins.network;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLPluginFactory;
+#include "qmf/Protocol.h"
+#include "qpid/framing/Buffer.h"
-public class FirewallFactory implements ACLPluginFactory
+using namespace std;
+using namespace qmf;
+using namespace qpid::framing;
+
+
+bool Protocol::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
{
+ if (buf.available() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
- @Override
- public ACLPlugin newInstance(Configuration config) throws ConfigurationException
- {
- FirewallPlugin plugin = new FirewallPlugin();
- plugin.setConfiguration(config);
- return plugin;
- }
-
- @Override
- public boolean supportsTag(String name)
- {
- return name.equals("firewall");
- }
-
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
}
+
+void Protocol::encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('3');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+
diff --git a/qpid/cpp/src/qmf/Protocol.h b/qpid/cpp/src/qmf/Protocol.h
new file mode 100644
index 0000000000..d5da08c1db
--- /dev/null
+++ b/qpid/cpp/src/qmf/Protocol.h
@@ -0,0 +1,67 @@
+#ifndef _QmfProtocol_
+#define _QmfProtocol_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <qpid/sys/IntegerTypes.h>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+
+ class Protocol {
+ public:
+ static bool checkHeader(qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ static void encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+
+ const static uint8_t OP_ATTACH_REQUEST = 'A';
+ const static uint8_t OP_ATTACH_RESPONSE = 'a';
+
+ const static uint8_t OP_BROKER_REQUEST = 'B';
+ const static uint8_t OP_BROKER_RESPONSE = 'b';
+
+ const static uint8_t OP_CONSOLE_ADDED_INDICATION = 'x';
+ const static uint8_t OP_COMMAND_COMPLETE = 'z';
+ const static uint8_t OP_HEARTBEAT_INDICATION = 'h';
+
+ const static uint8_t OP_PACKAGE_REQUEST = 'P';
+ const static uint8_t OP_PACKAGE_INDICATION = 'p';
+ const static uint8_t OP_CLASS_QUERY = 'Q';
+ const static uint8_t OP_CLASS_INDICATION = 'q';
+ const static uint8_t OP_SCHEMA_REQUEST = 'S';
+ const static uint8_t OP_SCHEMA_RESPONSE = 's';
+
+ const static uint8_t OP_METHOD_REQUEST = 'M';
+ const static uint8_t OP_METHOD_RESPONSE = 'm';
+ const static uint8_t OP_GET_QUERY = 'G';
+ const static uint8_t OP_OBJECT_INDICATION = 'g';
+ const static uint8_t OP_PROPERTY_INDICATION = 'c';
+ const static uint8_t OP_STATISTIC_INDICATION = 'i';
+ const static uint8_t OP_EVENT_INDICATION = 'e';
+ };
+
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/Query.h b/qpid/cpp/src/qmf/Query.h
index 78bc6f4ae2..875749862e 100644
--- a/qpid/cpp/src/qmf/Query.h
+++ b/qpid/cpp/src/qmf/Query.h
@@ -25,26 +25,76 @@
namespace qmf {
+ struct Object;
+ struct QueryElementImpl;
struct QueryImpl;
+ struct QueryExpressionImpl;
+ struct SchemaClassKey;
+
+ enum ValueOper {
+ O_EQ = 1,
+ O_NE = 2,
+ O_LT = 3,
+ O_LE = 4,
+ O_GT = 5,
+ O_GE = 6,
+ O_RE_MATCH = 7,
+ O_RE_NOMATCH = 8
+ };
+
+ struct QueryOperand {
+ virtual ~QueryOperand() {}
+ virtual bool evaluate(const Object* object) const = 0;
+ };
+
+ struct QueryElement : public QueryOperand {
+ QueryElement(const char* attrName, const Value* value, ValueOper oper);
+ QueryElement(QueryElementImpl* impl);
+ virtual ~QueryElement();
+ bool evaluate(const Object* object) const;
+
+ QueryElementImpl* impl;
+ };
+
+ enum ExprOper {
+ E_NOT = 1,
+ E_AND = 2,
+ E_OR = 3,
+ E_XOR = 4
+ };
+
+ struct QueryExpression : public QueryOperand {
+ QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2);
+ QueryExpression(QueryExpressionImpl* impl);
+ virtual ~QueryExpression();
+ bool evaluate(const Object* object) const;
+
+ QueryExpressionImpl* impl;
+ };
+
class Query {
public:
- Query();
+ Query(const char* className, const char* packageName);
+ Query(const SchemaClassKey* key);
+ Query(const ObjectId* oid);
Query(QueryImpl* impl);
~Query();
+ void setSelect(const QueryOperand* criterion);
+ void setLimit(uint32_t maxResults);
+ void setOrderBy(const char* attrName, bool decreasing);
+
const char* getPackage() const;
const char* getClass() const;
const ObjectId* getObjectId() const;
- enum Oper {
- OPER_AND = 1,
- OPER_OR = 2
- };
-
- int whereCount() const;
- Oper whereOper() const;
- const char* whereKey() const;
- const Value* whereValue() const;
+ bool haveSelect() const;
+ bool haveLimit() const;
+ bool haveOrderBy() const;
+ const QueryOperand* getSelect() const;
+ uint32_t getLimit() const;
+ const char* getOrderBy() const;
+ bool getDecreasing() const;
QueryImpl* impl;
};
diff --git a/qpid/cpp/src/qmf/QueryImpl.cpp b/qpid/cpp/src/qmf/QueryImpl.cpp
index 7e827796bb..f75a9aa5d5 100644
--- a/qpid/cpp/src/qmf/QueryImpl.cpp
+++ b/qpid/cpp/src/qmf/QueryImpl.cpp
@@ -18,54 +18,77 @@
*/
#include "qmf/QueryImpl.h"
+#include "qmf/ObjectIdImpl.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
using namespace std;
using namespace qmf;
+using namespace qpid::framing;
-//==================================================================
-// Wrappers
-//==================================================================
-
-Query::Query() : impl(new QueryImpl(this)) {}
-Query::Query(QueryImpl* i) : impl(i) {}
-
-Query::~Query()
+bool QueryElementImpl::evaluate(const Object* /*object*/) const
{
- delete impl;
+ // TODO: Implement this
+ return false;
}
-const char* Query::getPackage() const
+bool QueryExpressionImpl::evaluate(const Object* /*object*/) const
{
- return impl->getPackage();
+ // TODO: Implement this
+ return false;
}
-const char* Query::getClass() const
+QueryImpl::QueryImpl(Buffer& buffer)
{
- return impl->getClass();
+ FieldTable ft;
+ ft.decode(buffer);
+ // TODO
}
-const ObjectId* Query::getObjectId() const
+void QueryImpl::encode(Buffer& buffer) const
{
- return impl->getObjectId();
-}
+ FieldTable ft;
-int Query::whereCount() const
-{
- return impl->whereCount();
-}
+ if (oid.get() != 0) {
+ ft.setString("_objectid", oid->impl->asString());
+ } else {
+ if (!packageName.empty())
+ ft.setString("_package", packageName);
+ ft.setString("_class", className);
+ }
-Query::Oper Query::whereOper() const
-{
- return impl->whereOper();
+ ft.encode(buffer);
}
-const char* Query::whereKey() const
-{
- return impl->whereKey();
-}
-const Value* Query::whereValue() const
-{
- return impl->whereValue();
-}
+//==================================================================
+// Wrappers
+//==================================================================
+
+QueryElement::QueryElement(const char* attrName, const Value* value, ValueOper oper) : impl(new QueryElementImpl(attrName, value, oper)) {}
+QueryElement::QueryElement(QueryElementImpl* i) : impl(i) {}
+QueryElement::~QueryElement() { delete impl; }
+bool QueryElement::evaluate(const Object* object) const { return impl->evaluate(object); }
+QueryExpression::QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2) : impl(new QueryExpressionImpl(oper, operand1, operand2)) {}
+QueryExpression::QueryExpression(QueryExpressionImpl* i) : impl(i) {}
+QueryExpression::~QueryExpression() { delete impl; }
+bool QueryExpression::evaluate(const Object* object) const { return impl->evaluate(object); }
+Query::Query(const char* className, const char* packageName) : impl(new QueryImpl(className, packageName)) {}
+Query::Query(const SchemaClassKey* key) : impl(new QueryImpl(key)) {}
+Query::Query(const ObjectId* oid) : impl(new QueryImpl(oid)) {}
+Query::Query(QueryImpl* i) : impl(i) {}
+Query::~Query() { delete impl; }
+void Query::setSelect(const QueryOperand* criterion) { impl->setSelect(criterion); }
+void Query::setLimit(uint32_t maxResults) { impl->setLimit(maxResults); }
+void Query::setOrderBy(const char* attrName, bool decreasing) { impl->setOrderBy(attrName, decreasing); }
+const char* Query::getPackage() const { return impl->getPackage().c_str(); }
+const char* Query::getClass() const { return impl->getClass().c_str(); }
+const ObjectId* Query::getObjectId() const { return impl->getObjectId(); }
+bool Query::haveSelect() const { return impl->haveSelect(); }
+bool Query::haveLimit() const { return impl->haveLimit(); }
+bool Query::haveOrderBy() const { return impl->haveOrderBy(); }
+const QueryOperand* Query::getSelect() const { return impl->getSelect(); }
+uint32_t Query::getLimit() const { return impl->getLimit(); }
+const char* Query::getOrderBy() const { return impl->getOrderBy().c_str(); }
+bool Query::getDecreasing() const { return impl->getDecreasing(); }
diff --git a/qpid/cpp/src/qmf/QueryImpl.h b/qpid/cpp/src/qmf/QueryImpl.h
index 1cb9bfe554..4a56a457c0 100644
--- a/qpid/cpp/src/qmf/QueryImpl.h
+++ b/qpid/cpp/src/qmf/QueryImpl.h
@@ -20,28 +20,82 @@
* under the License.
*/
-#include <qmf/Query.h>
+#include "qmf/Query.h"
+#include "qmf/Schema.h"
#include <string>
#include <boost/shared_ptr.hpp>
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
namespace qmf {
+ struct QueryElementImpl {
+ QueryElementImpl(const std::string& a, const Value* v, ValueOper o) :
+ envelope(new QueryElement(this)), attrName(a), value(v), oper(o) {}
+ ~QueryElementImpl() {}
+ bool evaluate(const Object* object) const;
+
+ QueryElement* envelope;
+ std::string attrName;
+ const Value* value;
+ ValueOper oper;
+ };
+
+ struct QueryExpressionImpl {
+ QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) :
+ envelope(new QueryExpression(this)), oper(o), left(operand1), right(operand2) {}
+ ~QueryExpressionImpl() {}
+ bool evaluate(const Object* object) const;
+
+ QueryExpression* envelope;
+ ExprOper oper;
+ const QueryOperand* left;
+ const QueryOperand* right;
+ };
+
struct QueryImpl {
- Query* envelope;
- std::string packageName;
- std::string className;
- boost::shared_ptr<ObjectId> oid;
+ QueryImpl(Query* e) : envelope(e), select(0) {}
+ QueryImpl(const std::string& c, const std::string& p) :
+ envelope(new Query(this)), packageName(p), className(c) {}
+ QueryImpl(const SchemaClassKey* key) :
+ envelope(new Query(this)), packageName(key->getPackageName()), className(key->getClassName()) {}
+ QueryImpl(const ObjectId* oid) :
+ envelope(new Query(this)), oid(new ObjectId(*oid)) {}
+ QueryImpl(qpid::framing::Buffer& buffer);
+ ~QueryImpl() {};
- QueryImpl(Query* e) : envelope(e) {}
+ void setSelect(const QueryOperand* criterion) { select = criterion; }
+ void setLimit(uint32_t maxResults) { resultLimit = maxResults; }
+ void setOrderBy(const std::string& attrName, bool decreasing) {
+ orderBy = attrName; orderDecreasing = decreasing;
+ }
- const char* getPackage() const { return packageName.empty() ? 0 : packageName.c_str(); }
- const char* getClass() const { return className.empty() ? 0 : className.c_str(); }
+ const std::string& getPackage() const { return packageName; }
+ const std::string& getClass() const { return className; }
const ObjectId* getObjectId() const { return oid.get(); }
- int whereCount() const { return 0;}
- Query::Oper whereOper() const { return Query::OPER_AND; }
- const char* whereKey() const { return 0; }
- const Value* whereValue() const { return 0; }
+ bool haveSelect() const { return select != 0; }
+ bool haveLimit() const { return resultLimit > 0; }
+ bool haveOrderBy() const { return !orderBy.empty(); }
+ const QueryOperand* getSelect() const { return select; }
+ uint32_t getLimit() const { return resultLimit; }
+ const std::string& getOrderBy() const { return orderBy; }
+ bool getDecreasing() const { return orderDecreasing; }
+
+ void encode(qpid::framing::Buffer& buffer) const;
+
+ Query* envelope;
+ std::string packageName;
+ std::string className;
+ boost::shared_ptr<ObjectId> oid;
+ const QueryOperand* select;
+ uint32_t resultLimit;
+ std::string orderBy;
+ bool orderDecreasing;
};
}
diff --git a/qpid/cpp/src/qmf/ResilientConnection.cpp b/qpid/cpp/src/qmf/ResilientConnection.cpp
index 3531e104b0..7ec03cf4da 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.cpp
+++ b/qpid/cpp/src/qmf/ResilientConnection.cpp
@@ -41,7 +41,7 @@
using namespace std;
using namespace qmf;
-using namespace qpid::client;
+using namespace qpid;
using qpid::sys::Mutex;
namespace qmf {
@@ -57,29 +57,29 @@ namespace qmf {
ResilientConnectionEvent copy();
};
- struct RCSession : public MessageListener, public qpid::sys::Runnable, public qpid::RefCounted {
+ struct RCSession : public client::MessageListener, public qpid::sys::Runnable, public qpid::RefCounted {
typedef boost::intrusive_ptr<RCSession> Ptr;
ResilientConnectionImpl& connImpl;
string name;
- Connection& connection;
- Session session;
- SubscriptionManager* subscriptions;
+ client::Connection& connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
void* userContext;
vector<string> dests;
qpid::sys::Thread thread;
- RCSession(ResilientConnectionImpl& ci, const string& n, Connection& c, void* uc) :
+ RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) :
connImpl(ci), name(n), connection(c), session(connection.newSession(name)),
- subscriptions(new SubscriptionManager(session)), userContext(uc), thread(*this) {}
+ subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this) {}
~RCSession();
- void received(qpid::client::Message& msg);
+ void received(client::Message& msg);
void run();
void stop();
};
class ResilientConnectionImpl : public qpid::sys::Runnable {
public:
- ResilientConnectionImpl(ConnectionSettings& settings);
+ ResilientConnectionImpl(const ConnectionSettings& settings);
~ResilientConnectionImpl();
bool isConnected() const;
@@ -108,8 +108,8 @@ namespace qmf {
bool connected;
bool shutdown;
string lastError;
- ConnectionSettings settings;
- Connection connection;
+ const ConnectionSettings settings;
+ client::Connection connection;
mutable qpid::sys::Mutex lock;
int delayMin;
int delayMax;
@@ -156,7 +156,7 @@ void RCSession::stop()
subscriptions->stop();
}
-void RCSession::received(qpid::client::Message& msg)
+void RCSession::received(client::Message& msg)
{
qmf::MessageImpl qmsg;
qmsg.body = msg.getData();
@@ -175,8 +175,8 @@ void RCSession::received(qpid::client::Message& msg)
connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg);
}
-ResilientConnectionImpl::ResilientConnectionImpl(ConnectionSettings& _settings) :
- notifyFd(-1), connected(false), shutdown(false), settings(_settings), connThread(*this)
+ResilientConnectionImpl::ResilientConnectionImpl(const ConnectionSettings& _settings) :
+ notifyFd(-1), connected(false), shutdown(false), settings(_settings), delayMin(1), connThread(*this)
{
connection.registerFailureCallback(boost::bind(&ResilientConnectionImpl::failure, this));
settings.impl->getRetrySettings(&delayMin, &delayMax, &delayFactor);
@@ -222,7 +222,7 @@ bool ResilientConnectionImpl::createSession(const char* name, void* sessionConte
RCSession::Ptr sess = RCSession::Ptr(new RCSession(*this, name, connection, sessionContext));
- handle.handle = (void*) sess.get();
+ handle.impl = (void*) sess.get();
sessions.insert(sess);
return true;
@@ -231,7 +231,7 @@ bool ResilientConnectionImpl::createSession(const char* name, void* sessionConte
void ResilientConnectionImpl::destroySession(SessionHandle handle)
{
Mutex::ScopedLock _lock(lock);
- RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.handle);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
set<RCSession::Ptr>::iterator iter = sessions.find(sess);
if (iter != sessions.end()) {
for (vector<string>::iterator dIter = sess->dests.begin(); dIter != sess->dests.end(); dIter++)
@@ -247,7 +247,7 @@ void ResilientConnectionImpl::destroySession(SessionHandle handle)
void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& message)
{
Mutex::ScopedLock _lock(lock);
- RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.handle);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
set<RCSession::Ptr>::iterator iter = sessions.find(sess);
qpid::client::Message msg;
string data(message.body, message.length);
@@ -256,7 +256,7 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me
msg.setData(data);
try {
- sess->session.messageTransfer(arg::content=msg, arg::destination=message.destination);
+ sess->session.messageTransfer(client::arg::content=msg, client::arg::destination=message.destination);
} catch(exception& e) {
QPID_LOG(error, "Session Exception during message-transfer: " << e.what());
sessions.erase(iter);
@@ -267,19 +267,22 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me
void ResilientConnectionImpl::declareQueue(SessionHandle handle, char* queue)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.queueDeclare(arg::queue=queue, arg::autoDelete=true, arg::exclusive=true);
+ sess->session.queueDeclare(client::arg::queue=queue, client::arg::autoDelete=true, client::arg::exclusive=true);
+ sess->subscriptions->setAcceptMode(client::ACCEPT_MODE_NONE);
+ sess->subscriptions->setAcquireMode(client::ACQUIRE_MODE_PRE_ACQUIRED);
sess->subscriptions->subscribe(*sess, queue, queue);
+ sess->subscriptions->setFlowControl(queue, client::FlowControl::unlimited());
sess->dests.push_back(string(queue));
}
void ResilientConnectionImpl::deleteQueue(SessionHandle handle, char* queue)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.queueDelete(arg::queue=queue);
+ sess->session.queueDelete(client::arg::queue=queue);
for (vector<string>::iterator iter = sess->dests.begin();
iter != sess->dests.end(); iter++)
if (*iter == queue) {
@@ -293,18 +296,18 @@ void ResilientConnectionImpl::bind(SessionHandle handle,
char* exchange, char* queue, char* key)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=key);
+ sess->session.exchangeBind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
}
void ResilientConnectionImpl::unbind(SessionHandle handle,
char* exchange, char* queue, char* key)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.exchangeUnbind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=key);
+ sess->session.exchangeUnbind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
}
void ResilientConnectionImpl::setNotifyFd(int fd)
@@ -318,6 +321,7 @@ void ResilientConnectionImpl::run()
while (true) {
try {
+ QPID_LOG(trace, "Trying to open connection...");
connection.open(settings.impl->getClientSettings());
{
Mutex::ScopedLock _lock(lock);
@@ -326,6 +330,7 @@ void ResilientConnectionImpl::run()
while (connected)
cond.wait(lock);
+ delay = delayMin;
while (!sessions.empty()) {
set<RCSession::Ptr>::iterator iter = sessions.begin();
@@ -334,6 +339,11 @@ void ResilientConnectionImpl::run()
EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, sess->userContext);
Mutex::ScopedUnlock _u(lock);
sess->stop();
+
+ // Nullify the intrusive pointer within the scoped unlock, otherwise,
+ // the reference is held until overwritted above (under lock) which causes
+ // the session destructor to be called with the lock held.
+ sess = 0;
}
EnqueueEvent(ResilientConnectionEvent::DISCONNECTED);
@@ -341,7 +351,6 @@ void ResilientConnectionImpl::run()
if (shutdown)
return;
}
- delay = delayMin;
connection.close();
} catch (exception &e) {
QPID_LOG(debug, "connection.open exception: " << e.what());
@@ -396,7 +405,7 @@ void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind k
// Wrappers
//==================================================================
-ResilientConnection::ResilientConnection(ConnectionSettings& settings)
+ResilientConnection::ResilientConnection(const ConnectionSettings& settings)
{
impl = new ResilientConnectionImpl(settings);
}
diff --git a/qpid/cpp/src/qmf/ResilientConnection.h b/qpid/cpp/src/qmf/ResilientConnection.h
index 6e05541253..03f1b9c0d5 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.h
+++ b/qpid/cpp/src/qmf/ResilientConnection.h
@@ -26,6 +26,8 @@
namespace qmf {
+ class ResilientConnectionImpl;
+
/**
* Represents events that occur, unsolicited, from ResilientConnection.
*/
@@ -43,12 +45,11 @@ namespace qmf {
Message message; // RECV
};
- struct SessionHandle {
- void* handle;
+ class SessionHandle {
+ friend class ResilientConnectionImpl;
+ void* impl;
};
- class ResilientConnectionImpl;
-
/**
* ResilientConnection represents a Qpid connection that is resilient.
*
@@ -67,7 +68,7 @@ namespace qmf {
*@param delayMax Maximum delay (in seconds) between retries.
*@param delayFactor Factor to multiply retry delay by after each failure.
*/
- ResilientConnection(ConnectionSettings& settings);
+ ResilientConnection(const ConnectionSettings& settings);
~ResilientConnection();
/**
diff --git a/qpid/cpp/src/qmf/Schema.h b/qpid/cpp/src/qmf/Schema.h
index e3ab90e3e3..1123acc3b8 100644
--- a/qpid/cpp/src/qmf/Schema.h
+++ b/qpid/cpp/src/qmf/Schema.h
@@ -35,6 +35,7 @@ namespace qmf {
struct SchemaStatisticImpl;
struct SchemaObjectClassImpl;
struct SchemaEventClassImpl;
+ struct SchemaClassKeyImpl;
/**
*/
@@ -114,6 +115,20 @@ namespace qmf {
/**
*/
+ class SchemaClassKey {
+ public:
+ SchemaClassKey(SchemaClassKeyImpl* impl);
+ ~SchemaClassKey();
+
+ const char* getPackageName() const;
+ const char* getClassName() const;
+ const uint8_t* getHash() const;
+
+ SchemaClassKeyImpl* impl;
+ };
+
+ /**
+ */
class SchemaObjectClass {
public:
SchemaObjectClass(const char* package, const char* name);
@@ -123,9 +138,7 @@ namespace qmf {
void addStatistic(const SchemaStatistic& statistic);
void addMethod(const SchemaMethod& method);
- const char* getPackage() const;
- const char* getName() const;
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getPropertyCount() const;
int getStatisticCount() const;
int getMethodCount() const;
@@ -146,9 +159,7 @@ namespace qmf {
void addArgument(const SchemaArgument& argument);
void setDesc(const char* desc);
- const char* getPackage() const;
- const char* getName() const;
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getArgumentCount() const;
const SchemaArgument* getArgument(int idx) const;
diff --git a/qpid/cpp/src/qmf/SchemaImpl.cpp b/qpid/cpp/src/qmf/SchemaImpl.cpp
index 665c94f2a1..3eb14c3952 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.cpp
+++ b/qpid/cpp/src/qmf/SchemaImpl.cpp
@@ -20,6 +20,8 @@
#include "qmf/SchemaImpl.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/Uuid.h>
+#include <string.h>
#include <string>
#include <vector>
@@ -27,6 +29,7 @@ using namespace std;
using namespace qmf;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
+using qpid::framing::Uuid;
SchemaHash::SchemaHash()
{
@@ -34,7 +37,7 @@ SchemaHash::SchemaHash()
hash[idx] = 0x5A;
}
-void SchemaHash::encode(Buffer& buffer)
+void SchemaHash::encode(Buffer& buffer) const
{
buffer.putBin128(hash);
}
@@ -63,6 +66,21 @@ void SchemaHash::update(const char* data, uint32_t len)
}
}
+bool SchemaHash::operator==(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) == 0;
+}
+
+bool SchemaHash::operator<(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) < 0;
+}
+
+bool SchemaHash::operator>(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) > 0;
+}
+
SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgument(this))
{
FieldTable map;
@@ -240,15 +258,59 @@ void SchemaStatisticImpl::updateHash(SchemaHash& hash) const
hash.update(description);
}
-SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : envelope(new SchemaObjectClass(this)), hasHash(true)
+SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) :
+ envelope(new SchemaClassKey(this)), package(p), name(n), hash(h) {}
+
+SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) :
+ envelope(new SchemaClassKey(this)), package(packageContainer), name(nameContainer), hash(hashContainer)
+{
+ buffer.getShortString(packageContainer);
+ buffer.getShortString(nameContainer);
+ hashContainer.decode(buffer);
+}
+
+void SchemaClassKeyImpl::encode(Buffer& buffer) const
+{
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ hash.encode(buffer);
+}
+
+bool SchemaClassKeyImpl::operator==(const SchemaClassKeyImpl& other) const
+{
+ return package == other.package &&
+ name == other.name &&
+ hash == other.hash;
+}
+
+bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const
+{
+ if (package < other.package) return true;
+ if (package > other.package) return false;
+ if (name < other.name) return true;
+ if (name > other.name) return false;
+ return hash < other.hash;
+}
+
+string SchemaClassKeyImpl::str() const
+{
+ Uuid printableHash(hash.get());
+ stringstream str;
+ str << package << ":" << name << "(" << printableHash << ")";
+ return str.str();
+}
+
+SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) :
+ envelope(new SchemaObjectClass(this)), hasHash(true), classKey(package, name, hash)
{
buffer.getShortString(package);
buffer.getShortString(name);
hash.decode(buffer);
- uint16_t propCount = buffer.getShort();
- uint16_t statCount = buffer.getShort();
- uint16_t methodCount = buffer.getShort();
+ /*uint8_t hasParentClass =*/ buffer.getOctet(); // TODO: Parse parent-class indicator
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
for (uint16_t idx = 0; idx < propCount; idx++) {
SchemaPropertyImpl* property = new SchemaPropertyImpl(buffer);
@@ -288,7 +350,7 @@ void SchemaObjectClassImpl::encode(Buffer& buffer) const
(*iter)->encode(buffer);
}
-const uint8_t* SchemaObjectClassImpl::getHash() const
+const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const
{
if (!hasHash) {
hasHash = true;
@@ -305,7 +367,7 @@ const uint8_t* SchemaObjectClassImpl::getHash() const
(*iter)->updateHash(hash);
}
- return hash.get();
+ return classKey.envelope;
}
void SchemaObjectClassImpl::addProperty(const SchemaProperty& property)
@@ -353,13 +415,15 @@ const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const
return 0;
}
-SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : envelope(new SchemaEventClass(this)), hasHash(true)
+SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) :
+ envelope(new SchemaEventClass(this)), hasHash(true), classKey(package, name, hash)
{
buffer.getShortString(package);
buffer.getShortString(name);
hash.decode(buffer);
+ buffer.putOctet(0); // No parent class
- uint16_t argCount = buffer.getShort();
+ uint16_t argCount = buffer.getShort();
for (uint16_t idx = 0; idx < argCount; idx++) {
SchemaArgumentImpl* argument = new SchemaArgumentImpl(buffer);
@@ -380,7 +444,7 @@ void SchemaEventClassImpl::encode(Buffer& buffer) const
(*iter)->encode(buffer);
}
-const uint8_t* SchemaEventClassImpl::getHash() const
+const SchemaClassKey* SchemaEventClassImpl::getClassKey() const
{
if (!hasHash) {
hasHash = true;
@@ -390,7 +454,7 @@ const uint8_t* SchemaEventClassImpl::getHash() const
iter != arguments.end(); iter++)
(*iter)->updateHash(hash);
}
- return hash.get();
+ return classKey.envelope;
}
void SchemaEventClassImpl::addArgument(const SchemaArgument& argument)
@@ -408,334 +472,79 @@ const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const
return 0;
}
+
//==================================================================
// Wrappers
//==================================================================
-SchemaArgument::SchemaArgument(const char* name, Typecode typecode)
-{
- impl = new SchemaArgumentImpl(this, name, typecode);
-}
-
+SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(this, name, typecode); }
SchemaArgument::SchemaArgument(SchemaArgumentImpl* i) : impl(i) {}
-
-SchemaArgument::~SchemaArgument()
-{
- delete impl;
-}
-
-void SchemaArgument::setDirection(Direction dir)
-{
- impl->setDirection(dir);
-}
-
-void SchemaArgument::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaArgument::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaArgument::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaArgument::getType() const
-{
- return impl->getType();
-}
-
-Direction SchemaArgument::getDirection() const
-{
- return impl->getDirection();
-}
-
-const char* SchemaArgument::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaArgument::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaMethod::SchemaMethod(const char* name)
-{
- impl = new SchemaMethodImpl(this, name);
-}
-
+SchemaArgument::~SchemaArgument() { delete impl; }
+void SchemaArgument::setDirection(Direction dir) { impl->setDirection(dir); }
+void SchemaArgument::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaArgument::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaArgument::getName() const { return impl->getName().c_str(); }
+Typecode SchemaArgument::getType() const { return impl->getType(); }
+Direction SchemaArgument::getDirection() const { return impl->getDirection(); }
+const char* SchemaArgument::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaArgument::getDesc() const { return impl->getDesc().c_str(); }
+SchemaMethod::SchemaMethod(const char* name) { impl = new SchemaMethodImpl(this, name); }
SchemaMethod::SchemaMethod(SchemaMethodImpl* i) : impl(i) {}
-
-SchemaMethod::~SchemaMethod()
-{
- delete impl;
-}
-
-void SchemaMethod::addArgument(const SchemaArgument& argument)
-{
- impl->addArgument(argument);
-}
-
-void SchemaMethod::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaMethod::getName() const
-{
- return impl->getName().c_str();
-}
-
-const char* SchemaMethod::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-int SchemaMethod::getArgumentCount() const
-{
- return impl->getArgumentCount();
-}
-
-const SchemaArgument* SchemaMethod::getArgument(int idx) const
-{
- return impl->getArgument(idx);
-}
-
-SchemaProperty::SchemaProperty(const char* name, Typecode typecode)
-{
- impl = new SchemaPropertyImpl(this, name, typecode);
-}
-
+SchemaMethod::~SchemaMethod() { delete impl; }
+void SchemaMethod::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaMethod::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaMethod::getName() const { return impl->getName().c_str(); }
+const char* SchemaMethod::getDesc() const { return impl->getDesc().c_str(); }
+int SchemaMethod::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaMethod::getArgument(int idx) const { return impl->getArgument(idx); }
+SchemaProperty::SchemaProperty(const char* name, Typecode typecode) { impl = new SchemaPropertyImpl(this, name, typecode); }
SchemaProperty::SchemaProperty(SchemaPropertyImpl* i) : impl(i) {}
-
-SchemaProperty::~SchemaProperty()
-{
- delete impl;
-}
-
-void SchemaProperty::setAccess(Access access)
-{
- impl->setAccess(access);
-}
-
-void SchemaProperty::setIndex(bool val)
-{
- impl->setIndex(val);
-}
-
-void SchemaProperty::setOptional(bool val)
-{
- impl->setOptional(val);
-}
-
-void SchemaProperty::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaProperty::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaProperty::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaProperty::getType() const
-{
- return impl->getType();
-}
-
-Access SchemaProperty::getAccess() const
-{
- return impl->getAccess();
-}
-
-bool SchemaProperty::isIndex() const
-{
- return impl->isIndex();
-}
-
-bool SchemaProperty::isOptional() const
-{
- return impl->isOptional();
-}
-
-const char* SchemaProperty::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaProperty::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode)
-{
- impl = new SchemaStatisticImpl(this, name, typecode);
-}
-
+SchemaProperty::~SchemaProperty() { delete impl; }
+void SchemaProperty::setAccess(Access access) { impl->setAccess(access); }
+void SchemaProperty::setIndex(bool val) { impl->setIndex(val); }
+void SchemaProperty::setOptional(bool val) { impl->setOptional(val); }
+void SchemaProperty::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaProperty::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaProperty::getName() const { return impl->getName().c_str(); }
+Typecode SchemaProperty::getType() const { return impl->getType(); }
+Access SchemaProperty::getAccess() const { return impl->getAccess(); }
+bool SchemaProperty::isIndex() const { return impl->isIndex(); }
+bool SchemaProperty::isOptional() const { return impl->isOptional(); }
+const char* SchemaProperty::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaProperty::getDesc() const { return impl->getDesc().c_str(); }
+SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) { impl = new SchemaStatisticImpl(this, name, typecode); }
SchemaStatistic::SchemaStatistic(SchemaStatisticImpl* i) : impl(i) {}
-
-SchemaStatistic::~SchemaStatistic()
-{
- delete impl;
-}
-
-void SchemaStatistic::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaStatistic::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaStatistic::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaStatistic::getType() const
-{
- return impl->getType();
-}
-
-const char* SchemaStatistic::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaStatistic::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaObjectClass::SchemaObjectClass(const char* package, const char* name)
-{
- impl = new SchemaObjectClassImpl(this, package, name);
-}
-
+SchemaStatistic::~SchemaStatistic() { delete impl; }
+void SchemaStatistic::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaStatistic::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaStatistic::getName() const { return impl->getName().c_str(); }
+Typecode SchemaStatistic::getType() const { return impl->getType(); }
+const char* SchemaStatistic::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaStatistic::getDesc() const { return impl->getDesc().c_str(); }
+SchemaClassKey::SchemaClassKey(SchemaClassKeyImpl* i) : impl(i) {}
+SchemaClassKey::~SchemaClassKey() { delete impl; }
+const char* SchemaClassKey::getPackageName() const { return impl->getPackageName().c_str(); }
+const char* SchemaClassKey::getClassName() const { return impl->getClassName().c_str(); }
+const uint8_t* SchemaClassKey::getHash() const { return impl->getHash(); }
+SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) { impl = new SchemaObjectClassImpl(this, package, name); }
SchemaObjectClass::SchemaObjectClass(SchemaObjectClassImpl* i) : impl(i) {}
-
-SchemaObjectClass::~SchemaObjectClass()
-{
- delete impl;
-}
-
-void SchemaObjectClass::addProperty(const SchemaProperty& property)
-{
- impl->addProperty(property);
-}
-
-void SchemaObjectClass::addStatistic(const SchemaStatistic& statistic)
-{
- impl->addStatistic(statistic);
-}
-
-void SchemaObjectClass::addMethod(const SchemaMethod& method)
-{
- impl->addMethod(method);
-}
-
-const char* SchemaObjectClass::getPackage() const
-{
- return impl->getPackage().c_str();
-}
-
-const char* SchemaObjectClass::getName() const
-{
- return impl->getName().c_str();
-}
-
-const uint8_t* SchemaObjectClass::getHash() const
-{
- return impl->getHash();
-}
-
-int SchemaObjectClass::getPropertyCount() const
-{
- return impl->getPropertyCount();
-}
-
-int SchemaObjectClass::getStatisticCount() const
-{
- return impl->getStatisticCount();
-}
-
-int SchemaObjectClass::getMethodCount() const
-{
- return impl->getMethodCount();
-}
-
-const SchemaProperty* SchemaObjectClass::getProperty(int idx) const
-{
- return impl->getProperty(idx);
-}
-
-const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const
-{
- return impl->getStatistic(idx);
-}
-
-const SchemaMethod* SchemaObjectClass::getMethod(int idx) const
-{
- return impl->getMethod(idx);
-}
-
-SchemaEventClass::SchemaEventClass(const char* package, const char* name)
-{
- impl = new SchemaEventClassImpl(this, package, name);
-}
-
+SchemaObjectClass::~SchemaObjectClass() { delete impl; }
+void SchemaObjectClass::addProperty(const SchemaProperty& property) { impl->addProperty(property); }
+void SchemaObjectClass::addStatistic(const SchemaStatistic& statistic) { impl->addStatistic(statistic); }
+void SchemaObjectClass::addMethod(const SchemaMethod& method) { impl->addMethod(method); }
+const SchemaClassKey* SchemaObjectClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaObjectClass::getPropertyCount() const { return impl->getPropertyCount(); }
+int SchemaObjectClass::getStatisticCount() const { return impl->getStatisticCount(); }
+int SchemaObjectClass::getMethodCount() const { return impl->getMethodCount(); }
+const SchemaProperty* SchemaObjectClass::getProperty(int idx) const { return impl->getProperty(idx); }
+const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const { return impl->getStatistic(idx); }
+const SchemaMethod* SchemaObjectClass::getMethod(int idx) const { return impl->getMethod(idx); }
+SchemaEventClass::SchemaEventClass(const char* package, const char* name) { impl = new SchemaEventClassImpl(this, package, name); }
SchemaEventClass::SchemaEventClass(SchemaEventClassImpl* i) : impl(i) {}
-
-SchemaEventClass::~SchemaEventClass()
-{
- delete impl;
-}
-
-void SchemaEventClass::addArgument(const SchemaArgument& argument)
-{
- impl->addArgument(argument);
-}
-
-void SchemaEventClass::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaEventClass::getPackage() const
-{
- return impl->getPackage().c_str();
-}
-
-const char* SchemaEventClass::getName() const
-{
- return impl->getName().c_str();
-}
-
-const uint8_t* SchemaEventClass::getHash() const
-{
- return impl->getHash();
-}
-
-int SchemaEventClass::getArgumentCount() const
-{
- return impl->getArgumentCount();
-}
-
-const SchemaArgument* SchemaEventClass::getArgument(int idx) const
-{
- return impl->getArgument(idx);
-}
+SchemaEventClass::~SchemaEventClass() { delete impl; }
+void SchemaEventClass::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaEventClass::setDesc(const char* desc) { impl->setDesc(desc); }
+const SchemaClassKey* SchemaEventClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaEventClass::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaEventClass::getArgument(int idx) const { return impl->getArgument(idx); }
diff --git a/qpid/cpp/src/qmf/SchemaImpl.h b/qpid/cpp/src/qmf/SchemaImpl.h
index 2c30a8851f..035d99aecd 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.h
+++ b/qpid/cpp/src/qmf/SchemaImpl.h
@@ -21,6 +21,7 @@
*/
#include "qmf/Schema.h"
+#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
#include <qpid/framing/Buffer.h>
@@ -35,7 +36,7 @@ namespace qmf {
uint8_t hash[16];
public:
SchemaHash();
- void encode(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
void decode(qpid::framing::Buffer& buffer);
void update(const char* data, uint32_t len);
void update(uint8_t data);
@@ -45,6 +46,9 @@ namespace qmf {
void update(Access a) { update((uint8_t) a); }
void update(bool b) { update((uint8_t) (b ? 1 : 0)); }
const uint8_t* get() const { return hash; }
+ bool operator==(const SchemaHash& other) const;
+ bool operator<(const SchemaHash& other) const;
+ bool operator>(const SchemaHash& other) const;
};
struct SchemaArgumentImpl {
@@ -138,27 +142,52 @@ namespace qmf {
void updateHash(SchemaHash& hash) const;
};
+ struct SchemaClassKeyImpl {
+ const SchemaClassKey* envelope;
+ const std::string& package;
+ const std::string& name;
+ const SchemaHash& hash;
+
+ // The *Container elements are only used if there isn't an external place to
+ // store these values.
+ std::string packageContainer;
+ std::string nameContainer;
+ SchemaHash hashContainer;
+
+ SchemaClassKeyImpl(const std::string& package, const std::string& name, const SchemaHash& hash);
+ SchemaClassKeyImpl(qpid::framing::Buffer& buffer);
+
+ const std::string& getPackageName() const { return package; }
+ const std::string& getClassName() const { return name; }
+ const uint8_t* getHash() const { return hash.get(); }
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ bool operator==(const SchemaClassKeyImpl& other) const;
+ bool operator<(const SchemaClassKeyImpl& other) const;
+ std::string str() const;
+ };
+
struct SchemaObjectClassImpl {
+ typedef boost::shared_ptr<SchemaObjectClassImpl> Ptr;
SchemaObjectClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
+ SchemaClassKeyImpl classKey;
std::vector<SchemaPropertyImpl*> properties;
std::vector<SchemaStatisticImpl*> statistics;
std::vector<SchemaMethodImpl*> methods;
SchemaObjectClassImpl(SchemaObjectClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false) {}
+ envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
SchemaObjectClassImpl(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void addProperty(const SchemaProperty& property);
void addStatistic(const SchemaStatistic& statistic);
void addMethod(const SchemaMethod& method);
- const std::string& getPackage() const { return package; }
- const std::string& getName() const { return name; }
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getPropertyCount() const { return properties.size(); }
int getStatisticCount() const { return statistics.size(); }
int getMethodCount() const { return methods.size(); }
@@ -168,24 +197,24 @@ namespace qmf {
};
struct SchemaEventClassImpl {
+ typedef boost::shared_ptr<SchemaEventClassImpl> Ptr;
SchemaEventClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
+ SchemaClassKeyImpl classKey;
std::string description;
std::vector<SchemaArgumentImpl*> arguments;
SchemaEventClassImpl(SchemaEventClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false) {}
+ envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
SchemaEventClassImpl(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void addArgument(const SchemaArgument& argument);
void setDesc(const char* desc) { description = desc; }
- const std::string& getPackage() const { return package; }
- const std::string& getName() const { return name; }
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getArgumentCount() const { return arguments.size(); }
const SchemaArgument* getArgument(int idx) const;
};
diff --git a/qpid/cpp/src/qmf/SequenceManager.cpp b/qpid/cpp/src/qmf/SequenceManager.cpp
new file mode 100644
index 0000000000..3171e66fac
--- /dev/null
+++ b/qpid/cpp/src/qmf/SequenceManager.cpp
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/SequenceManager.h"
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::sys;
+
+SequenceManager::SequenceManager() : nextSequence(1) {}
+
+void SequenceManager::setUnsolicitedContext(SequenceContext::Ptr ctx)
+{
+ unsolicitedContext = ctx;
+}
+
+uint32_t SequenceManager::reserve(SequenceContext::Ptr ctx)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (ctx.get() == 0)
+ ctx = unsolicitedContext;
+ uint32_t seq = nextSequence;
+ while (contextMap.find(seq) != contextMap.end())
+ seq = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ nextSequence = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ contextMap[seq] = ctx;
+ ctx->reserve();
+ return seq;
+}
+
+void SequenceManager::release(uint32_t sequence)
+{
+ Mutex::ScopedLock _lock(lock);
+
+ if (sequence == 0) {
+ if (unsolicitedContext.get() != 0)
+ unsolicitedContext->release();
+ return;
+ }
+
+ map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter != contextMap.end()) {
+ if (iter->second != 0)
+ iter->second->release();
+ contextMap.erase(iter);
+ }
+}
+
+void SequenceManager::releaseAll()
+{
+ Mutex::ScopedLock _lock(lock);
+ contextMap.clear();
+}
+
+void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer)
+{
+ Mutex::ScopedLock _lock(lock);
+ bool done;
+
+ if (sequence == 0) {
+ if (unsolicitedContext.get() != 0) {
+ done = unsolicitedContext->handleMessage(opcode, sequence, buffer);
+ if (done)
+ unsolicitedContext->release();
+ }
+ return;
+ }
+
+ map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter != contextMap.end()) {
+ if (iter->second != 0) {
+ done = iter->second->handleMessage(opcode, sequence, buffer);
+ if (done) {
+ iter->second->release();
+ contextMap.erase(iter);
+ }
+ }
+ }
+}
+
diff --git a/qpid/cpp/src/qmf/SequenceManager.h b/qpid/cpp/src/qmf/SequenceManager.h
new file mode 100644
index 0000000000..bbfd0728a7
--- /dev/null
+++ b/qpid/cpp/src/qmf/SequenceManager.h
@@ -0,0 +1,66 @@
+#ifndef _QmfSequenceManager_
+#define _QmfSequenceManager_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qpid/sys/Mutex.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+
+ class SequenceContext {
+ public:
+ typedef boost::shared_ptr<SequenceContext> Ptr;
+ SequenceContext() {}
+ virtual ~SequenceContext() {}
+
+ virtual void reserve() = 0;
+ virtual bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer) = 0;
+ virtual void release() = 0;
+ };
+
+ class SequenceManager {
+ public:
+ SequenceManager();
+
+ void setUnsolicitedContext(SequenceContext::Ptr ctx);
+ uint32_t reserve(SequenceContext::Ptr ctx = SequenceContext::Ptr());
+ void release(uint32_t sequence);
+ void releaseAll();
+ void dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer);
+
+ private:
+ mutable qpid::sys::Mutex lock;
+ uint32_t nextSequence;
+ SequenceContext::Ptr unsolicitedContext;
+ std::map<uint32_t, SequenceContext::Ptr> contextMap;
+ };
+
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/Value.h b/qpid/cpp/src/qmf/Value.h
index a45df14ea9..2ec2149110 100644
--- a/qpid/cpp/src/qmf/Value.h
+++ b/qpid/cpp/src/qmf/Value.h
@@ -30,7 +30,8 @@ namespace qmf {
class Value {
public:
- Value();
+ // Value();
+ Value(const Value& from);
Value(Typecode t, Typecode arrayType = TYPE_UINT8);
Value(ValueImpl* impl);
~Value();
diff --git a/qpid/cpp/src/qmf/ValueImpl.cpp b/qpid/cpp/src/qmf/ValueImpl.cpp
index f42c85eb33..b03d222835 100644
--- a/qpid/cpp/src/qmf/ValueImpl.cpp
+++ b/qpid/cpp/src/qmf/ValueImpl.cpp
@@ -67,6 +67,11 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typec
}
}
+ValueImpl::ValueImpl(Value* e, Typecode t, Typecode at) :
+ envelope(e), typecode(t), valid(false), arrayTypecode(at)
+{
+}
+
ValueImpl::ValueImpl(Typecode t) : envelope(new Value(this)), typecode(t)
{
::memset(&value, 0, sizeof(value));
@@ -186,293 +191,64 @@ void ValueImpl::deleteArrayItem(uint32_t)
// Wrappers
//==================================================================
-Value::Value(Typecode t, Typecode at)
-{
- impl = new ValueImpl(this, t, at);
-}
-
-Value::Value(ValueImpl* i)
-{
- impl = i;
-}
-
-Value::~Value()
-{
- delete impl;
-}
-
-Typecode Value::getType() const
-{
- return impl->getType();
-}
-
-bool Value::isNull() const
-{
- return impl->isNull();
-}
-
-void Value::setNull()
-{
- impl->setNull();
-}
-
-bool Value::isObjectId() const
-{
- return impl->isObjectId();
-}
-
-const ObjectId& Value::asObjectId() const
-{
- return impl->asObjectId();
-}
-
-void Value::setObjectId(const ObjectId& oid)
-{
- impl->setObjectId(oid);
-}
-
-bool Value::isUint() const
-{
- return impl->isUint();
-}
-
-uint32_t Value::asUint() const
-{
- return impl->asUint();
-}
-
-void Value::setUint(uint32_t val)
-{
- impl->setUint(val);
-}
-
-bool Value::isInt() const
-{
- return impl->isInt();
-}
-
-int32_t Value::asInt() const
-{
- return impl->asInt();
-}
-
-void Value::setInt(int32_t val)
-{
- impl->setInt(val);
-}
-
-bool Value::isUint64() const
-{
- return impl->isUint64();
-}
-
-uint64_t Value::asUint64() const
-{
- return impl->asUint64();
-}
-
-void Value::setUint64(uint64_t val)
-{
- impl->setUint64(val);
-}
-
-bool Value::isInt64() const
-{
- return impl->isInt64();
-}
-
-int64_t Value::asInt64() const
-{
- return impl->asInt64();
-}
-
-void Value::setInt64(int64_t val)
-{
- impl->setInt64(val);
-}
-
-bool Value::isString() const
-{
- return impl->isString();
-}
-
-const char* Value::asString() const
-{
- return impl->asString();
-}
-
-void Value::setString(const char* val)
-{
- impl->setString(val);
-}
-
-bool Value::isBool() const
-{
- return impl->isBool();
-}
-
-bool Value::asBool() const
-{
- return impl->asBool();
-}
-
-void Value::setBool(bool val)
-{
- impl->setBool(val);
-}
-
-bool Value::isFloat() const
-{
- return impl->isFloat();
-}
-
-float Value::asFloat() const
-{
- return impl->asFloat();
-}
-
-void Value::setFloat(float val)
-{
- impl->setFloat(val);
-}
-
-bool Value::isDouble() const
-{
- return impl->isDouble();
-}
-
-double Value::asDouble() const
-{
- return impl->asDouble();
-}
-
-void Value::setDouble(double val)
-{
- impl->setDouble(val);
-}
-
-bool Value::isUuid() const
-{
- return impl->isUuid();
-}
-
-const uint8_t* Value::asUuid() const
-{
- return impl->asUuid();
-}
-
-void Value::setUuid(const uint8_t* val)
-{
- impl->setUuid(val);
-}
-
-bool Value::isObject() const
-{
- return impl->isObject();
-}
-
-Object* Value::asObject() const
-{
- return impl->asObject();
-}
-
-void Value::setObject(Object* val)
-{
- impl->setObject(val);
-}
-
-bool Value::isMap() const
-{
- return impl->isMap();
-}
-
-bool Value::keyInMap(const char* key) const
-{
- return impl->keyInMap(key);
-}
-
-Value* Value::byKey(const char* key)
-{
- return impl->byKey(key);
-}
-
-const Value* Value::byKey(const char* key) const
-{
- return impl->byKey(key);
-}
-
-void Value::deleteKey(const char* key)
-{
- impl->deleteKey(key);
-}
-
-void Value::insert(const char* key, Value* val)
-{
- impl->insert(key, val);
-}
-
-uint32_t Value::keyCount() const
-{
- return impl->keyCount();
-}
-
-const char* Value::key(uint32_t idx) const
-{
- return impl->key(idx);
-}
-
-bool Value::isList() const
-{
- return impl->isList();
-}
-
-uint32_t Value::listItemCount() const
-{
- return impl->listItemCount();
-}
-
-Value* Value::listItem(uint32_t idx)
-{
- return impl->listItem(idx);
-}
-
-void Value::appendToList(Value* val)
-{
- impl->appendToList(val);
-}
-
-void Value::deleteListItem(uint32_t idx)
-{
- impl->deleteListItem(idx);
-}
-
-bool Value::isArray() const
-{
- return impl->isArray();
-}
-
-Typecode Value::arrayType() const
-{
- return impl->arrayType();
-}
-
-uint32_t Value::arrayItemCount() const
-{
- return impl->arrayItemCount();
-}
-
-Value* Value::arrayItem(uint32_t idx)
-{
- return impl->arrayItem(idx);
-}
-
-void Value::appendToArray(Value* val)
-{
- impl->appendToArray(val);
-}
-
-void Value::deleteArrayItem(uint32_t idx)
-{
- impl->deleteArrayItem(idx);
-}
+Value::Value(const Value& from) : impl(new ValueImpl(*(from.impl))) {}
+Value::Value(Typecode t, Typecode at) : impl(new ValueImpl(this, t, at)) {}
+Value::Value(ValueImpl* i) : impl(i) {}
+Value::~Value() { delete impl; }
+
+Typecode Value::getType() const { return impl->getType(); }
+bool Value::isNull() const { return impl->isNull(); }
+void Value::setNull() { impl->setNull(); }
+bool Value::isObjectId() const { return impl->isObjectId(); }
+const ObjectId& Value::asObjectId() const { return impl->asObjectId(); }
+void Value::setObjectId(const ObjectId& oid) { impl->setObjectId(oid); }
+bool Value::isUint() const { return impl->isUint(); }
+uint32_t Value::asUint() const { return impl->asUint(); }
+void Value::setUint(uint32_t val) { impl->setUint(val); }
+bool Value::isInt() const { return impl->isInt(); }
+int32_t Value::asInt() const { return impl->asInt(); }
+void Value::setInt(int32_t val) { impl->setInt(val); }
+bool Value::isUint64() const { return impl->isUint64(); }
+uint64_t Value::asUint64() const { return impl->asUint64(); }
+void Value::setUint64(uint64_t val) { impl->setUint64(val); }
+bool Value::isInt64() const { return impl->isInt64(); }
+int64_t Value::asInt64() const { return impl->asInt64(); }
+void Value::setInt64(int64_t val) { impl->setInt64(val); }
+bool Value::isString() const { return impl->isString(); }
+const char* Value::asString() const { return impl->asString(); }
+void Value::setString(const char* val) { impl->setString(val); }
+bool Value::isBool() const { return impl->isBool(); }
+bool Value::asBool() const { return impl->asBool(); }
+void Value::setBool(bool val) { impl->setBool(val); }
+bool Value::isFloat() const { return impl->isFloat(); }
+float Value::asFloat() const { return impl->asFloat(); }
+void Value::setFloat(float val) { impl->setFloat(val); }
+bool Value::isDouble() const { return impl->isDouble(); }
+double Value::asDouble() const { return impl->asDouble(); }
+void Value::setDouble(double val) { impl->setDouble(val); }
+bool Value::isUuid() const { return impl->isUuid(); }
+const uint8_t* Value::asUuid() const { return impl->asUuid(); }
+void Value::setUuid(const uint8_t* val) { impl->setUuid(val); }
+bool Value::isObject() const { return impl->isObject(); }
+Object* Value::asObject() const { return impl->asObject(); }
+void Value::setObject(Object* val) { impl->setObject(val); }
+bool Value::isMap() const { return impl->isMap(); }
+bool Value::keyInMap(const char* key) const { return impl->keyInMap(key); }
+Value* Value::byKey(const char* key) { return impl->byKey(key); }
+const Value* Value::byKey(const char* key) const { return impl->byKey(key); }
+void Value::deleteKey(const char* key) { impl->deleteKey(key); }
+void Value::insert(const char* key, Value* val) { impl->insert(key, val); }
+uint32_t Value::keyCount() const { return impl->keyCount(); }
+const char* Value::key(uint32_t idx) const { return impl->key(idx); }
+bool Value::isList() const { return impl->isList(); }
+uint32_t Value::listItemCount() const { return impl->listItemCount(); }
+Value* Value::listItem(uint32_t idx) { return impl->listItem(idx); }
+void Value::appendToList(Value* val) { impl->appendToList(val); }
+void Value::deleteListItem(uint32_t idx) { impl->deleteListItem(idx); }
+bool Value::isArray() const { return impl->isArray(); }
+Typecode Value::arrayType() const { return impl->arrayType(); }
+uint32_t Value::arrayItemCount() const { return impl->arrayItemCount(); }
+Value* Value::arrayItem(uint32_t idx) { return impl->arrayItem(idx); }
+void Value::appendToArray(Value* val) { impl->appendToArray(val); }
+void Value::deleteArrayItem(uint32_t idx) { impl->deleteArrayItem(idx); }
diff --git a/qpid/cpp/src/qmf/ValueImpl.h b/qpid/cpp/src/qmf/ValueImpl.h
index cf33035bf7..5be4cbc205 100644
--- a/qpid/cpp/src/qmf/ValueImpl.h
+++ b/qpid/cpp/src/qmf/ValueImpl.h
@@ -60,8 +60,7 @@ namespace qmf {
uint8_t uuidVal[16];
} value;
- ValueImpl(Value* e, Typecode t, Typecode at) :
- envelope(e), typecode(t), valid(false), arrayTypecode(at) {}
+ ValueImpl(Value* e, Typecode t, Typecode at);
ValueImpl(Typecode t, qpid::framing::Buffer& b);
ValueImpl(Typecode t);
~ValueImpl();
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index d2a55c0027..81519c3311 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -53,42 +53,65 @@ bool AclData::matchProp(const std::string & src, const std::string& src1)
}
}
-AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params)
-{
- AclResult aclresult = decisionMode;
-
- if (actionList[action] && actionList[action][objType]){
- AclData::actObjItr itrRule = actionList[action][objType]->find(id);
- if (itrRule == actionList[action][objType]->end())
- itrRule = actionList[action][objType]->find("*");
- if (itrRule != actionList[action][objType]->end() ) {
-
- //loop the vector
- for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
-
- // loop the names looking for match
- bool match =true;
- for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
- {
- //match name is exists first
- if (pMItr->first == acl::PROP_NAME){
- if (!matchProp(pMItr->second, name)){
- match= false;
- }
- }else if (params){ //match pMItr against params
- propertyMapItr paramItr = params->find (pMItr->first);
- if (paramItr == params->end()){
- match = false;
- }else if (!matchProp(paramItr->second, pMItr->second)){
- match = false;
- }
+AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType,
+ const std::string& name, std::map<Property, std::string>* params) {
+
+ QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name
+ << " with params " << AclHelper::propertyMapToString(params));
+
+ AclResult aclresult = decisionMode;
+ if (actionList[action] && actionList[action][objType]) {
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+ if (itrRule != actionList[action][objType]->end()) {
+
+ QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
+
+ //loop the vector
+ for (ruleSetItr i = itrRule->second.begin(); i < itrRule->second.end(); i++) {
+ QPID_LOG(debug, "ACL: checking rule " << i->toString());
+ // loop the names looking for match
+ bool match = true;
+ for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++) {
+ //match name is exists first
+ if (pMItr->first == acl::PROP_NAME) {
+ if (matchProp(pMItr->second, name)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
+ << pMItr->second << "' given in the rule");
+ }else{
+ match = false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
+ << pMItr->second << "' given in the rule");
+ }
+ } else if (params) { //match pMItr against params
+ propertyMapItr paramItr = params->find(pMItr->first);
+ if (paramItr == params->end()) {
+ match = false;
+ QPID_LOG(debug, "ACL: the given parameter map in lookup doesn't contain the property '"
+ << AclHelper::getPropertyStr(pMItr->first) << "'");
+ } else if (!matchProp(pMItr->second, paramItr->second)) {
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
+ << ") given in lookup doesn't match the pair("
+ << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
+ match = false;
}
}
- if (match) return getACLResult(i->logOnly, i->log);
- }
- }
- }
- return aclresult;
+ }
+ if (match)
+ {
+ aclresult = getACLResult(i->logOnly, i->log);
+ QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+ }
+ }
+ }
+ }
+
+ QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
}
AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey)
diff --git a/qpid/cpp/src/qpid/acl/AclData.h b/qpid/cpp/src/qpid/acl/AclData.h
index 249c3523eb..a63afab12b 100644
--- a/qpid/cpp/src/qpid/acl/AclData.h
+++ b/qpid/cpp/src/qpid/acl/AclData.h
@@ -22,7 +22,7 @@
#include "qpid/broker/AclModule.h"
#include <vector>
-
+#include <sstream>
namespace qpid {
namespace acl {
@@ -45,6 +45,16 @@ public:
rule (propertyMap& p):log(false),logOnly(false),props(p) {};
+
+ std::string toString () const {
+ std::ostringstream ruleStr;
+ ruleStr << "[log=" << log << ", logOnly=" << logOnly << " props{";
+ for (propertyMapItr pMItr = props.begin(); pMItr != props.end(); pMItr++) {
+ ruleStr << " " << AclHelper::getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ }
+ ruleStr << " }]";
+ return ruleStr.str();
+ }
};
typedef std::vector<rule> ruleSet;
typedef ruleSet::const_iterator ruleSetItr;
diff --git a/qpid/cpp/src/qpid/acl/AclReader.cpp b/qpid/cpp/src/qpid/acl/AclReader.cpp
index 8f5e4f5b57..8f419a6f50 100644
--- a/qpid/cpp/src/qpid/acl/AclReader.cpp
+++ b/qpid/cpp/src/qpid/acl/AclReader.cpp
@@ -83,115 +83,142 @@ std::string AclReader::aclRule::toString() {
return oss.str();
}
-void AclReader::loadDecisionData( boost::shared_ptr<AclData> d )
-{
- d->clear();
- QPID_LOG(debug, "ACL Load Rules");
- int cnt = rules.size();
+void AclReader::loadDecisionData(boost::shared_ptr<AclData> d) {
+ d->clear();
+ QPID_LOG(debug, "ACL Load Rules");
+ int cnt = rules.size();
bool foundmode = false;
- for (rlCitr i=rules.end()-1; cnt; i--,cnt--) {
- QPID_LOG(debug, "ACL Processing " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
-
- if (!foundmode && (*i)->actionAll && (*i)->names.size()==1 && (*((*i)->names.begin())).compare("*")==0 ){
- d->decisionMode = (*i)->res;
- QPID_LOG(debug, "ACL FoundMode " << AclHelper::getAclResultStr(d->decisionMode));
- foundmode=true;
- }else{
- AclData::rule rule((*i)->props);
- bool addrule= true;
-
- switch ((*i)->res)
- {
- case qpid::acl::ALLOWLOG:
- rule.log = true;
- if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode == qpid::acl::ALLOWLOG)
- rule.logOnly = true;
+
+ for (rlCitr i = rules.end() - 1; cnt; i--, cnt--) {
+ QPID_LOG(debug, "ACL Processing " << std::setfill(' ') << std::setw(2)
+ << cnt << " " << (*i)->toString());
+
+ if (!foundmode && (*i)->actionAll && (*i)->names.size() == 1
+ && (*((*i)->names.begin())).compare("*") == 0) {
+ d->decisionMode = (*i)->res;
+ QPID_LOG(debug, "ACL FoundMode " << AclHelper::getAclResultStr(
+ d->decisionMode));
+ foundmode = true;
+ } else {
+ AclData::rule rule((*i)->props);
+ bool addrule = true;
+
+ switch ((*i)->res) {
+ case qpid::acl::ALLOWLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode
+ == qpid::acl::ALLOWLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::ALLOW:
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode
+ == qpid::acl::ALLOWLOG)
+ addrule = false;
+ break;
+ case qpid::acl::DENYLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode
+ == qpid::acl::DENYLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::DENY:
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode
+ == qpid::acl::DENYLOG)
+ addrule = false;
break;
- case qpid::acl::ALLOW:
- if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode == qpid::acl::ALLOWLOG)
- addrule = false;
- break;
- case qpid::acl::DENYLOG:
- rule.log = true;
- if (d->decisionMode == qpid::acl::DENY || d->decisionMode == qpid::acl::DENYLOG)
- rule.logOnly = true;
- break;
- case qpid::acl::DENY:
- if (d->decisionMode == qpid::acl::DENY || d->decisionMode == qpid::acl::DENYLOG)
- addrule = false;
- break;
- default:
- throw Exception("Invalid ACL Result loading rules.");
- }
-
-
- // Action -> Object -> map<user -> set<Rule> >
- if (addrule){
- for (int acnt= ((*i)->actionAll?0:(*i)->action);
- acnt< acl::ACTIONSIZE; (*i)->actionAll?acnt++:acnt=acl::ACTIONSIZE ) {
-
- if (acnt == acl::ACT_PUBLISH) d->transferAcl = true; // we have transfer ACL
-
- QPID_LOG(debug, "ACL Adding action:" << AclHelper::getActionStr((Action)acnt) );
-
- //find the Action, create if not exist
- if (d->actionList[acnt]==NULL) {
- d->actionList[acnt] = new AclData::aclAction[qpid::acl::OBJECTSIZE];
- for (int j=0;j<qpid::acl::OBJECTSIZE; j++)
- d->actionList[acnt][j] = NULL;
- }
+ default:
+ throw Exception("Invalid ACL Result loading rules.");
+ }
+
+ // Action -> Object -> map<user -> set<Rule> >
+ if (addrule) {
+ std::ostringstream actionstr;
+ for (int acnt = ((*i)->actionAll ? 0 : (*i)->action); acnt
+ < acl::ACTIONSIZE; (*i)->actionAll ? acnt++ : acnt
+ = acl::ACTIONSIZE) {
+
+ if (acnt == acl::ACT_PUBLISH)
+ d->transferAcl = true; // we have transfer ACL
+
+ actionstr << AclHelper::getActionStr((Action) acnt) << ",";
+
+ //find the Action, create if not exist
+ if (d->actionList[acnt] == NULL) {
+ d->actionList[acnt]
+ = new AclData::aclAction[qpid::acl::OBJECTSIZE];
+ for (int j = 0; j < qpid::acl::OBJECTSIZE; j++)
+ d->actionList[acnt][j] = NULL;
+ }
// optimize this loop to limit to valid options only!!
- for (int ocnt= ((*i)->objStatus!=aclRule::VALUE ?0:(*i)->object);
- ocnt< acl::OBJECTSIZE;
- (*i)->objStatus!=aclRule::VALUE?ocnt++:ocnt=acl::OBJECTSIZE ) {
-
- QPID_LOG(debug, "ACL Adding object:" << AclHelper::getObjectTypeStr((ObjectType)ocnt) );
-
- //find the Object, create if not exist
- if (d->actionList[acnt][ocnt] == NULL)
- d->actionList[acnt][ocnt] = new AclData::actionObject;
-
- // add users and Rule to object set
- bool allNames=false;
- // check to see if names.begin is '*'
- if ( (*(*i)->names.begin()).compare("*")==0 ) allNames = true;
-
- for (nsCitr itr = (allNames?names.begin():(*i)->names.begin());
- itr != (allNames?names.end():(*i)->names.end()); itr++) {
- AclData::actObjItr itrRule = d->actionList[acnt][ocnt]->find(*itr);
- if (itrRule == d->actionList[acnt][ocnt]->end()) {
- QPID_LOG(debug, "ACL Adding rule & user:" << *itr);
- AclData::ruleSet rSet;
- rSet.push_back(rule);
- d->actionList[acnt][ocnt]->insert(make_pair( std::string(*itr) , rSet) );
- }else{
-
- // TODO add code to check for dead rules
- // allow peter create queue name=tmp <-- dead rule!!
- // allow peter create queue
-
- itrRule->second.push_back(rule);
- QPID_LOG(debug, "ACL Adding rule to user:" << *itr);
- }
- }
-
- }
-
- }
- }else{
- QPID_LOG(debug, "ACL Skipping based on Mode:" << AclHelper::getAclResultStr(d->decisionMode) );
- }
- }
-
- }
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0
+ : (*i)->object); ocnt < acl::OBJECTSIZE; (*i)->objStatus
+ != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+
+ //find the Object, create if not exist
+ if (d->actionList[acnt][ocnt] == NULL)
+ d->actionList[acnt][ocnt]
+ = new AclData::actionObject;
+
+ // add users and Rule to object set
+ bool allNames = false;
+ // check to see if names.begin is '*'
+ if ((*(*i)->names.begin()).compare("*") == 0)
+ allNames = true;
+
+ for (nsCitr itr = (allNames ? names.begin()
+ : (*i)->names.begin()); itr
+ != (allNames ? names.end() : (*i)->names.end()); itr++) {
+
+ AclData::actObjItr itrRule =
+ d->actionList[acnt][ocnt]->find(*itr);
+
+ if (itrRule == d->actionList[acnt][ocnt]->end()) {
+ AclData::ruleSet rSet;
+ rSet.push_back(rule);
+ d->actionList[acnt][ocnt]->insert(make_pair(
+ std::string(*itr), rSet));
+ } else {
+
+ // TODO add code to check for dead rules
+ // allow peter create queue name=tmp <-- dead rule!!
+ // allow peter create queue
+
+ itrRule->second.push_back(rule);
+ }
+ }
+
+ }
+ }
+
+ std::ostringstream objstr;
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0 : (*i)->object); ocnt < acl::OBJECTSIZE;
+ (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+ objstr << AclHelper::getObjectTypeStr((ObjectType) ocnt) << ",";
+ }
+
+ bool allNames = ((*(*i)->names.begin()).compare("*") == 0);
+ std::ostringstream userstr;
+ for (nsCitr itr = (allNames ? names.begin() : (*i)->names.begin());
+ itr != (allNames ? names.end() : (*i)->names.end()); itr++) {
+ userstr << *itr << ",";
+ }
+
+ QPID_LOG(debug,"ACL: Adding actions {" << actionstr.str().substr(0,actionstr.str().length()-1)
+ << "} to objects {" << objstr.str().substr(0,objstr.str().length()-1)
+ << "} with props " << AclHelper::propertyMapToString(&rule.props)
+ << " for users {" << userstr.str().substr(0,userstr.str().length()-1) << "}" );
+ } else {
+ QPID_LOG(debug, "ACL Skipping based on Mode:"
+ << AclHelper::getAclResultStr(d->decisionMode));
+ }
+ }
+ }
}
-
-
void AclReader::aclRule::processName(const std::string& name, const groupMap& groups) {
if (name.compare("all") == 0) {
names.insert("*");
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index 4a6590fb5f..093e9cea32 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -435,8 +435,8 @@ void ManagementAgentImpl::invokeMethodRequest(Buffer& inBuffer, uint32_t sequenc
} else {
if ((iter->second->getPackageName() != packageName) ||
(iter->second->getClassName() != className)) {
- outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
- outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
}
else
try {
diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h
index a78b2d5b4a..536fa21b2b 100644
--- a/qpid/cpp/src/qpid/broker/AclModule.h
+++ b/qpid/cpp/src/qpid/broker/AclModule.h
@@ -26,7 +26,7 @@
#include <map>
#include <set>
#include <string>
-
+#include <sstream>
namespace qpid {
@@ -179,6 +179,8 @@ class AclHelper {
typedef std::map<ObjectType, actionMapPtr> objectMap;
typedef objectMap::const_iterator omCitr;
typedef boost::shared_ptr<objectMap> objectMapPtr;
+ typedef std::map<Property, std::string> propMap;
+ typedef propMap::const_iterator propMapItr;
// This map contains the legal combinations of object/action/properties found in an ACL file
static void loadValidationMap(objectMapPtr& map) {
@@ -248,6 +250,19 @@ class AclHelper {
map->insert(objectPair(OBJ_METHOD, a4));
}
+
+ static std::string propertyMapToString(const std::map<Property, std::string>* params) {
+ std::ostringstream ss;
+ ss << "{";
+ if (params)
+ {
+ for (propMapItr pMItr = params->begin(); pMItr != params->end(); pMItr++) {
+ ss << " " << getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ }
+ }
+ ss << " }";
+ return ss.str();
+ }
};
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index 8b6cb5e049..13cf88fb11 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -386,7 +386,7 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty))
status = Manageable::STATUS_OK;
else
- return Manageable::STATUS_INVALID_PARAMETER;
+ return Manageable::STATUS_PARAMETER_INVALID;
break;
}
default:
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
index a1a3c6ada7..3b8a6c71d4 100644
--- a/qpid/cpp/src/qpid/broker/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -269,11 +269,13 @@ bool Connection::doOutput() {
cb(); // Lend the IO thread for management processing
}
}
- if (mgmtClosing)
+ if (mgmtClosing) {
+ closed();
close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request");
- else
+ } else {
//then do other output as needed:
return outputTasks.doOutput();
+ }
}catch(ConnectionException& e){
close(e.code, e.getMessage());
}catch(std::exception& e){
diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp
index b1fc1295f3..90d81b81c6 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.cpp
+++ b/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -38,7 +38,7 @@ using qpid::management::Manageable;
using qpid::management::Args;
namespace _qmf = qmf::org::apache::qpid::broker;
-namespace
+namespace
{
const std::string qpidMsgSequence("qpid.msg_sequence");
const std::string qpidSequenceCounter("qpid.sequence_counter");
@@ -51,17 +51,19 @@ const std::string fedOpBind("B");
const std::string fedOpUnbind("U");
const std::string fedOpReorigin("R");
const std::string fedOpHello("H");
+
+const std::string QPID_MANAGEMENT("qpid.management");
}
Exchange::PreRoute::PreRoute(Deliverable& msg, Exchange* _p):parent(_p) {
if (parent){
if (parent->sequence || parent->ive) parent->sequenceLock.lock();
-
+
if (parent->sequence){
parent->sequenceNo++;
- msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders().setInt64(qpidMsgSequence,parent->sequenceNo);
- }
+ msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders().setInt64(qpidMsgSequence,parent->sequenceNo);
+ }
if (parent->ive) {
parent->lastMsg = &( msg.getMessage());
}
@@ -99,11 +101,9 @@ Exchange::Exchange (const string& _name, Manageable* parent, Broker* b) :
}
}
-static const std::string QPID_MANAGEMENT("qpid.management");
-
Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args,
Manageable* parent, Broker* b)
- : name(_name), durable(_durable), alternateUsers(0), persistenceId(0),
+ : name(_name), durable(_durable), alternateUsers(0), persistenceId(0),
args(_args), sequence(false), sequenceNo(0), ive(false), mgmtExchange(0), broker(b)
{
if (parent != 0 && broker != 0)
@@ -169,7 +169,7 @@ Exchange::shared_ptr Exchange::decode(ExchangeRegistry& exchanges, Buffer& buffe
string name;
string type;
FieldTable args;
-
+
buffer.getShortString(name);
bool durable(buffer.getOctet());
buffer.getShortString(type);
@@ -185,7 +185,7 @@ Exchange::shared_ptr Exchange::decode(ExchangeRegistry& exchanges, Buffer& buffe
}
}
-void Exchange::encode(Buffer& buffer) const
+void Exchange::encode(Buffer& buffer) const
{
buffer.putShortString(name);
buffer.putOctet(durable);
@@ -195,8 +195,8 @@ void Exchange::encode(Buffer& buffer) const
buffer.put(args);
}
-uint32_t Exchange::encodedSize() const
-{
+uint32_t Exchange::encodedSize() const
+{
return name.size() + 1/*short string size*/
+ 1 /*durable*/
+ getType().size() + 1/*short string size*/
diff --git a/qpid/cpp/src/qpid/broker/Link.cpp b/qpid/cpp/src/qpid/broker/Link.cpp
index 9ce0c710bd..cdba18ccf9 100644
--- a/qpid/cpp/src/qpid/broker/Link.cpp
+++ b/qpid/cpp/src/qpid/broker/Link.cpp
@@ -200,8 +200,10 @@ void Link::destroy ()
// Move the bridges to be deleted into a local vector so there is no
// corruption of the iterator caused by bridge deletion.
- for (Bridges::iterator i = active.begin(); i != active.end(); i++)
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->closed();
toDelete.push_back(*i);
+ }
active.clear();
for (Bridges::iterator i = created.begin(); i != created.end(); i++)
@@ -264,7 +266,6 @@ void Link::ioThreadProcessing()
}
if (!cancellations.empty()) {
for (Bridges::iterator i = cancellations.begin(); i != cancellations.end(); ++i) {
- active.push_back(*i);
(*i)->cancel(*connection);
}
cancellations.clear();
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index 639f04faa2..7360010192 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -362,7 +362,7 @@ boost::intrusive_ptr<Message>& Message::getReplacementMessage(const Queue* qfor)
Replacement::iterator i = replacement.find(qfor);
if (i != replacement.end()){
return i->second;
- }
+ }
return empty;
}
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index 0024509bc8..e4d09b1042 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -34,12 +34,12 @@
#include <vector>
namespace qpid {
-
+
namespace framing {
class FieldTable;
class SequenceNumber;
}
-
+
namespace broker {
class ConnectionToken;
class Exchange;
@@ -145,9 +145,9 @@ public:
bool isExcluded(const std::vector<std::string>& excludes) const;
void addTraceId(const std::string& id);
-
- void forcePersistent();
- bool isForcedPersistent();
+
+ void forcePersistent();
+ bool isForcedPersistent();
boost::intrusive_ptr<Message>& getReplacementMessage(const Queue* qfor) const;
void setReplacementMessage(boost::intrusive_ptr<Message> msg, const Queue* qfor);
diff --git a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
index e01fd81074..14b233fd6c 100644
--- a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
+++ b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,14 +30,14 @@ using boost::intrusive_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
-namespace
+namespace
{
std::string type_str(uint8_t type);
+ const std::string QPID_MANAGEMENT("qpid.management");
}
-MessageBuilder::MessageBuilder(MessageStore* const _store, uint64_t _stagingThreshold) :
- state(DORMANT), store(_store), stagingThreshold(_stagingThreshold), staging(false) {}
-static const std::string QPID_MANAGEMENT("qpid.management");
+MessageBuilder::MessageBuilder(MessageStore* const _store, uint64_t _stagingThreshold) :
+ state(DORMANT), store(_store), stagingThreshold(_stagingThreshold), staging(false) {}
void MessageBuilder::handle(AMQFrame& frame)
{
@@ -54,10 +54,10 @@ void MessageBuilder::handle(AMQFrame& frame)
AMQFrame header((AMQHeaderBody()));
header.setBof(false);
header.setEof(false);
- message->getFrames().append(header);
+ message->getFrames().append(header);
} else if (type != HEADER_BODY) {
throw CommandInvalidException(
- QPID_MSG("Invalid frame sequence for message, expected header or content got "
+ QPID_MSG("Invalid frame sequence for message, expected header or content got "
<< type_str(type) << ")"));
}
state = CONTENT;
@@ -74,13 +74,13 @@ void MessageBuilder::handle(AMQFrame& frame)
} else {
message->getFrames().append(frame);
//have we reached the staging limit? if so stage message and release content
- if (state == CONTENT
- && stagingThreshold
+ if (state == CONTENT
+ && stagingThreshold
&& message->getFrames().getContentSize() >= stagingThreshold
&& !NullMessageStore::isNullStore(store)
- && message->getExchangeName() != QPID_MANAGEMENT /* don't stage mgnt messages */)
+ && message->getExchangeName() != QPID_MANAGEMENT /* don't stage mgnt messages */)
{
- message->releaseContent(store);
+ message->releaseContent(store);
staging = true;
}
}
@@ -108,7 +108,7 @@ const std::string CONTENT_BODY_S = "CONTENT";
const std::string HEARTBEAT_BODY_S = "HEARTBEAT";
const std::string UNKNOWN = "unknown";
-std::string type_str(uint8_t type)
+std::string type_str(uint8_t type)
{
switch(type) {
case METHOD_BODY: return METHOD_BODY_S;
@@ -124,7 +124,7 @@ std::string type_str(uint8_t type)
void MessageBuilder::checkType(uint8_t expected, uint8_t actual)
{
if (expected != actual) {
- throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (expected "
+ throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (expected "
<< type_str(expected) << " got " << type_str(actual) << ")"));
}
}
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
index c1f86d4ca4..2ef223aa81 100644
--- a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp
@@ -62,7 +62,7 @@ void PersistableMessage::flush()
void PersistableMessage::setContentReleased() {contentReleased = true; }
bool PersistableMessage::isContentReleased()const { return contentReleased; }
-
+
bool PersistableMessage::isEnqueueComplete() {
sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
return asyncEnqueueCounter == 0;
diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h
index 05de9ff4c3..0274b41375 100644
--- a/qpid/cpp/src/qpid/broker/PersistableMessage.h
+++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h
@@ -46,7 +46,7 @@ class PersistableMessage : public Persistable
sys::Mutex asyncEnqueueLock;
sys::Mutex asyncDequeueLock;
sys::Mutex storeLock;
-
+
/**
* Tracks the number of outstanding asynchronous enqueue
* operations. When the message is enqueued asynchronously the
@@ -97,7 +97,7 @@ class PersistableMessage : public Persistable
void flush();
bool isContentReleased() const;
-
+
QPID_BROKER_EXTERN bool isEnqueueComplete();
QPID_BROKER_EXTERN void enqueueComplete();
diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp
index 08ee133981..b2a8e223c5 100644
--- a/qpid/cpp/src/qpid/broker/Queue.cpp
+++ b/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -597,7 +597,7 @@ void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
Mutex::ScopedUnlock u(messageLock);
dequeue(0, QueuedMessage(qm.queue, old, qm.position));
}
- }
+ }
}else {
messages.push_back(qm);
listeners.populate(copy);
@@ -702,7 +702,7 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
if (inLastNodeFailure && persistLastNode){
msg->forcePersistent();
}
-
+
if (traceId.size()) {
msg->addTraceId(traceId);
}
diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.h b/qpid/cpp/src/qpid/broker/QueueRegistry.h
index c134f399c8..72a91dff24 100644
--- a/qpid/cpp/src/qpid/broker/QueueRegistry.h
+++ b/qpid/cpp/src/qpid/broker/QueueRegistry.h
@@ -111,7 +111,7 @@ class QueueRegistry {
/** Call f for each queue in the registry. */
template <class F> void eachQueue(F f) const {
- qpid::sys::RWlock::ScopedWlock l(lock);
+ qpid::sys::RWlock::ScopedRlock l(lock);
for (QueueMap::const_iterator i = queues.begin(); i != queues.end(); ++i)
f(i->second);
}
diff --git a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
index 2a19115fd1..5bc4cdf960 100644
--- a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
+++ b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
@@ -195,7 +195,7 @@ void RecoverableQueueImpl::setPersistenceId(uint64_t id)
{
queue->setPersistenceId(id);
}
-
+
uint64_t RecoverableQueueImpl::getPersistenceId() const
{
return queue->getPersistenceId();
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
index b0c5e9ea00..a1ad5a0a30 100644
--- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -72,7 +72,7 @@ void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const
params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? _TRUE : _FALSE) ));
params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE)));
if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,&params) )
- throw NotAllowedException(QPID_MSG("ACL denied exhange declare request from " << getConnection().getUserId()));
+ throw NotAllowedException(QPID_MSG("ACL denied exchange declare request from " << getConnection().getUserId()));
}
//TODO: implement autoDelete
@@ -121,9 +121,11 @@ void SessionAdapter::ExchangeHandlerImpl::checkType(Exchange::shared_ptr exchang
void SessionAdapter::ExchangeHandlerImpl::checkAlternate(Exchange::shared_ptr exchange, Exchange::shared_ptr alternate)
{
- if (alternate && alternate != exchange->getAlternate())
+ if (alternate && ((exchange->getAlternate() && alternate != exchange->getAlternate())
+ || !exchange->getAlternate()))
throw NotAllowedException(QPID_MSG("Exchange declared with alternate-exchange "
- << exchange->getAlternate()->getName() << ", requested "
+ << (exchange->getAlternate() ? exchange->getAlternate()->getName() : "<nonexistent>")
+ << ", requested "
<< alternate->getName()));
}
@@ -132,7 +134,7 @@ void SessionAdapter::ExchangeHandlerImpl::delete_(const string& name, bool /*ifU
AclModule* acl = getBroker().getAcl();
if (acl) {
if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_EXCHANGE,name,NULL) )
- throw NotAllowedException(QPID_MSG("ACL denied exhange delete request from " << getConnection().getUserId()));
+ throw NotAllowedException(QPID_MSG("ACL denied exchange delete request from " << getConnection().getUserId()));
}
//TODO: implement unused
@@ -152,7 +154,7 @@ ExchangeQueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& nam
AclModule* acl = getBroker().getAcl();
if (acl) {
if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,name,NULL) )
- throw NotAllowedException(QPID_MSG("ACL denied exhange query request from " << getConnection().getUserId()));
+ throw NotAllowedException(QPID_MSG("ACL denied exchange query request from " << getConnection().getUserId()));
}
try {
@@ -169,8 +171,12 @@ void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName,
{
AclModule* acl = getBroker().getAcl();
if (acl) {
- if (!acl->authorise(getConnection().getUserId(),acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,routingKey) )
- throw NotAllowedException(QPID_MSG("ACL denied exhange bind request from " << getConnection().getUserId()));
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey));
+
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,&params))
+ throw NotAllowedException(QPID_MSG("ACL denied exchange bind request from " << getConnection().getUserId()));
}
Queue::shared_ptr queue = getQueue(queueName);
@@ -232,8 +238,8 @@ ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
params.insert(make_pair(acl::PROP_ROUTINGKEY, key));
- if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchangeName,&params) )
- throw NotAllowedException(QPID_MSG("ACL denied exhange bound request from " << getConnection().getUserId()));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,exchangeName,&params) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange bound request from " << getConnection().getUserId()));
}
Exchange::shared_ptr exchange;
diff --git a/qpid/cpp/src/qpid/client/Dispatcher.cpp b/qpid/cpp/src/qpid/client/Dispatcher.cpp
index 43cbf3aa4d..a715c623bf 100644
--- a/qpid/cpp/src/qpid/client/Dispatcher.cpp
+++ b/qpid/cpp/src/qpid/client/Dispatcher.cpp
@@ -29,7 +29,14 @@
#include "qpid/client/Message.h"
#include "qpid/client/MessageImpl.h"
-#include <boost/state_saver.hpp>
+#include <boost/version.hpp>
+#if (BOOST_VERSION >= 104000)
+# include <boost/serialization/state_saver.hpp>
+ using boost::serialization::state_saver;
+#else
+# include <boost/state_saver.hpp>
+ using boost::state_saver;
+#endif /* BOOST_VERSION */
using qpid::framing::FrameSet;
using qpid::framing::MessageTransferBody;
@@ -65,7 +72,7 @@ void Dispatcher::run()
Mutex::ScopedLock l(lock);
if (running)
throw Exception("Dispatcher is already running.");
- boost::state_saver<bool> reset(running); // Reset to false on exit.
+ state_saver<bool> reset(running); // Reset to false on exit.
running = true;
try {
while (!queue->isClosed()) {
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp
new file mode 100644
index 0000000000..80be5c56f3
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp
@@ -0,0 +1,111 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AcceptTracker.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+void AcceptTracker::State::accept()
+{
+ unconfirmed.add(unaccepted);
+ unaccepted.clear();
+}
+
+void AcceptTracker::State::release()
+{
+ unaccepted.clear();
+}
+
+uint32_t AcceptTracker::State::acceptsPending()
+{
+ return unconfirmed.size();
+}
+
+void AcceptTracker::State::completed(qpid::framing::SequenceSet& set)
+{
+ unconfirmed.remove(set);
+}
+
+void AcceptTracker::delivered(const std::string& destination, const qpid::framing::SequenceNumber& id)
+{
+ aggregateState.unaccepted.add(id);
+ destinationState[destination].unaccepted.add(id);
+}
+
+void AcceptTracker::accept(qpid::client::AsyncSession& session)
+{
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.accept();
+ }
+ Record record;
+ record.status = session.messageAccept(aggregateState.unaccepted);
+ record.accepted = aggregateState.unaccepted;
+ pending.push_back(record);
+ aggregateState.accept();
+}
+
+void AcceptTracker::release(qpid::client::AsyncSession& session)
+{
+ session.messageRelease(aggregateState.unaccepted);
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.release();
+ }
+ aggregateState.release();
+}
+
+uint32_t AcceptTracker::acceptsPending()
+{
+ checkPending();
+ return aggregateState.acceptsPending();
+}
+
+uint32_t AcceptTracker::acceptsPending(const std::string& destination)
+{
+ checkPending();
+ return destinationState[destination].acceptsPending();
+}
+
+void AcceptTracker::reset()
+{
+ destinationState.clear();
+ aggregateState.unaccepted.clear();
+ aggregateState.unconfirmed.clear();
+ pending.clear();
+}
+
+void AcceptTracker::checkPending()
+{
+ while (!pending.empty() && pending.front().status.isComplete()) {
+ completed(pending.front().accepted);
+ pending.pop_front();
+ }
+}
+
+void AcceptTracker::completed(qpid::framing::SequenceSet& set)
+{
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.completed(set);
+ }
+ aggregateState.completed(set);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.h b/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.h
new file mode 100644
index 0000000000..fb58a3a8c8
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AcceptTracker.h
@@ -0,0 +1,85 @@
+#ifndef QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H
+#define QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Completion.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceSet.h"
+#include <deque>
+#include <map>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Tracks the set of messages requiring acceptance, and those for
+ * which an accept has been issued but is yet to be confirmed
+ * complete.
+ */
+class AcceptTracker
+{
+ public:
+ void delivered(const std::string& destination, const qpid::framing::SequenceNumber& id);
+ void accept(qpid::client::AsyncSession&);
+ void release(qpid::client::AsyncSession&);
+ uint32_t acceptsPending();
+ uint32_t acceptsPending(const std::string& destination);
+ void reset();
+ private:
+ struct State
+ {
+ /**
+ * ids of messages that have been delivered but not yet
+ * accepted
+ */
+ qpid::framing::SequenceSet unaccepted;
+ /**
+ * ids of messages for which an accpet has been issued but not
+ * yet confirmed as completed
+ */
+ qpid::framing::SequenceSet unconfirmed;
+
+ void accept();
+ void release();
+ uint32_t acceptsPending();
+ void completed(qpid::framing::SequenceSet&);
+ };
+ typedef std::map<std::string, State> StateMap;
+ struct Record
+ {
+ qpid::client::Completion status;
+ qpid::framing::SequenceSet accepted;
+ };
+ typedef std::deque<Record> Records;
+
+ State aggregateState;
+ StateMap destinationState;
+ Records pending;
+
+ void checkPending();
+ void completed(qpid::framing::SequenceSet&);
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
index 6ff9c2397a..9b9f06ec57 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -22,6 +22,7 @@
#include "qpid/client/amqp0_10/Codecs.h"
#include "qpid/client/amqp0_10/MessageSource.h"
#include "qpid/client/amqp0_10/MessageSink.h"
+#include "qpid/client/amqp0_10/OutgoingMessage.h"
#include "qpid/messaging/Address.h"
#include "qpid/messaging/Filter.h"
#include "qpid/messaging/Message.h"
@@ -122,7 +123,7 @@ class Exchange : public MessageSink
bool passive = true, const std::string& type = EMPTY_STRING, bool durable = false,
const FieldTable& options = EMPTY_FIELD_TABLE);
void declare(qpid::client::AsyncSession& session, const std::string& name);
- void send(qpid::client::AsyncSession& session, const std::string& name, qpid::messaging::Message& message);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
void cancel(qpid::client::AsyncSession& session, const std::string& name);
private:
const std::string name;
@@ -139,7 +140,7 @@ class QueueSink : public MessageSink
QueueSink(const std::string& name, bool passive=true, bool exclusive=false,
bool autoDelete=false, bool durable=false, const FieldTable& options = EMPTY_FIELD_TABLE);
void declare(qpid::client::AsyncSession& session, const std::string& name);
- void send(qpid::client::AsyncSession& session, const std::string& name, qpid::messaging::Message& message);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
void cancel(qpid::client::AsyncSession& session, const std::string& name);
private:
const std::string name;
@@ -328,14 +329,12 @@ void Exchange::declare(qpid::client::AsyncSession& session, const std::string&)
}
}
-void Exchange::send(qpid::client::AsyncSession& session, const std::string&, qpid::messaging::Message& m)
+void Exchange::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
{
- qpid::client::Message message;
- convert(m, message);
- if (message.getDeliveryProperties().getRoutingKey().empty() && !defaultSubject.empty()) {
- message.getDeliveryProperties().setRoutingKey(defaultSubject);
+ if (m.message.getDeliveryProperties().getRoutingKey().empty() && !defaultSubject.empty()) {
+ m.message.getDeliveryProperties().setRoutingKey(defaultSubject);
}
- session.messageTransfer(arg::destination=name, arg::content=message);
+ m.status = session.messageTransfer(arg::destination=name, arg::content=m.message);
}
void Exchange::cancel(qpid::client::AsyncSession&, const std::string&) {}
@@ -355,12 +354,10 @@ void QueueSink::declare(qpid::client::AsyncSession& session, const std::string&)
arg::autoDelete=autoDelete, arg::arguments=options);
}
}
-void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, qpid::messaging::Message& m)
+void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
{
- qpid::client::Message message;
- convert(m, message);
- message.getDeliveryProperties().setRoutingKey(name);
- session.messageTransfer(arg::content=message);
+ m.message.getDeliveryProperties().setRoutingKey(name);
+ m.status = session.messageTransfer(arg::content=m.message);
}
void QueueSink::cancel(qpid::client::AsyncSession&, const std::string&) {}
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h
index 87758abe6d..9d5657450d 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h
@@ -31,8 +31,8 @@ class ReplyTo;
}
namespace messaging {
-class Address;
-class Filter;
+struct Address;
+struct Filter;
}
namespace client {
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
index 9aee3118fe..57184e3937 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
@@ -183,25 +183,25 @@ boost::shared_ptr<FieldValue> toFieldValue(const Variant& in)
{
boost::shared_ptr<FieldValue> out;
switch (in.getType()) {
- case VOID: out = boost::shared_ptr<FieldValue>(new VoidValue()); break;
- case BOOL: out = boost::shared_ptr<FieldValue>(new BoolValue(in.asBool())); break;
- case UINT8: out = boost::shared_ptr<FieldValue>(new Unsigned8Value(in.asUint8())); break;
- case UINT16: out = boost::shared_ptr<FieldValue>(new Unsigned16Value(in.asUint16())); break;
- case UINT32: out = boost::shared_ptr<FieldValue>(new Unsigned32Value(in.asUint32())); break;
- case UINT64: out = boost::shared_ptr<FieldValue>(new Unsigned64Value(in.asUint64())); break;
- case INT8: out = boost::shared_ptr<FieldValue>(new Integer8Value(in.asInt8())); break;
- case INT16: out = boost::shared_ptr<FieldValue>(new Integer16Value(in.asInt16())); break;
- case INT32: out = boost::shared_ptr<FieldValue>(new Integer32Value(in.asInt32())); break;
- case INT64: out = boost::shared_ptr<FieldValue>(new Integer64Value(in.asInt64())); break;
- case FLOAT: out = boost::shared_ptr<FieldValue>(new FloatValue(in.asFloat())); break;
- case DOUBLE: out = boost::shared_ptr<FieldValue>(new DoubleValue(in.asDouble())); break;
+ case VAR_VOID: out = boost::shared_ptr<FieldValue>(new VoidValue()); break;
+ case VAR_BOOL: out = boost::shared_ptr<FieldValue>(new BoolValue(in.asBool())); break;
+ case VAR_UINT8: out = boost::shared_ptr<FieldValue>(new Unsigned8Value(in.asUint8())); break;
+ case VAR_UINT16: out = boost::shared_ptr<FieldValue>(new Unsigned16Value(in.asUint16())); break;
+ case VAR_UINT32: out = boost::shared_ptr<FieldValue>(new Unsigned32Value(in.asUint32())); break;
+ case VAR_UINT64: out = boost::shared_ptr<FieldValue>(new Unsigned64Value(in.asUint64())); break;
+ case VAR_INT8: out = boost::shared_ptr<FieldValue>(new Integer8Value(in.asInt8())); break;
+ case VAR_INT16: out = boost::shared_ptr<FieldValue>(new Integer16Value(in.asInt16())); break;
+ case VAR_INT32: out = boost::shared_ptr<FieldValue>(new Integer32Value(in.asInt32())); break;
+ 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 STRING: out = boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); break;
- case MAP:
+ case VAR_STRING: out = boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); break;
+ case VAR_MAP:
//out = boost::shared_ptr<FieldValue>(toFieldValueCollection<FieldTableValue>(in.asMap(), &toFieldTableEntry));
out = boost::shared_ptr<FieldValue>(toFieldTableValue(in.asMap()));
break;
- case LIST:
+ case VAR_LIST:
//out = boost::shared_ptr<FieldValue>(toFieldValueCollection<ListValue>(in.asList(), &toFieldValue));
out = boost::shared_ptr<FieldValue>(toListValue(in.asList()));
break;
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h b/qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
index 6147c5682e..b5a561a9c3 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
@@ -1,5 +1,5 @@
-#ifndef QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H
-#define QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H
+#ifndef QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
+#define QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
/*
*
@@ -21,30 +21,21 @@
* under the License.
*
*/
-
-#include "qpid/framing/SequenceNumber.h"
-#include <map>
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/FieldTable.h"
namespace qpid {
namespace client {
namespace amqp0_10 {
/**
- * Provides a mapping from command ids to application supplied
- * 'tokens', and is used to determine when the sending or
- * acknowledging of a specific message is complete.
+ * Declarations of a couple of conversion functions implemented in
+ * Codecs.cpp but not exposed through API
*/
-class CompletionTracker
-{
- public:
- void track(qpid::framing::SequenceNumber command, void* token);
- void completedTo(qpid::framing::SequenceNumber command);
- void* getLastCompletedToken();
- private:
- typedef std::map<qpid::framing::SequenceNumber, void*> Tokens;
- Tokens tokens;
- void* lastCompleted;
-};
+
+void translate(const qpid::messaging::Variant::Map& from, qpid::framing::FieldTable& to);
+void translate(const qpid::framing::FieldTable& from, qpid::messaging::Variant::Map& to);
+
}}} // namespace qpid::client::amqp0_10
-#endif /*!QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H*/
+#endif /*!QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
index 9f738731e2..3a735b5698 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -21,14 +21,16 @@
#include "ConnectionImpl.h"
#include "SessionImpl.h"
#include "qpid/messaging/Session.h"
-#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/PrivateImplRef.h"
#include "qpid/log/Statement.h"
+#include <boost/intrusive_ptr.hpp>
namespace qpid {
namespace client {
namespace amqp0_10 {
using qpid::messaging::Variant;
+using namespace qpid::sys;
template <class T> void setIfFound(const Variant::Map& map, const std::string& key, T& value)
{
@@ -56,24 +58,124 @@ void convert(const Variant::Map& from, ConnectionSettings& to)
setIfFound(from, "bounds", to.bounds);
}
-ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options)
+ConnectionImpl::ConnectionImpl(const std::string& u, const Variant::Map& options) :
+ url(u), reconnectionEnabled(true), timeout(-1),
+ minRetryInterval(1), maxRetryInterval(30)
{
QPID_LOG(debug, "Opening connection to " << url << " with " << options);
- Url u(url);
- ConnectionSettings settings;
convert(options, settings);
- connection.open(u, settings);
+ setIfFound(options, "reconnection-enabled", reconnectionEnabled);
+ setIfFound(options, "reconnection-timeout", timeout);
+ setIfFound(options, "min-retry-interval", minRetryInterval);
+ setIfFound(options, "max-retry-interval", maxRetryInterval);
+ connection.open(url, settings);
}
void ConnectionImpl::close()
{
+ qpid::sys::Mutex::ScopedLock l(lock);
connection.close();
}
+boost::intrusive_ptr<SessionImpl> getImplPtr(qpid::messaging::Session& session)
+{
+ return boost::dynamic_pointer_cast<SessionImpl>(
+ qpid::client::PrivateImplRef<qpid::messaging::Session>::get(session)
+ );
+}
+
+void ConnectionImpl::closed(SessionImpl& s)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ if (getImplPtr(*i).get() == &s) {
+ sessions.erase(i);
+ break;
+ }
+ }
+}
+
qpid::messaging::Session ConnectionImpl::newSession()
{
- qpid::messaging::Session impl(new SessionImpl(connection.newSession()));
+ qpid::messaging::Session impl(new SessionImpl(*this));
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ sessions.push_back(impl);
+ }
+ try {
+ getImplPtr(impl)->setSession(connection.newSession());
+ } catch (const TransportFailure&) {
+ reconnect();
+ }
return impl;
}
+void ConnectionImpl::reconnect()
+{
+ AbsTime start = now();
+ ScopedLock<Semaphore> l(semaphore);
+ if (!connection.isOpen()) connect(start);
+}
+
+bool expired(const AbsTime& start, int timeout)
+{
+ if (timeout == 0) return true;
+ if (timeout < 0) return false;
+ Duration used(start, now());
+ Duration allowed = timeout * TIME_SEC;
+ return allowed > used;
+}
+
+void ConnectionImpl::connect(const AbsTime& started)
+{
+ for (int i = minRetryInterval; !tryConnect(); i = std::min(i * 2, maxRetryInterval)) {
+ if (expired(started, timeout)) throw TransportFailure();
+ else qpid::sys::sleep(i);
+ }
+}
+
+bool ConnectionImpl::tryConnect()
+{
+ if (tryConnect(url) || tryConnect(connection.getKnownBrokers())) {
+ return resetSessions();
+ } else {
+ return false;
+ }
+}
+
+bool ConnectionImpl::tryConnect(const Url& u)
+{
+ try {
+ QPID_LOG(info, "Trying to connect to " << url << "...");
+ connection.open(u, settings);
+ 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;
+ }
+ return false;
+}
+
+bool ConnectionImpl::resetSessions()
+{
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ getImplPtr(*i)->setSession(connection.newSession());
+ }
+ return true;
+ } catch (const TransportFailure&) {
+ QPID_LOG(debug, "Connection failed while re-inialising sessions");
+ return false;
+ }
+}
+
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
index 120a8ab9d8..565f2ec7ec 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
@@ -23,20 +23,46 @@
*/
#include "qpid/messaging/ConnectionImpl.h"
#include "qpid/messaging/Variant.h"
+#include "qpid/Url.h"
#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Semaphore.h"
+#include <vector>
namespace qpid {
namespace client {
namespace amqp0_10 {
+class SessionImpl;
+
class ConnectionImpl : public qpid::messaging::ConnectionImpl
{
public:
ConnectionImpl(const std::string& url, const qpid::messaging::Variant::Map& options);
void close();
qpid::messaging::Session newSession();
+ void closed(SessionImpl&);
+ void reconnect();
private:
+ typedef std::vector<qpid::messaging::Session> Sessions;
+
+ qpid::sys::Mutex lock;//used to protect data structures
+ qpid::sys::Semaphore semaphore;//used to coordinate reconnection
qpid::client::Connection connection;
+ qpid::Url url;
+ qpid::client::ConnectionSettings settings;
+ Sessions sessions;
+ bool reconnectionEnabled;
+ int timeout;
+ int minRetryInterval;
+ int maxRetryInterval;
+
+ void connect(const qpid::sys::AbsTime& started);
+ bool tryConnect();
+ bool tryConnect(const std::vector<Url>& urls);
+ bool tryConnect(const Url&);
+ bool resetSessions();
};
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
index b69c1917e6..d22208368b 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
@@ -21,11 +21,13 @@
#include "qpid/client/amqp0_10/IncomingMessages.h"
#include "qpid/client/amqp0_10/AddressResolution.h"
#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
#include "qpid/client/SessionImpl.h"
#include "qpid/client/SessionBase_0_10Access.h"
#include "qpid/log/Statement.h"
#include "qpid/messaging/Address.h"
#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
#include "qpid/messaging/Variant.h"
#include "qpid/framing/DeliveryProperties.h"
#include "qpid/framing/FrameSet.h"
@@ -41,6 +43,7 @@ using namespace qpid::framing;
using namespace qpid::framing::message;
using qpid::sys::AbsTime;
using qpid::sys::Duration;
+using qpid::messaging::MessageImplAccess;
using qpid::messaging::Variant;
namespace {
@@ -78,11 +81,32 @@ struct MatchAndTrack
}
}
};
+
+struct Match
+{
+ const std::string destination;
+ uint32_t matched;
+
+ Match(const std::string& d) : destination(d), matched(0) {}
+
+ bool operator()(boost::shared_ptr<qpid::framing::FrameSet> command)
+ {
+ if (command->as<MessageTransferBody>()->getDestination() == destination) {
+ ++matched;
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
}
-IncomingMessages::IncomingMessages(qpid::client::AsyncSession s) :
- session(s),
- incoming(SessionBase_0_10Access(session).get()->getDemux().getDefault()) {}
+void IncomingMessages::setSession(qpid::client::AsyncSession s)
+{
+ session = s;
+ incoming = SessionBase_0_10Access(session).get()->getDemux().getDefault();
+ acceptTracker.reset();
+}
bool IncomingMessages::get(Handler& handler, Duration timeout)
{
@@ -101,8 +125,7 @@ bool IncomingMessages::get(Handler& handler, Duration timeout)
void IncomingMessages::accept()
{
- session.messageAccept(unaccepted);
- unaccepted.clear();
+ acceptTracker.accept(session);
}
void IncomingMessages::releaseAll()
@@ -116,8 +139,7 @@ void IncomingMessages::releaseAll()
GetAny handler;
while (process(&handler, 0)) ;
//now release all messages
- session.messageRelease(unaccepted);
- unaccepted.clear();
+ acceptTracker.release(session);
}
void IncomingMessages::releasePending(const std::string& destination)
@@ -161,6 +183,32 @@ bool IncomingMessages::process(Handler* handler, qpid::sys::Duration duration)
return false;
}
+uint32_t IncomingMessages::pendingAccept()
+{
+ return acceptTracker.acceptsPending();
+}
+uint32_t IncomingMessages::pendingAccept(const std::string& destination)
+{
+ return acceptTracker.acceptsPending(destination);
+}
+
+uint32_t IncomingMessages::available()
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) {}
+ //return the count of received messages
+ return received.size();
+}
+
+uint32_t IncomingMessages::available(const std::string& destination)
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) {}
+
+ //count all messages for this destination from received list
+ return std::for_each(received.begin(), received.end(), Match(destination)).matched;
+}
+
void populate(qpid::messaging::Message& message, FrameSet& command);
/**
@@ -175,7 +223,7 @@ void IncomingMessages::retrieve(FrameSetPtr command, qpid::messaging::Message* m
}
const MessageTransferBody* transfer = command->as<MessageTransferBody>();
if (transfer->getAcquireMode() == ACQUIRE_MODE_PRE_ACQUIRED && transfer->getAcceptMode() == ACCEPT_MODE_EXPLICIT) {
- unaccepted.add(command->getId());
+ acceptTracker.delivered(transfer->getDestination(), command->getId());
}
session.markCompleted(command->getId(), false, false);
}
@@ -191,8 +239,6 @@ void IncomingMessages::MessageTransfer::retrieve(qpid::messaging::Message* messa
parent.retrieve(content, message);
}
-void translate(const FieldTable& from, Variant::Map& to);//implemented in Codecs.cpp
-
void populateHeaders(qpid::messaging::Message& message,
const DeliveryProperties* deliveryProperties,
const MessageProperties* messageProperties)
@@ -206,6 +252,7 @@ void populateHeaders(qpid::messaging::Message& message,
if (messageProperties->hasReplyTo()) {
message.setReplyTo(AddressResolution::convert(messageProperties->getReplyTo()));
}
+ message.getHeaders().clear();
translate(messageProperties->getApplicationHeaders(), message.getHeaders());
//TODO: convert other message properties
}
@@ -219,9 +266,8 @@ void populateHeaders(qpid::messaging::Message& message, const AMQHeaderBody* hea
void populate(qpid::messaging::Message& message, FrameSet& command)
{
//need to be able to link the message back to the transfer it was delivered by
- //e.g. for rejecting. TODO: hide this from API
- uint32_t commandId = command.getId();
- message.setInternalId(reinterpret_cast<void*>(commandId));
+ //e.g. for rejecting.
+ MessageImplAccess::get(message).setInternalId(command.getId());
command.getContent(message.getBytes());
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
index c4346fd7d7..e84cd18892 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
@@ -27,6 +27,7 @@
#include "qpid/framing/SequenceSet.h"
#include "qpid/sys/BlockingQueue.h"
#include "qpid/sys/Time.h"
+#include "qpid/client/amqp0_10/AcceptTracker.h"
namespace qpid {
@@ -67,20 +68,26 @@ class IncomingMessages
virtual bool accept(MessageTransfer& transfer) = 0;
};
- IncomingMessages(qpid::client::AsyncSession session);
+ void setSession(qpid::client::AsyncSession session);
bool get(Handler& handler, qpid::sys::Duration timeout);
//bool get(qpid::messaging::Message& message, qpid::sys::Duration timeout);
//bool get(const std::string& destination, qpid::messaging::Message& message, qpid::sys::Duration timeout);
void accept();
void releaseAll();
void releasePending(const std::string& destination);
+
+ uint32_t pendingAccept();
+ uint32_t pendingAccept(const std::string& destination);
+
+ uint32_t available();
+ uint32_t available(const std::string& destination);
private:
typedef std::deque<FrameSetPtr> FrameSetQueue;
qpid::client::AsyncSession session;
- qpid::framing::SequenceSet unaccepted;
boost::shared_ptr< sys::BlockingQueue<FrameSetPtr> > incoming;
FrameSetQueue received;
+ AcceptTracker acceptTracker;
bool process(Handler*, qpid::sys::Duration);
void retrieve(FrameSetPtr, qpid::messaging::Message*);
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h b/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h
index 19d5e4ef82..d66d2ecb3c 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h
@@ -33,6 +33,8 @@ class Message;
namespace client {
namespace amqp0_10 {
+class OutgoingMessage;
+
/**
*
*/
@@ -41,7 +43,7 @@ class MessageSink
public:
virtual ~MessageSink() {}
virtual void declare(qpid::client::AsyncSession& session, const std::string& name) = 0;
- virtual void send(qpid::client::AsyncSession& session, const std::string& name, qpid::messaging::Message& message) = 0;
+ virtual void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message) = 0;
virtual void cancel(qpid::client::AsyncSession& session, const std::string& name) = 0;
private:
};
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
new file mode 100644
index 0000000000..716f955f98
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/OutgoingMessage.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Address;
+using qpid::messaging::MessageImplAccess;
+
+template <class T> void encode(const qpid::messaging::Message& from, qpid::client::Message& to)
+{
+ T codec;
+ MessageImplAccess::get(from).getEncodedContent(codec, to.getData());
+ to.getMessageProperties().setContentType(T::contentType);
+}
+
+void OutgoingMessage::convert(const qpid::messaging::Message& from)
+{
+ //TODO: need to avoid copying as much as possible
+ if (from.getContent().isList()) {
+ encode<ListCodec>(from, message);
+ } else if (from.getContent().isMap()) {
+ encode<MapCodec>(from, message);
+ } else {
+ message.setData(from.getBytes());
+ message.getMessageProperties().setContentType(from.getContentType());
+ }
+ const Address& address = from.getReplyTo();
+ if (!address.value.empty()) {
+ message.getMessageProperties().setReplyTo(AddressResolution::convert(address));
+ }
+ translate(from.getHeaders(), message.getMessageProperties().getApplicationHeaders());
+ //TODO: set other message properties
+ message.getDeliveryProperties().setRoutingKey(from.getSubject());
+ //TODO: set other delivery properties
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
index 52b623b65c..8801e4e769 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
@@ -1,3 +1,6 @@
+#ifndef QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+#define QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -18,31 +21,26 @@
* under the License.
*
*/
-#include "CompletionTracker.h"
+#include "qpid/client/Completion.h"
+#include "qpid/client/Message.h"
namespace qpid {
+namespace messaging {
+class Message;
+}
namespace client {
namespace amqp0_10 {
-using qpid::framing::SequenceNumber;
-
-void CompletionTracker::track(SequenceNumber command, void* token)
+struct OutgoingMessage
{
- tokens[command] = token;
-}
+ qpid::client::Message message;
+ qpid::client::Completion status;
+
+ void convert(const qpid::messaging::Message&);
+};
-void CompletionTracker::completedTo(SequenceNumber command)
-{
- Tokens::iterator i = tokens.lower_bound(command);
- if (i != tokens.end()) {
- lastCompleted = i->second;
- tokens.erase(tokens.begin(), ++i);
- }
-}
-void* CompletionTracker::getLastCompletedToken()
-{
- return lastCompleted;
-}
}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
index e6ed4bfc4e..da91c4a160 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
@@ -19,6 +19,7 @@
*
*/
#include "ReceiverImpl.h"
+#include "AddressResolution.h"
#include "MessageSource.h"
#include "SessionImpl.h"
#include "qpid/messaging/MessageListener.h"
@@ -38,11 +39,6 @@ void ReceiverImpl::received(qpid::messaging::Message&)
window = capacity;
}
}
-
-bool ReceiverImpl::get(qpid::messaging::Message& message, qpid::sys::Duration timeout)
-{
- return parent.get(*this, message, timeout);
-}
qpid::messaging::Message ReceiverImpl::get(qpid::sys::Duration timeout)
{
@@ -50,24 +46,6 @@ qpid::messaging::Message ReceiverImpl::get(qpid::sys::Duration timeout)
if (!get(result, timeout)) throw Receiver::NoMessageAvailable();
return result;
}
-
-bool ReceiverImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
-{
- if (capacity == 0 && !cancelled) {
- session.messageFlow(destination, CREDIT_UNIT_MESSAGE, 1);
- if (!started) session.messageFlow(destination, CREDIT_UNIT_BYTE, byteCredit);
- }
-
- if (get(message, timeout)) {
- return true;
- } else {
- if (!cancelled) {
- sync(session).messageFlush(destination);
- start();//reallocate credit
- }
- return get(message, 0);
- }
-}
qpid::messaging::Message ReceiverImpl::fetch(qpid::sys::Duration timeout)
{
@@ -76,71 +54,152 @@ qpid::messaging::Message ReceiverImpl::fetch(qpid::sys::Duration timeout)
return result;
}
+bool ReceiverImpl::get(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Get f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
+bool ReceiverImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Fetch f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
void ReceiverImpl::cancel()
{
- if (!cancelled) {
- //TODO: should syncronicity be an optional argument to this call?
- source->cancel(session, destination);
- //need to be sure cancel is complete and all incoming
- //framesets are processed before removing the receiver
- parent.receiverCancelled(destination);
- cancelled = true;
- }
+ execute<Cancel>();
}
void ReceiverImpl::start()
{
- if (!cancelled) {
- started = true;
- session.messageSetFlowMode(destination, capacity > 0);
+ execute<Start>();
+}
+
+void ReceiverImpl::stop()
+{
+ execute<Stop>();
+}
+
+void ReceiverImpl::setCapacity(uint32_t c)
+{
+ execute1<SetCapacity>(c);
+}
+
+void ReceiverImpl::startFlow()
+{
+ if (capacity > 0) {
+ session.messageSetFlowMode(destination, FLOW_MODE_WINDOW);
session.messageFlow(destination, CREDIT_UNIT_MESSAGE, capacity);
session.messageFlow(destination, CREDIT_UNIT_BYTE, byteCredit);
window = capacity;
}
}
-void ReceiverImpl::stop()
+void ReceiverImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
{
- session.messageStop(destination);
- started = false;
+
+ session = s;
+ if (state == UNRESOLVED) {
+ source = resolver.resolveSource(session, address, filter, options);
+ state = STOPPED;//TODO: if session is started, go straight to started
+ }
+ if (state == CANCELLED) {
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
+ } else {
+ source->subscribe(session, destination);
+ if (state == STARTED) start();
+ }
}
-void ReceiverImpl::subscribe()
+void ReceiverImpl::setListener(qpid::messaging::MessageListener* l) { listener = l; }
+qpid::messaging::MessageListener* ReceiverImpl::getListener() { return listener; }
+
+const std::string& ReceiverImpl::getName() const { return destination; }
+
+uint32_t ReceiverImpl::getCapacity()
+{
+ return capacity;
+}
+
+uint32_t ReceiverImpl::available()
+{
+ return parent.available(destination);
+}
+
+uint32_t ReceiverImpl::pendingAck()
{
- source->subscribe(session, destination);
+ return parent.pendingAck(destination);
}
-void ReceiverImpl::setSession(qpid::client::AsyncSession s)
+ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name,
+ const qpid::messaging::Address& a,
+ const qpid::messaging::Filter* f,
+ const qpid::messaging::Variant::Map& o) :
+
+ parent(p), destination(name), address(a), filter(f), options(o), byteCredit(0xFFFFFFFF),
+ state(UNRESOLVED), capacity(0), listener(0), window(0) {}
+
+bool ReceiverImpl::getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ return parent.get(*this, message, timeout);
+}
+
+bool ReceiverImpl::fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ if (state == CANCELLED) return false;//TODO: or should this be an error?
+
+ if (capacity == 0 || state != STARTED) {
+ session.messageSetFlowMode(destination, FLOW_MODE_CREDIT);
+ session.messageFlow(destination, CREDIT_UNIT_MESSAGE, 1);
+ session.messageFlow(destination, CREDIT_UNIT_BYTE, 0xFFFFFFFF);
+ }
+
+ if (getImpl(message, timeout)) {
+ return true;
+ } else {
+ sync(session).messageFlush(destination);
+ startFlow();//reallocate credit
+ return getImpl(message, 0);
+ }
+}
+
+void ReceiverImpl::cancelImpl()
{
- session = s;
- if (!cancelled) {
- subscribe();
- //if we were in started state before the session was changed,
- //start again on this new session
- //TODO: locking if receiver is to be threadsafe...
- if (started) start();
+ if (state != CANCELLED) {
+ state = CANCELLED;
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
}
}
-void ReceiverImpl::setCapacity(uint32_t c)
+void ReceiverImpl::startImpl()
+{
+ if (state == STOPPED) {
+ state = STARTED;
+ startFlow();
+ }
+}
+
+void ReceiverImpl::stopImpl()
+{
+ state = STOPPED;
+ session.messageStop(destination);
+}
+
+void ReceiverImpl::setCapacityImpl(uint32_t c)
{
if (c != capacity) {
capacity = c;
- if (!cancelled && started) {
- stop();
- start();
+ if (state == STARTED) {
+ session.messageStop(destination);
+ startFlow();
}
}
}
-void ReceiverImpl::setListener(qpid::messaging::MessageListener* l) { listener = l; }
-qpid::messaging::MessageListener* ReceiverImpl::getListener() { return listener; }
-
-const std::string& ReceiverImpl::getName() const { return destination; }
-
-ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name, std::auto_ptr<MessageSource> s) :
- parent(p), source(s), destination(name), byteCredit(0xFFFFFFFF),
- capacity(0), started(false), cancelled(false), listener(0), window(0) {}
-
}}} // 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 b549242d35..b941348fc8 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
@@ -21,9 +21,13 @@
* under the License.
*
*/
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Filter.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/ReceiverImpl.h"
+#include "qpid/messaging/Variant.h"
#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
#include "qpid/sys/Time.h"
#include <memory>
@@ -31,8 +35,8 @@ namespace qpid {
namespace client {
namespace amqp0_10 {
+class AddressResolution;
class MessageSource;
-class SessionImpl;
/**
* A receiver implementation based on an AMQP 0-10 subscription.
@@ -41,8 +45,14 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl
{
public:
- ReceiverImpl(SessionImpl& parent, const std::string& name, std::auto_ptr<MessageSource> source);
+ enum State {UNRESOLVED, STOPPED, STARTED, CANCELLED};
+ ReceiverImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Filter* filter,
+ const qpid::messaging::Variant::Map& options);
+
+ void init(qpid::client::AsyncSession session, AddressResolution& resolver);
bool get(qpid::messaging::Message& message, qpid::sys::Duration timeout);
qpid::messaging::Message get(qpid::sys::Duration timeout);
bool fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout);
@@ -50,25 +60,107 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl
void cancel();
void start();
void stop();
- void subscribe();
- void setSession(qpid::client::AsyncSession s);
const std::string& getName() const;
void setCapacity(uint32_t);
+ uint32_t getCapacity();
+ uint32_t available();
+ uint32_t pendingAck();
void setListener(qpid::messaging::MessageListener* listener);
qpid::messaging::MessageListener* getListener();
void received(qpid::messaging::Message& message);
private:
SessionImpl& parent;
- const std::auto_ptr<MessageSource> source;
const std::string destination;
+ const qpid::messaging::Address address;
+ const qpid::messaging::Filter* filter;
+ const qpid::messaging::Variant::Map options;
const uint32_t byteCredit;
-
+ State state;
+
+ std::auto_ptr<MessageSource> source;
uint32_t capacity;
qpid::client::AsyncSession session;
- bool started;
- bool cancelled;
qpid::messaging::MessageListener* listener;
uint32_t window;
+
+ void startFlow();
+ //implementation of public facing methods
+ bool fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ bool getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ void startImpl();
+ void stopImpl();
+ void cancelImpl();
+ void setCapacityImpl(uint32_t);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ ReceiverImpl& impl;
+
+ Command(ReceiverImpl& i) : impl(i) {}
+ };
+
+ struct Get : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Get(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.getImpl(message, timeout); }
+ };
+
+ struct Fetch : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Fetch(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.fetchImpl(message, timeout); }
+ };
+
+ struct Stop : Command
+ {
+ Stop(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.stopImpl(); }
+ };
+
+ struct Start : Command
+ {
+ Start(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.startImpl(); }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ struct SetCapacity : Command
+ {
+ uint32_t capacity;
+
+ SetCapacity(ReceiverImpl& i, uint32_t c) : Command(i), capacity(c) {}
+ void operator()() { impl.setCapacityImpl(capacity); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> void execute1(P p)
+ {
+ F f(*this, p);
+ parent.execute(f);
+ }
};
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
index ac36eb1537..4cd2dc0521 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -21,29 +21,113 @@
#include "SenderImpl.h"
#include "MessageSink.h"
#include "SessionImpl.h"
+#include "AddressResolution.h"
+#include "OutgoingMessage.h"
namespace qpid {
namespace client {
namespace amqp0_10 {
-SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name, std::auto_ptr<MessageSink> _sink) :
- parent(_parent), name(_name), sink(_sink) {}
+SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name,
+ const qpid::messaging::Address& _address,
+ const qpid::messaging::Variant::Map& _options) :
+ parent(_parent), name(_name), address(_address), options(_options), state(UNRESOLVED),
+ capacity(50), window(0), flushed(false) {}
-void SenderImpl::send(qpid::messaging::Message& m)
+void SenderImpl::send(const qpid::messaging::Message& message)
{
- sink->send(session, name, m);
+ Send f(*this, &message);
+ while (f.repeat) parent.execute(f);
}
void SenderImpl::cancel()
{
- sink->cancel(session, name);
- parent.senderCancelled(name);
+ execute<Cancel>();
+}
+
+void SenderImpl::setCapacity(uint32_t c)
+{
+ bool flush = c < capacity;
+ capacity = c;
+ execute1<CheckPendingSends>(flush);
}
+uint32_t SenderImpl::getCapacity() { return capacity; }
+uint32_t SenderImpl::pending()
+{
+ CheckPendingSends f(*this, false);
+ parent.execute(f);
+ return f.pending;
+}
-void SenderImpl::setSession(qpid::client::AsyncSession s)
+void SenderImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
{
session = s;
- sink->declare(session, name);
+ if (state == UNRESOLVED) {
+ sink = resolver.resolveSink(session, address, options);
+ state = ACTIVE;
+ }
+ if (state == CANCELLED) {
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
+ } else {
+ sink->declare(session, name);
+ replay();
+ }
+}
+
+void SenderImpl::waitForCapacity()
+{
+ //TODO: add option to throw exception rather than blocking?
+ if (capacity <= (flushed ? checkPendingSends(false) : outgoing.size())) {
+ //Initial implementation is very basic. As outgoing is
+ //currently only reduced on receiving completions and we are
+ //blocking anyway we may as well sync(). If successful that
+ //should clear all outstanding sends.
+ session.sync();
+ checkPendingSends(false);
+ }
+ //flush periodically and check for conmpleted sends
+ if (++window > (capacity / 4)) {//TODO: make this configurable?
+ checkPendingSends(true);
+ window = 0;
+ }
+}
+
+void SenderImpl::sendImpl(const qpid::messaging::Message& m)
+{
+ //TODO: make recording for replay optional (would still want to track completion however)
+ std::auto_ptr<OutgoingMessage> msg(new OutgoingMessage());
+ msg->convert(m);
+ outgoing.push_back(msg.release());
+ sink->send(session, name, outgoing.back());
+}
+
+void SenderImpl::replay()
+{
+ for (OutgoingMessages::iterator i = outgoing.begin(); i != outgoing.end(); ++i) {
+ sink->send(session, name, *i);
+ }
+}
+
+uint32_t SenderImpl::checkPendingSends(bool flush)
+{
+ if (flush) {
+ session.flush();
+ flushed = true;
+ } else {
+ flushed = false;
+ }
+ while (!outgoing.empty() && outgoing.front().status.isComplete()) {
+ outgoing.pop_front();
+ }
+ return outgoing.size();
+}
+
+void SenderImpl::cancelImpl()
+{
+ state = CANCELLED;
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
}
}}} // 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 e737450ba1..028d26bda7 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
@@ -21,17 +21,22 @@
* under the License.
*
*/
+#include "qpid/messaging/Address.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/SenderImpl.h"
+#include "qpid/messaging/Variant.h"
#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
#include <memory>
+#include <boost/ptr_container/ptr_deque.hpp>
namespace qpid {
namespace client {
namespace amqp0_10 {
+class AddressResolution;
class MessageSink;
-class SessionImpl;
+class OutgoingMessage;
/**
*
@@ -39,19 +44,96 @@ class SessionImpl;
class SenderImpl : public qpid::messaging::SenderImpl
{
public:
- SenderImpl(SessionImpl& parent, const std::string& name, std::auto_ptr<MessageSink> sink);
- void send(qpid::messaging::Message&);
+ enum State {UNRESOLVED, ACTIVE, CANCELLED};
+
+ SenderImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Variant::Map& options);
+ void send(const qpid::messaging::Message&);
void cancel();
- void setSession(qpid::client::AsyncSession);
+ void setCapacity(uint32_t);
+ uint32_t getCapacity();
+ uint32_t pending();
+ void init(qpid::client::AsyncSession, AddressResolution&);
private:
SessionImpl& parent;
const std::string name;
+ const qpid::messaging::Address address;
+ const qpid::messaging::Variant::Map options;
+ State state;
std::auto_ptr<MessageSink> sink;
qpid::client::AsyncSession session;
std::string destination;
std::string routingKey;
+
+ typedef boost::ptr_deque<OutgoingMessage> OutgoingMessages;
+ OutgoingMessages outgoing;
+ uint32_t capacity;
+ uint32_t window;
+ bool flushed;
+
+ uint32_t checkPendingSends(bool flush);
+ void replay();
+ void waitForCapacity();
+
+ //logic for application visible methods:
+ void sendImpl(const qpid::messaging::Message&);
+ void cancelImpl();
+
+
+ //functors for application visible methods (allowing locking and
+ //retry to be centralised):
+ struct Command
+ {
+ SenderImpl& impl;
+
+ Command(SenderImpl& i) : impl(i) {}
+ };
+
+ struct Send : Command
+ {
+ const qpid::messaging::Message* message;
+ bool repeat;
+
+ Send(SenderImpl& i, const qpid::messaging::Message* m) : Command(i), message(m), repeat(true) {}
+ void operator()()
+ {
+ impl.waitForCapacity();
+ //from this point message will be recorded if there is any
+ //failure (and replayed) so need not repeat the call
+ repeat = false;
+ impl.sendImpl(*message);
+ }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(SenderImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ struct CheckPendingSends : Command
+ {
+ bool flush;
+ uint32_t pending;
+ CheckPendingSends(SenderImpl& i, bool f) : Command(i), flush(f), pending(0) {}
+ void operator()() { pending = impl.checkPendingSends(flush); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> bool execute1(P p)
+ {
+ F f(*this, p);
+ 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 9ea2a9f598..bc6289d84b 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
@@ -19,6 +19,7 @@
*
*/
#include "qpid/client/amqp0_10/SessionImpl.h"
+#include "qpid/client/amqp0_10/ConnectionImpl.h"
#include "qpid/client/amqp0_10/ReceiverImpl.h"
#include "qpid/client/amqp0_10/SenderImpl.h"
#include "qpid/client/amqp0_10/MessageSource.h"
@@ -29,6 +30,7 @@
#include "qpid/messaging/Address.h"
#include "qpid/messaging/Filter.h"
#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
#include "qpid/messaging/MessageListener.h"
#include "qpid/messaging/Sender.h"
#include "qpid/messaging/Receiver.h"
@@ -39,6 +41,7 @@
#include <boost/intrusive_ptr.hpp>
using qpid::messaging::Filter;
+using qpid::messaging::MessageImplAccess;
using qpid::messaging::Sender;
using qpid::messaging::Receiver;
using qpid::messaging::VariantMap;
@@ -47,64 +50,55 @@ namespace qpid {
namespace client {
namespace amqp0_10 {
-SessionImpl::SessionImpl(qpid::client::Session s) : session(s), incoming(session) {}
+SessionImpl::SessionImpl(ConnectionImpl& c) : connection(c) {}
+void SessionImpl::sync()
+{
+ retry<Sync>();
+}
+
+void SessionImpl::flush()
+{
+ retry<Flush>();
+}
+
void SessionImpl::commit()
{
- qpid::sys::Mutex::ScopedLock l(lock);
- incoming.accept();
- session.txCommit();
+ if (!execute<Commit>()) {
+ throw Exception();//TODO: what type?
+ }
}
void SessionImpl::rollback()
{
- qpid::sys::Mutex::ScopedLock l(lock);
- for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.stop();
- //ensure that stop has been processed and all previously sent
- //messages are available for release:
- session.sync();
- incoming.releaseAll();
- session.txRollback();
- for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.start();
+ //If the session fails during this operation, the transaction will
+ //be rolled back anyway.
+ execute<Rollback>();
}
void SessionImpl::acknowledge()
{
- qpid::sys::Mutex::ScopedLock l(lock);
- incoming.accept();
+ //Should probably throw an exception on failure here, or indicate
+ //it through a return type at least. Failure means that the
+ //message may be redelivered; i.e. the application cannot delete
+ //any state necessary for preventing reprocessing of the message
+ execute<Acknowledge>();
}
void SessionImpl::reject(qpid::messaging::Message& m)
{
- qpid::sys::Mutex::ScopedLock l(lock);
- //TODO: how do I get the id of the original transfer command? think this through some more...
-
- // [tross] The following hack was added to get this code to compile on a 64-bit machine.
- // It should be functionally equivalent to the original on a 32-bit architecture
- // but is almost certainly not what was intended by the author.
- uint64_t rawId(reinterpret_cast<uint64_t>(m.getInternalId()));
- SequenceNumber id((uint32_t) ((rawId & 0xFFFFFFFF) ^ ((rawId >> 32) & 0xFFFFFFFF)));
-
- SequenceSet set;
- set.add(id);
- session.messageReject(set);
+ //Possibly want to somehow indicate failure here as well. Less
+ //clear need as compared to acknowledge however.
+ execute1<Reject>(m);
}
void SessionImpl::close()
{
+ connection.closed(*this);
session.close();
}
-void translate(const VariantMap& options, SubscriptionSettings& settings)
-{
- //TODO: fill this out
- VariantMap::const_iterator i = options.find("auto_acknowledge");
- if (i != options.end()) {
- settings.autoAck = i->second.asInt32();
- }
-}
-
template <class T, class S> boost::intrusive_ptr<S> getImplPtr(T& t)
{
return boost::dynamic_pointer_cast<S>(qpid::client::PrivateImplRef<T>::get(t));
@@ -120,38 +114,88 @@ template <class T> void getFreeKey(std::string& key, T& map)
key = name;
}
-Sender SessionImpl::createSender(const qpid::messaging::Address& address, const VariantMap& options)
-{
+
+void SessionImpl::setSession(qpid::client::Session s)
+{
qpid::sys::Mutex::ScopedLock l(lock);
- std::auto_ptr<MessageSink> sink = resolver.resolveSink(session, address, options);
- std::string name = address;
- getFreeKey(name, senders);
- Sender sender(new SenderImpl(*this, name, sink));
- getImplPtr<Sender, SenderImpl>(sender)->setSession(session);
- senders[name] = sender;
- return sender;
+ session = s;
+ incoming.setSession(session);
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) {
+ getImplPtr<Receiver, ReceiverImpl>(i->second)->init(session, resolver);
+ }
+ for (Senders::iterator i = senders.begin(); i != senders.end(); ++i) {
+ getImplPtr<Sender, SenderImpl>(i->second)->init(session, resolver);
+ }
}
+
+struct SessionImpl::CreateReceiver : Command
+{
+ qpid::messaging::Receiver result;
+ const qpid::messaging::Address& address;
+ const Filter* filter;
+ const qpid::messaging::Variant::Map& options;
+
+ CreateReceiver(SessionImpl& i, const qpid::messaging::Address& a, const Filter* f,
+ const qpid::messaging::Variant::Map& o) :
+ Command(i), address(a), filter(f), options(o) {}
+ void operator()() { result = impl.createReceiverImpl(address, filter, options); }
+};
+
Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address, const VariantMap& options)
{
- return addReceiver(address, 0, options);
+ CreateReceiver f(*this, address, 0, options);
+ while (!execute(f)) {}
+ return f.result;
}
-Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address, const Filter& filter, const VariantMap& options)
+
+Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address,
+ const Filter& filter, const VariantMap& options)
{
- return addReceiver(address, &filter, options);
+ CreateReceiver f(*this, address, &filter, options);
+ while (!execute(f)) {}
+ return f.result;
}
-Receiver SessionImpl::addReceiver(const qpid::messaging::Address& address, const Filter* filter, const VariantMap& options)
+Receiver SessionImpl::createReceiverImpl(const qpid::messaging::Address& address,
+ const Filter* filter, const VariantMap& options)
{
- qpid::sys::Mutex::ScopedLock l(lock);
- std::auto_ptr<MessageSource> source = resolver.resolveSource(session, address, filter, options);
std::string name = address;
getFreeKey(name, receivers);
- Receiver receiver(new ReceiverImpl(*this, name, source));
- getImplPtr<Receiver, ReceiverImpl>(receiver)->setSession(session);
+ Receiver receiver(new ReceiverImpl(*this, name, address, filter, options));
+ getImplPtr<Receiver, ReceiverImpl>(receiver)->init(session, resolver);
receivers[name] = receiver;
return receiver;
}
+struct SessionImpl::CreateSender : Command
+{
+ qpid::messaging::Sender result;
+ const qpid::messaging::Address& address;
+ const qpid::messaging::Variant::Map& options;
+
+ CreateSender(SessionImpl& i, const qpid::messaging::Address& a,
+ const qpid::messaging::Variant::Map& o) :
+ Command(i), address(a), options(o) {}
+ void operator()() { result = impl.createSenderImpl(address, options); }
+};
+
+Sender SessionImpl::createSender(const qpid::messaging::Address& address, const VariantMap& options)
+{
+ CreateSender f(*this, address, options);
+ while (!execute(f)) {}
+ return f.result;
+}
+
+Sender SessionImpl::createSenderImpl(const qpid::messaging::Address& address, const VariantMap& options)
+{
+ std::string name = address;
+ getFreeKey(name, senders);
+ Sender sender(new SenderImpl(*this, name, address, options));
+ getImplPtr<Sender, SenderImpl>(sender)->init(session, resolver);
+ senders[name] = sender;
+ return sender;
+}
+
qpid::messaging::Address SessionImpl::createTempQueue(const std::string& baseName)
{
std::string name = baseName + std::string("_") + session.getId().getName();
@@ -218,27 +262,135 @@ bool SessionImpl::acceptAny(qpid::messaging::Message* message, bool isDispatch,
bool SessionImpl::getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout)
{
- qpid::sys::Mutex::ScopedLock l(lock);
return incoming.get(handler, timeout);
}
-bool SessionImpl::dispatch(qpid::sys::Duration timeout)
+bool SessionImpl::get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout)
{
- qpid::messaging::Message message;
- IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, true, _1));
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::accept, this, &receiver, &message, false, _1));
return getIncoming(handler, timeout);
}
-bool SessionImpl::get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout)
+bool SessionImpl::dispatch(qpid::sys::Duration timeout)
{
- IncomingMessageHandler handler(boost::bind(&SessionImpl::accept, this, &receiver, &message, false, _1));
- return getIncoming(handler, timeout);
+ qpid::sys::Mutex::ScopedLock l(lock);
+ while (true) {
+ try {
+ qpid::messaging::Message message;
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, true, _1));
+ return getIncoming(handler, timeout);
+ } catch (TransportFailure&) {
+ reconnect();
+ }
+ }
}
bool SessionImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
{
- IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, false, _1));
- return getIncoming(handler, timeout);
+ qpid::sys::Mutex::ScopedLock l(lock);
+ while (true) {
+ try {
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, false, _1));
+ return getIncoming(handler, timeout);
+ } catch (TransportFailure&) {
+ reconnect();
+ }
+ }
+}
+
+uint32_t SessionImpl::available()
+{
+ return get1<Available, uint32_t>((const std::string*) 0);
+}
+uint32_t SessionImpl::available(const std::string& destination)
+{
+ return get1<Available, uint32_t>(&destination);
+}
+
+struct SessionImpl::Available : Command
+{
+ const std::string* destination;
+ uint32_t result;
+
+ Available(SessionImpl& i, const std::string* d) : Command(i), destination(d), result(0) {}
+ void operator()() { result = impl.availableImpl(destination); }
+};
+
+uint32_t SessionImpl::availableImpl(const std::string* destination)
+{
+ if (destination) {
+ return incoming.available(*destination);
+ } else {
+ return incoming.available();
+ }
+}
+
+uint32_t SessionImpl::pendingAck()
+{
+ return get1<PendingAck, uint32_t>((const std::string*) 0);
+}
+
+uint32_t SessionImpl::pendingAck(const std::string& destination)
+{
+ return get1<PendingAck, uint32_t>(&destination);
+}
+
+struct SessionImpl::PendingAck : Command
+{
+ const std::string* destination;
+ uint32_t result;
+
+ PendingAck(SessionImpl& i, const std::string* d) : Command(i), destination(d), result(0) {}
+ void operator()() { result = impl.pendingAckImpl(destination); }
+};
+
+uint32_t SessionImpl::pendingAckImpl(const std::string* destination)
+{
+ if (destination) {
+ return incoming.pendingAccept(*destination);
+ } else {
+ return incoming.pendingAccept();
+ }
+}
+
+void SessionImpl::syncImpl()
+{
+ session.sync();
+}
+
+void SessionImpl::flushImpl()
+{
+ session.flush();
+}
+
+
+void SessionImpl::commitImpl()
+{
+ incoming.accept();
+ session.txCommit();
+}
+
+void SessionImpl::rollbackImpl()
+{
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.stop();
+ //ensure that stop has been processed and all previously sent
+ //messages are available for release:
+ session.sync();
+ incoming.releaseAll();
+ session.txRollback();
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.start();
+}
+
+void SessionImpl::acknowledgeImpl()
+{
+ incoming.accept();
+}
+
+void SessionImpl::rejectImpl(qpid::messaging::Message& m)
+{
+ SequenceSet set;
+ set.add(MessageImplAccess::get(m).getInternalId());
+ session.messageReject(set);
}
qpid::messaging::Message SessionImpl::fetch(qpid::sys::Duration timeout)
@@ -250,28 +402,19 @@ qpid::messaging::Message SessionImpl::fetch(qpid::sys::Duration timeout)
void SessionImpl::receiverCancelled(const std::string& name)
{
- {
- qpid::sys::Mutex::ScopedLock l(lock);
- receivers.erase(name);
- }
+ receivers.erase(name);
session.sync();
incoming.releasePending(name);
}
void SessionImpl::senderCancelled(const std::string& name)
{
- qpid::sys::Mutex::ScopedLock l(lock);
senders.erase(name);
}
-void SessionImpl::sync()
+void SessionImpl::reconnect()
{
- session.sync();
-}
-
-void SessionImpl::flush()
-{
- session.flush();
+ connection.reconnect();
}
void* SessionImpl::getLastConfirmedSent()
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
index 6926fb0235..b453f3f08f 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
@@ -32,8 +32,8 @@
namespace qpid {
namespace messaging {
-class Address;
-class Filter;
+struct Address;
+struct Filter;
class Message;
class Receiver;
class Sender;
@@ -43,6 +43,7 @@ class Session;
namespace client {
namespace amqp0_10 {
+class ConnectionImpl;
class ReceiverImpl;
class SenderImpl;
@@ -53,7 +54,7 @@ class SenderImpl;
class SessionImpl : public qpid::messaging::SessionImpl
{
public:
- SessionImpl(qpid::client::Session);
+ SessionImpl(ConnectionImpl&);
void commit();
void rollback();
void acknowledge();
@@ -81,26 +82,137 @@ class SessionImpl : public qpid::messaging::SessionImpl
void receiverCancelled(const std::string& name);
void senderCancelled(const std::string& name);
-
+
+ uint32_t available();
+ uint32_t available(const std::string& destination);
+
+ uint32_t pendingAck();
+ uint32_t pendingAck(const std::string& destination);
+
+ void setSession(qpid::client::Session);
+
+ template <class T> bool execute(T& f)
+ {
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ f();
+ return true;
+ } catch (TransportFailure&) {
+ reconnect();
+ return false;
+ }
+ }
+
static SessionImpl& convert(qpid::messaging::Session&);
- qpid::client::Session session;
private:
typedef std::map<std::string, qpid::messaging::Receiver> Receivers;
typedef std::map<std::string, qpid::messaging::Sender> Senders;
qpid::sys::Mutex lock;
+ ConnectionImpl& connection;
+ qpid::client::Session session;
AddressResolution resolver;
IncomingMessages incoming;
Receivers receivers;
Senders senders;
- qpid::messaging::Receiver addReceiver(const qpid::messaging::Address& address,
- const qpid::messaging::Filter* filter,
- const qpid::messaging::VariantMap& options);
bool acceptAny(qpid::messaging::Message*, bool, IncomingMessages::MessageTransfer&);
bool accept(ReceiverImpl*, qpid::messaging::Message*, bool, IncomingMessages::MessageTransfer&);
bool getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout);
+ void reconnect();
+
+ void commitImpl();
+ void rollbackImpl();
+ void acknowledgeImpl();
+ void rejectImpl(qpid::messaging::Message&);
+ void closeImpl();
+ void syncImpl();
+ void flushImpl();
+ qpid::messaging::Sender createSenderImpl(const qpid::messaging::Address& address,
+ const qpid::messaging::VariantMap& options);
+ qpid::messaging::Receiver createReceiverImpl(const qpid::messaging::Address& address,
+ const qpid::messaging::Filter* filter,
+ const qpid::messaging::VariantMap& options);
+ uint32_t availableImpl(const std::string* destination);
+ uint32_t pendingAckImpl(const std::string* destination);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ SessionImpl& impl;
+
+ Command(SessionImpl& i) : impl(i) {}
+ };
+
+ struct Commit : Command
+ {
+ Commit(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.commitImpl(); }
+ };
+
+ struct Rollback : Command
+ {
+ Rollback(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.rollbackImpl(); }
+ };
+
+ struct Acknowledge : Command
+ {
+ Acknowledge(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.acknowledgeImpl(); }
+ };
+
+ struct Sync : Command
+ {
+ Sync(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.syncImpl(); }
+ };
+
+ struct Flush : Command
+ {
+ Flush(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.flushImpl(); }
+ };
+
+ struct Reject : Command
+ {
+ qpid::messaging::Message& message;
+
+ Reject(SessionImpl& i, qpid::messaging::Message& m) : Command(i), message(m) {}
+ void operator()() { impl.rejectImpl(message); }
+ };
+
+ struct CreateSender;
+ struct CreateReceiver;
+ struct PendingAck;
+ struct Available;
+
+ //helper templates for some common patterns
+ template <class F> bool execute()
+ {
+ F f(*this);
+ return execute(f);
+ }
+
+ template <class F> void retry()
+ {
+ while (!execute<F>()) {}
+ }
+
+ template <class F, class P> bool execute1(P p)
+ {
+ F f(*this, p);
+ return execute(f);
+ }
+
+ template <class F, class R, class P> R get1(P p)
+ {
+ F f(*this, p);
+ while (!execute(f)) {}
+ return f.result;
+ }
};
}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/cluster/Connection.cpp b/qpid/cpp/src/qpid/cluster/Connection.cpp
index 4cc977d14a..6873827b81 100644
--- a/qpid/cpp/src/qpid/cluster/Connection.cpp
+++ b/qpid/cpp/src/qpid/cluster/Connection.cpp
@@ -156,8 +156,17 @@ bool Connection::checkUnsupported(const AMQBody& body) {
return !message.empty();
}
+struct GiveReadCreditOnExit {
+ Connection& connection;
+ int credit;
+ GiveReadCreditOnExit(Connection& connection_, int credit_) :
+ connection(connection_), credit(credit_) {}
+ ~GiveReadCreditOnExit() { connection.giveReadCredit(credit); }
+};
+
// Called in delivery thread, in cluster order.
void Connection::deliveredFrame(const EventFrame& f) {
+ GiveReadCreditOnExit gc(*this, f.readCredit);
assert(!catchUp);
currentChannel = f.frame.getChannel();
if (f.frame.getBody() // frame can be emtpy with just readCredit
@@ -171,7 +180,6 @@ void Connection::deliveredFrame(const EventFrame& f) {
if (ss) ss->out(const_cast<AMQFrame&>(f.frame));
}
}
- giveReadCredit(f.readCredit);
}
// A local connection is closed by the network layer.
diff --git a/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp b/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp
index 277adaf7b1..507d9649b9 100644
--- a/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp
+++ b/qpid/cpp/src/qpid/cluster/Quorum_cman.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,8 +33,8 @@ namespace {
boost::function<void()> errorFn;
-void cmanCallbackFn(cman_handle_t handle, void */*privdata*/, int reason, int arg) {
- if (reason == CMAN_REASON_STATECHANGE && arg == 0) {
+void cmanCallbackFn(cman_handle_t handle, void */*privdata*/, int reason, int /*arg*/) {
+ if (reason == CMAN_REASON_STATECHANGE && !cman_is_quorate(handle)) {
QPID_LOG(critical, "Lost contact with cluster quorum.");
if (errorFn) errorFn();
cman_stop_notification(handle);
diff --git a/qpid/cpp/src/qpid/framing/Uuid.cpp b/qpid/cpp/src/qpid/framing/Uuid.cpp
index c0b41c6906..71fa6a7329 100644
--- a/qpid/cpp/src/qpid/framing/Uuid.cpp
+++ b/qpid/cpp/src/qpid/framing/Uuid.cpp
@@ -17,6 +17,8 @@
*/
#include "qpid/framing/Uuid.h"
+
+#include "qpid/sys/uuid.h"
#include "qpid/Exception.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/reply_exceptions.h"
@@ -28,6 +30,35 @@ using namespace std;
static const size_t UNPARSED_SIZE=36;
+Uuid::Uuid(bool unique) {
+ if (unique) {
+ generate();
+ } else {
+ clear();
+ }
+}
+
+Uuid::Uuid(const uint8_t* data) {
+ assign(data);
+}
+
+void Uuid::assign(const uint8_t* data) {
+ uuid_copy(c_array(), data);
+}
+
+void Uuid::generate() {
+ uuid_generate(c_array());
+}
+
+void Uuid::clear() {
+ uuid_clear(c_array());
+}
+
+// Force int 0/!0 to false/true; avoids compile warnings.
+bool Uuid::isNull() {
+ return !!uuid_is_null(data());
+}
+
void Uuid::encode(Buffer& buf) const {
buf.putRawData(data(), size());
}
diff --git a/qpid/cpp/src/qpid/management/Manageable.cpp b/qpid/cpp/src/qpid/management/Manageable.cpp
index e487dfc455..a3593e73e3 100644
--- a/qpid/cpp/src/qpid/management/Manageable.cpp
+++ b/qpid/cpp/src/qpid/management/Manageable.cpp
@@ -33,7 +33,7 @@ string Manageable::StatusText (status_t status, string text)
case STATUS_UNKNOWN_OBJECT : return "UnknownObject";
case STATUS_UNKNOWN_METHOD : return "UnknownMethod";
case STATUS_NOT_IMPLEMENTED : return "NotImplemented";
- case STATUS_INVALID_PARAMETER : return "InvalidParameter";
+ case STATUS_PARAMETER_INVALID : return "InvalidParameter";
case STATUS_FEATURE_NOT_IMPLEMENTED : return "FeatureNotImplemented";
case STATUS_FORBIDDEN : return "Forbidden";
}
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index 2df10b1e95..0e462342d4 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -535,8 +535,8 @@ void ManagementAgent::handleMethodRequestLH (Buffer& inBuffer, string replyToKey
} else {
if ((iter->second->getPackageName() != packageName) ||
(iter->second->getClassName() != className)) {
- outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
- outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
}
else
try {
diff --git a/qpid/cpp/src/qpid/messaging/Address.cpp b/qpid/cpp/src/qpid/messaging/Address.cpp
index ed35054a00..813a8e1377 100644
--- a/qpid/cpp/src/qpid/messaging/Address.cpp
+++ b/qpid/cpp/src/qpid/messaging/Address.cpp
@@ -21,9 +21,6 @@
#include "qpid/messaging/Address.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
Address::Address() {}
diff --git a/qpid/cpp/src/qpid/messaging/Message.cpp b/qpid/cpp/src/qpid/messaging/Message.cpp
index e95a05db17..1d844b3027 100644
--- a/qpid/cpp/src/qpid/messaging/Message.cpp
+++ b/qpid/cpp/src/qpid/messaging/Message.cpp
@@ -19,263 +19,11 @@
*
*/
#include "qpid/messaging/Message.h"
-#include "qpid/messaging/Address.h"
-#include "qpid/messaging/Codec.h"
-#include "qpid/messaging/MessageContent.h"
-#include "qpid/messaging/Variant.h"
+#include "qpid/messaging/MessageImpl.h"
namespace qpid {
-namespace client {
-}
-
namespace messaging {
-namespace {
-const std::string EMPTY_STRING = "";
-}
-
-struct MessageImpl : MessageContent
-{
- Address replyTo;
- std::string subject;
- std::string contentType;
- VariantMap headers;
-
- std::string bytes;
- Variant content;//used only for LIST and MAP
- VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value
-
- void* internalId;
-
- MessageImpl(const std::string& c);
- MessageImpl(const char* chars, size_t count);
-
- void setReplyTo(const Address& d);
- const Address& getReplyTo() const;
-
- void setSubject(const std::string& s);
- const std::string& getSubject() const;
-
- void setContentType(const std::string& s);
- const std::string& getContentType() const;
-
- const VariantMap& getHeaders() const;
- VariantMap& getHeaders();
-
- void setBytes(const std::string& bytes);
- void setBytes(const char* chars, size_t count);
- const std::string& getBytes() const;
- std::string& getBytes();
-
- void setInternalId(void*);
- void* getInternalId();
-
- bool isVoid() const;
-
- const std::string& asString() const;
- std::string& asString();
-
- const char* asChars() const;
- size_t size() const;
-
- const Variant::Map& asMap() const;
- Variant::Map& asMap();
- bool isMap() const;
-
- const Variant::List& asList() const;
- Variant::List& asList();
- bool isList() const;
-
- void clear();
-
- void encode(Codec& codec);
- void decode(Codec& codec);
-
- Variant& operator[](const std::string&);
-
- std::ostream& print(std::ostream& out) const;
-
- //operator<< for variety of types...
- MessageContent& operator<<(const std::string&);
- MessageContent& operator<<(const char*);
- MessageContent& operator<<(bool);
- MessageContent& operator<<(int8_t);
- MessageContent& operator<<(int16_t);
- MessageContent& operator<<(int32_t);
- MessageContent& operator<<(int64_t);
- MessageContent& operator<<(uint8_t);
- MessageContent& operator<<(uint16_t);
- MessageContent& operator<<(uint32_t);
- MessageContent& operator<<(uint64_t);
- MessageContent& operator<<(double);
- MessageContent& operator<<(float);
-
- //assignment from string, map and list
- MessageContent& operator=(const std::string&);
- MessageContent& operator=(const char*);
- MessageContent& operator=(const Variant::Map&);
- MessageContent& operator=(const Variant::List&);
-
- template <class T> MessageContent& append(T& t);
-};
-
-MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VOID), internalId(0) {}
-MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VOID), internalId(0) {}
-
-void MessageImpl::setReplyTo(const Address& d) { replyTo = d; }
-const Address& MessageImpl::getReplyTo() const { return replyTo; }
-
-void MessageImpl::setSubject(const std::string& s) { subject = s; }
-const std::string& MessageImpl::getSubject() const { return subject; }
-
-void MessageImpl::setContentType(const std::string& s) { contentType = s; }
-const std::string& MessageImpl::getContentType() const { return contentType; }
-
-const VariantMap& MessageImpl::getHeaders() const { return headers; }
-VariantMap& MessageImpl::getHeaders() { return headers; }
-
-//should these methods be on MessageContent?
-void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; }
-void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); }
-const std::string& MessageImpl::getBytes() const { return bytes; }
-std::string& MessageImpl::getBytes() { return bytes; }
-
-
-Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; }
-
-std::ostream& MessageImpl::print(std::ostream& out) const
-{
- if (type == MAP) {
- return out << content.asMap();
- } else if (type == LIST) {
- return out << content.asList();
- } else {
- return out << bytes;
- }
-}
-
-template <class T> MessageContent& MessageImpl::append(T& t)
-{
- if (type == VOID) {
- //TODO: this is inefficient, probably want to hold on to the stream object
- std::stringstream s;
- s << bytes;
- s << t;
- bytes = s.str();
- } else if (type == LIST) {
- content.asList().push_back(Variant(t));
- } else {
- throw InvalidConversion("<< operator only valid on strings and lists");
- }
- return *this;
-}
-
-MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); }
-MessageContent& MessageImpl::operator<<(const char* v) { return append(v); }
-MessageContent& MessageImpl::operator<<(bool v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); }
-MessageContent& MessageImpl::operator<<(double v) { return append(v); }
-MessageContent& MessageImpl::operator<<(float v) { return append(v); }
-MessageContent& MessageImpl::operator=(const std::string& s)
-{
- type = VOID;
- bytes = s;
- return *this;
-}
-MessageContent& MessageImpl::operator=(const char* c)
-{
- type = VOID;
- bytes = c;
- return *this;
-}
-MessageContent& MessageImpl::operator=(const Variant::Map& m)
-{
- type = MAP;
- content = m;
- return *this;
-}
-
-MessageContent& MessageImpl::operator=(const Variant::List& l)
-{
- type = LIST;
- content = l;
- return *this;
-}
-
-void MessageImpl::encode(Codec& codec)
-{
- if (content.getType() != VOID) {
- bytes = EMPTY_STRING;
- codec.encode(content, bytes);
- }
-}
-
-void MessageImpl::decode(Codec& codec)
-{
- codec.decode(bytes, content);
- if (content.getType() == MAP) type = MAP;
- else if (content.getType() == LIST) type = LIST;
- else type = VOID;//TODO: what if codec set some type other than map or list??
-}
-
-void MessageImpl::setInternalId(void* i) { internalId = i; }
-void* MessageImpl::getInternalId() { return internalId; }
-
-bool MessageImpl::isVoid() const { return type == VOID; }
-
-const std::string& MessageImpl::asString() const
-{
- if (isVoid()) return getBytes();
- else return content.getString();//will throw an error
-}
-std::string& MessageImpl::asString()
-{
- if (isVoid()) return getBytes();
- else return content.getString();//will throw an error
-}
-
-const char* MessageImpl::asChars() const
-{
- if (!isVoid()) throw InvalidConversion("Content is of structured type.");
- return bytes.data();
-}
-size_t MessageImpl::size() const
-{
- return bytes.size();
-}
-
-const Variant::Map& MessageImpl::asMap() const { return content.asMap(); }
-Variant::Map& MessageImpl::asMap()
-{
- if (isVoid()) {
- content = Variant::Map();
- type = MAP;
- }
- return content.asMap();
-}
-bool MessageImpl::isMap() const { return type == MAP; }
-
-const Variant::List& MessageImpl::asList() const { return content.asList(); }
-Variant::List& MessageImpl::asList()
-{
- if (isVoid()) {
- content = Variant::List();
- type = LIST;
- }
- return content.asList();
-}
-bool MessageImpl::isList() const { return type == LIST; }
-
-void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VOID; }
-
-
Message::Message(const std::string& bytes) : impl(new MessageImpl(bytes)) {}
Message::Message(const char* bytes, size_t count) : impl(new MessageImpl(bytes, count)) {}
@@ -314,9 +62,6 @@ void Message::encode(Codec& codec) { impl->encode(codec); }
void Message::decode(Codec& codec) { impl->decode(codec); }
-void Message::setInternalId(void* i) { impl->setInternalId(i); }
-void* Message::getInternalId() { return impl->getInternalId(); }
-
std::ostream& operator<<(std::ostream& out, const MessageContent& content)
{
return content.print(out);
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
new file mode 100644
index 0000000000..5df9218e03
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "MessageImpl.h"
+#include "qpid/messaging/Message.h"
+
+namespace qpid {
+namespace messaging {
+
+namespace {
+const std::string EMPTY_STRING = "";
+}
+
+MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VAR_VOID), internalId(0) {}
+MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VAR_VOID), internalId(0) {}
+
+void MessageImpl::setReplyTo(const Address& d) { replyTo = d; }
+const Address& MessageImpl::getReplyTo() const { return replyTo; }
+
+void MessageImpl::setSubject(const std::string& s) { subject = s; }
+const std::string& MessageImpl::getSubject() const { return subject; }
+
+void MessageImpl::setContentType(const std::string& s) { contentType = s; }
+const std::string& MessageImpl::getContentType() const { return contentType; }
+
+const VariantMap& MessageImpl::getHeaders() const { return headers; }
+VariantMap& MessageImpl::getHeaders() { return headers; }
+
+//should these methods be on MessageContent?
+void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; }
+void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); }
+const std::string& MessageImpl::getBytes() const { return bytes; }
+std::string& MessageImpl::getBytes() { return bytes; }
+
+
+Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; }
+
+std::ostream& MessageImpl::print(std::ostream& out) const
+{
+ if (type == VAR_MAP) {
+ return out << content.asMap();
+ } else if (type == VAR_LIST) {
+ return out << content.asList();
+ } else {
+ return out << bytes;
+ }
+}
+
+template <class T> MessageContent& MessageImpl::append(T& t)
+{
+ if (type == VAR_VOID) {
+ //TODO: this is inefficient, probably want to hold on to the stream object
+ std::stringstream s;
+ s << bytes;
+ s << t;
+ bytes = s.str();
+ } else if (type == VAR_LIST) {
+ content.asList().push_back(Variant(t));
+ } else {
+ throw InvalidConversion("<< operator only valid on strings and lists");
+ }
+ return *this;
+}
+
+MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); }
+MessageContent& MessageImpl::operator<<(const char* v) { return append(v); }
+MessageContent& MessageImpl::operator<<(bool v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(double v) { return append(v); }
+MessageContent& MessageImpl::operator<<(float v) { return append(v); }
+MessageContent& MessageImpl::operator=(const std::string& s)
+{
+ type = VAR_VOID;
+ bytes = s;
+ return *this;
+}
+MessageContent& MessageImpl::operator=(const char* c)
+{
+ type = VAR_VOID;
+ bytes = c;
+ return *this;
+}
+MessageContent& MessageImpl::operator=(const Variant::Map& m)
+{
+ type = VAR_MAP;
+ content = m;
+ return *this;
+}
+
+MessageContent& MessageImpl::operator=(const Variant::List& l)
+{
+ type = VAR_LIST;
+ content = l;
+ return *this;
+}
+
+void MessageImpl::encode(Codec& codec)
+{
+ if (content.getType() != VAR_VOID) {
+ bytes = EMPTY_STRING;
+ codec.encode(content, bytes);
+ }
+}
+
+void MessageImpl::getEncodedContent(Codec& codec, std::string& out) const
+{
+ if (content.getType() != VAR_VOID) {
+ codec.encode(content, out);
+ } else {
+ out = bytes;
+ }
+}
+
+void MessageImpl::decode(Codec& codec)
+{
+ codec.decode(bytes, content);
+ if (content.getType() == VAR_MAP) type = VAR_MAP;
+ else if (content.getType() == VAR_LIST) type = VAR_LIST;
+ else type = VAR_VOID;//TODO: what if codec set some type other than map or list??
+}
+
+void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; }
+qpid::framing::SequenceNumber MessageImpl::getInternalId() { return internalId; }
+
+bool MessageImpl::isVoid() const { return type == VAR_VOID; }
+
+const std::string& MessageImpl::asString() const
+{
+ if (isVoid()) return getBytes();
+ else return content.getString();//will throw an error
+}
+std::string& MessageImpl::asString()
+{
+ if (isVoid()) return getBytes();
+ else return content.getString();//will throw an error
+}
+
+const char* MessageImpl::asChars() const
+{
+ if (!isVoid()) throw InvalidConversion("Content is of structured type.");
+ return bytes.data();
+}
+size_t MessageImpl::size() const
+{
+ return bytes.size();
+}
+
+const Variant::Map& MessageImpl::asMap() const { return content.asMap(); }
+Variant::Map& MessageImpl::asMap()
+{
+ if (isVoid()) {
+ content = Variant::Map();
+ type = VAR_MAP;
+ }
+ return content.asMap();
+}
+bool MessageImpl::isMap() const { return type == VAR_MAP; }
+
+const Variant::List& MessageImpl::asList() const { return content.asList(); }
+Variant::List& MessageImpl::asList()
+{
+ if (isVoid()) {
+ content = Variant::List();
+ type = VAR_LIST;
+ }
+ return content.asList();
+}
+bool MessageImpl::isList() const { return type == VAR_LIST; }
+
+void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VAR_VOID; }
+
+MessageImpl& MessageImplAccess::get(Message& msg)
+{
+ return *msg.impl;
+}
+const MessageImpl& MessageImplAccess::get(const Message& msg)
+{
+ return *msg.impl;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.h b/qpid/cpp/src/qpid/messaging/MessageImpl.h
new file mode 100644
index 0000000000..1173e7570a
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.h
@@ -0,0 +1,134 @@
+#ifndef QPID_MESSAGING_MESSAGEIMPL_H
+#define QPID_MESSAGING_MESSAGEIMPL_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/Address.h"
+#include "qpid/messaging/Codec.h"
+#include "qpid/messaging/MessageContent.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/SequenceNumber.h"
+
+namespace qpid {
+namespace messaging {
+
+struct MessageImpl : MessageContent
+{
+ Address replyTo;
+ std::string subject;
+ std::string contentType;
+ Variant::Map headers;
+
+ std::string bytes;
+ Variant content;//used only for LIST and MAP
+ VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value
+
+ qpid::framing::SequenceNumber internalId;
+
+ MessageImpl(const std::string& c);
+ MessageImpl(const char* chars, size_t count);
+
+ void setReplyTo(const Address& d);
+ const Address& getReplyTo() const;
+
+ void setSubject(const std::string& s);
+ const std::string& getSubject() const;
+
+ void setContentType(const std::string& s);
+ const std::string& getContentType() const;
+
+ const Variant::Map& getHeaders() const;
+ Variant::Map& getHeaders();
+
+ void setBytes(const std::string& bytes);
+ void setBytes(const char* chars, size_t count);
+ const std::string& getBytes() const;
+ std::string& getBytes();
+
+ void setInternalId(qpid::framing::SequenceNumber id);
+ qpid::framing::SequenceNumber getInternalId();
+
+ bool isVoid() const;
+
+ const std::string& asString() const;
+ std::string& asString();
+
+ const char* asChars() const;
+ size_t size() const;
+
+ const Variant::Map& asMap() const;
+ Variant::Map& asMap();
+ bool isMap() const;
+
+ const Variant::List& asList() const;
+ Variant::List& asList();
+ bool isList() const;
+
+ void clear();
+
+ void getEncodedContent(Codec& codec, std::string&) const;
+ void encode(Codec& codec);
+ void decode(Codec& codec);
+
+ Variant& operator[](const std::string&);
+
+ std::ostream& print(std::ostream& out) const;
+
+ //operator<< for variety of types...
+ MessageContent& operator<<(const std::string&);
+ MessageContent& operator<<(const char*);
+ MessageContent& operator<<(bool);
+ MessageContent& operator<<(int8_t);
+ MessageContent& operator<<(int16_t);
+ MessageContent& operator<<(int32_t);
+ MessageContent& operator<<(int64_t);
+ MessageContent& operator<<(uint8_t);
+ MessageContent& operator<<(uint16_t);
+ MessageContent& operator<<(uint32_t);
+ MessageContent& operator<<(uint64_t);
+ MessageContent& operator<<(double);
+ MessageContent& operator<<(float);
+
+ //assignment from string, map and list
+ MessageContent& operator=(const std::string&);
+ MessageContent& operator=(const char*);
+ MessageContent& operator=(const Variant::Map&);
+ MessageContent& operator=(const Variant::List&);
+
+ template <class T> MessageContent& append(T& t);
+};
+
+class Message;
+
+/**
+ * Provides access to the internal MessageImpl for a message which is
+ * useful when accessing any message state not exposed directly
+ * through the public API.
+ */
+struct MessageImplAccess
+{
+ static MessageImpl& get(Message&);
+ static const MessageImpl& get(const Message&);
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGEIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Receiver.cpp b/qpid/cpp/src/qpid/messaging/Receiver.cpp
index 2e8b89d27f..3290ea98ac 100644
--- a/qpid/cpp/src/qpid/messaging/Receiver.cpp
+++ b/qpid/cpp/src/qpid/messaging/Receiver.cpp
@@ -45,6 +45,9 @@ Message Receiver::fetch(qpid::sys::Duration timeout) { return impl->fetch(timeou
void Receiver::start() { impl->start(); }
void Receiver::stop() { impl->stop(); }
void Receiver::setCapacity(uint32_t c) { impl->setCapacity(c); }
+uint32_t Receiver::getCapacity() { return impl->getCapacity(); }
+uint32_t Receiver::available() { return impl->available(); }
+uint32_t Receiver::pendingAck() { return impl->pendingAck(); }
void Receiver::cancel() { impl->cancel(); }
void Receiver::setListener(MessageListener* listener) { impl->setListener(listener); }
diff --git a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
index 77697b730c..7db20acc29 100644
--- a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
@@ -44,6 +44,9 @@ class ReceiverImpl : public virtual qpid::RefCounted
virtual void start() = 0;
virtual void stop() = 0;
virtual void setCapacity(uint32_t) = 0;
+ virtual uint32_t getCapacity() = 0;
+ virtual uint32_t available() = 0;
+ virtual uint32_t pendingAck() = 0;
virtual void cancel() = 0;
virtual void setListener(MessageListener*) = 0;
};
diff --git a/qpid/cpp/src/qpid/messaging/Sender.cpp b/qpid/cpp/src/qpid/messaging/Sender.cpp
index 12a3a8eb0f..62b2944701 100644
--- a/qpid/cpp/src/qpid/messaging/Sender.cpp
+++ b/qpid/cpp/src/qpid/messaging/Sender.cpp
@@ -38,7 +38,10 @@ Sender::Sender(SenderImpl* impl) { PI::ctor(*this, impl); }
Sender::Sender(const Sender& s) : qpid::client::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(Message& message) { impl->send(message); }
+void Sender::send(const Message& message) { impl->send(message); }
void Sender::cancel() { impl->cancel(); }
+void Sender::setCapacity(uint32_t c) { impl->setCapacity(c); }
+uint32_t Sender::getCapacity() { return impl->getCapacity(); }
+uint32_t Sender::pending() { return impl->pending(); }
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/SenderImpl.h b/qpid/cpp/src/qpid/messaging/SenderImpl.h
index 3b61a37423..fa3794ca4e 100644
--- a/qpid/cpp/src/qpid/messaging/SenderImpl.h
+++ b/qpid/cpp/src/qpid/messaging/SenderImpl.h
@@ -35,8 +35,11 @@ class SenderImpl : public virtual qpid::RefCounted
{
public:
virtual ~SenderImpl() {}
- virtual void send(Message& message) = 0;
+ virtual void send(const Message& message) = 0;
virtual void cancel() = 0;
+ virtual void setCapacity(uint32_t) = 0;
+ virtual uint32_t getCapacity() = 0;
+ virtual uint32_t pending() = 0;
private:
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Session.cpp b/qpid/cpp/src/qpid/messaging/Session.cpp
index 284b20dacc..62b1ca0dcf 100644
--- a/qpid/cpp/src/qpid/messaging/Session.cpp
+++ b/qpid/cpp/src/qpid/messaging/Session.cpp
@@ -103,15 +103,7 @@ bool Session::dispatch(qpid::sys::Duration timeout)
{
return impl->dispatch(timeout);
}
-
-void* Session::getLastConfirmedSent()
-{
- return impl->getLastConfirmedSent();
-}
-
-void* Session::getLastConfirmedAcknowledged()
-{
- return impl->getLastConfirmedAcknowledged();
-}
+uint32_t Session::available() { return impl->available(); }
+uint32_t Session::pendingAck() { return impl->pendingAck(); }
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/SessionImpl.h b/qpid/cpp/src/qpid/messaging/SessionImpl.h
index 7a7ce731f8..0933cea9c8 100644
--- a/qpid/cpp/src/qpid/messaging/SessionImpl.h
+++ b/qpid/cpp/src/qpid/messaging/SessionImpl.h
@@ -32,8 +32,8 @@ namespace client {
namespace messaging {
-class Address;
-class Filter;
+struct Address;
+struct Filter;
class Message;
class Sender;
class Receiver;
@@ -56,8 +56,8 @@ class SessionImpl : public virtual qpid::RefCounted
virtual Sender createSender(const Address& address, const VariantMap& options) = 0;
virtual Receiver createReceiver(const Address& address, const VariantMap& options) = 0;
virtual Receiver createReceiver(const Address& address, const Filter& filter, const VariantMap& options) = 0;
- virtual void* getLastConfirmedSent() = 0;
- virtual void* getLastConfirmedAcknowledged() = 0;
+ virtual uint32_t available() = 0;
+ virtual uint32_t pendingAck() = 0;
private:
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Variant.cpp b/qpid/cpp/src/qpid/messaging/Variant.cpp
index 59770939e1..4e37134b39 100644
--- a/qpid/cpp/src/qpid/messaging/Variant.cpp
+++ b/qpid/cpp/src/qpid/messaging/Variant.cpp
@@ -113,31 +113,31 @@ class VariantImpl
};
-VariantImpl::VariantImpl() : type(VOID) { value.i64 = 0; }
-VariantImpl::VariantImpl(bool b) : type(BOOL) { value.b = b; }
-VariantImpl::VariantImpl(uint8_t i) : type(UINT8) { value.ui8 = i; }
-VariantImpl::VariantImpl(uint16_t i) : type(UINT16) { value.ui16 = i; }
-VariantImpl::VariantImpl(uint32_t i) : type(UINT32) { value.ui32 = i; }
-VariantImpl::VariantImpl(uint64_t i) : type(UINT64) { value.ui64 = i; }
-VariantImpl::VariantImpl(int8_t i) : type(INT8) { value.i8 = i; }
-VariantImpl::VariantImpl(int16_t i) : type(INT16) { value.i16 = i; }
-VariantImpl::VariantImpl(int32_t i) : type(INT32) { value.i32 = i; }
-VariantImpl::VariantImpl(int64_t i) : type(INT64) { value.i64 = i; }
-VariantImpl::VariantImpl(float f) : type(FLOAT) { value.f = f; }
-VariantImpl::VariantImpl(double d) : type(DOUBLE) { value.d = d; }
-VariantImpl::VariantImpl(const std::string& s) : type(STRING) { value.v = new std::string(s); }
-VariantImpl::VariantImpl(const Variant::Map& m) : type(MAP) { value.v = new Variant::Map(m); }
-VariantImpl::VariantImpl(const Variant::List& l) : type(LIST) { value.v = new Variant::List(l); }
+VariantImpl::VariantImpl() : type(VAR_VOID) { value.i64 = 0; }
+VariantImpl::VariantImpl(bool b) : type(VAR_BOOL) { value.b = b; }
+VariantImpl::VariantImpl(uint8_t i) : type(VAR_UINT8) { value.ui8 = i; }
+VariantImpl::VariantImpl(uint16_t i) : type(VAR_UINT16) { value.ui16 = i; }
+VariantImpl::VariantImpl(uint32_t i) : type(VAR_UINT32) { value.ui32 = i; }
+VariantImpl::VariantImpl(uint64_t i) : type(VAR_UINT64) { value.ui64 = i; }
+VariantImpl::VariantImpl(int8_t i) : type(VAR_INT8) { value.i8 = i; }
+VariantImpl::VariantImpl(int16_t i) : type(VAR_INT16) { value.i16 = i; }
+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 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() {
switch (type) {
- case STRING:
+ case VAR_STRING:
delete reinterpret_cast<std::string*>(value.v);
break;
- case MAP:
+ case VAR_MAP:
delete reinterpret_cast<Variant::Map*>(value.v);
break;
- case LIST:
+ case VAR_LIST:
delete reinterpret_cast<Variant::List*>(value.v);
break;
default:
@@ -175,169 +175,169 @@ bool toBool(const std::string& s)
bool VariantImpl::asBool() const
{
switch(type) {
- case VOID: return false;
- case BOOL: return value.b;
- case UINT8: return value.ui8;
- case UINT16: return value.ui16;
- case UINT32: return value.ui32;
- case UINT64: return value.ui64;
- case INT8: return value.i8;
- case INT16: return value.i16;
- case INT32: return value.i32;
- case INT64: return value.i64;
- case STRING: return toBool(*reinterpret_cast<std::string*>(value.v));
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(BOOL)));
+ case VAR_VOID: return false;
+ case VAR_BOOL: return value.b;
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return toBool(*reinterpret_cast<std::string*>(value.v));
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_BOOL)));
}
}
uint8_t VariantImpl::asUint8() const
{
switch(type) {
- case UINT8: return value.ui8;
- case STRING: return convertFromString<uint8_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(UINT8)));
+ case VAR_UINT8: return value.ui8;
+ case VAR_STRING: return convertFromString<uint8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT8)));
}
}
uint16_t VariantImpl::asUint16() const
{
switch(type) {
- case UINT8: return value.ui8;
- case UINT16: return value.ui16;
- case STRING: return convertFromString<uint16_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(UINT16)));
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_STRING: return convertFromString<uint16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT16)));
}
}
uint32_t VariantImpl::asUint32() const
{
switch(type) {
- case UINT8: return value.ui8;
- case UINT16: return value.ui16;
- case UINT32: return value.ui32;
- case STRING: return convertFromString<uint32_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(UINT32)));
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_STRING: return convertFromString<uint32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT32)));
}
}
uint64_t VariantImpl::asUint64() const
{
switch(type) {
- case UINT8: return value.ui8;
- case UINT16: return value.ui16;
- case UINT32: return value.ui32;
- case UINT64: return value.ui64;
- case STRING: return convertFromString<uint64_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(UINT64)));
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_STRING: return convertFromString<uint64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT64)));
}
}
int8_t VariantImpl::asInt8() const
{
switch(type) {
- case INT8: return value.i8;
- case STRING: return convertFromString<int8_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(INT8)));
+ case VAR_INT8: return value.i8;
+ case VAR_STRING: return convertFromString<int8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT8)));
}
}
int16_t VariantImpl::asInt16() const
{
switch(type) {
- case INT8: return value.i8;
- case INT16: return value.i16;
- case STRING: return convertFromString<int16_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(INT16)));
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_STRING: return convertFromString<int16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT16)));
}
}
int32_t VariantImpl::asInt32() const
{
switch(type) {
- case INT8: return value.i8;
- case INT16: return value.i16;
- case INT32: return value.i32;
- case STRING: return convertFromString<int32_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(INT32)));
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_STRING: return convertFromString<int32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT32)));
}
}
int64_t VariantImpl::asInt64() const
{
switch(type) {
- case INT8: return value.i8;
- case INT16: return value.i16;
- case INT32: return value.i32;
- case INT64: return value.i64;
- case STRING: return convertFromString<int64_t>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(INT64)));
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return convertFromString<int64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT64)));
}
}
float VariantImpl::asFloat() const
{
switch(type) {
- case FLOAT: return value.f;
- case STRING: return convertFromString<float>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(FLOAT)));
+ case VAR_FLOAT: return value.f;
+ case VAR_STRING: return convertFromString<float>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_FLOAT)));
}
}
double VariantImpl::asDouble() const
{
switch(type) {
- case FLOAT: return value.f;
- case DOUBLE: return value.d;
- case STRING: return convertFromString<double>();
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(DOUBLE)));
+ case VAR_FLOAT: return value.f;
+ case VAR_DOUBLE: return value.d;
+ case VAR_STRING: return convertFromString<double>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_DOUBLE)));
}
}
std::string VariantImpl::asString() const
{
switch(type) {
- case VOID: return EMPTY;
- case BOOL: return value.b ? TRUE : FALSE;
- case UINT8: return boost::lexical_cast<std::string>((int) value.ui8);
- case UINT16: return boost::lexical_cast<std::string>(value.ui16);
- case UINT32: return boost::lexical_cast<std::string>(value.ui32);
- case UINT64: return boost::lexical_cast<std::string>(value.ui64);
- case INT8: return boost::lexical_cast<std::string>((int) value.i8);
- case INT16: return boost::lexical_cast<std::string>(value.i16);
- case INT32: return boost::lexical_cast<std::string>(value.i32);
- case INT64: return boost::lexical_cast<std::string>(value.i64);
- case DOUBLE: return boost::lexical_cast<std::string>(value.d);
- case FLOAT: return boost::lexical_cast<std::string>(value.f);
- case STRING: return *reinterpret_cast<std::string*>(value.v);
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(STRING)));
+ case VAR_VOID: return EMPTY;
+ case VAR_BOOL: return value.b ? TRUE : FALSE;
+ case VAR_UINT8: return boost::lexical_cast<std::string>((int) value.ui8);
+ case VAR_UINT16: return boost::lexical_cast<std::string>(value.ui16);
+ case VAR_UINT32: return boost::lexical_cast<std::string>(value.ui32);
+ case VAR_UINT64: return boost::lexical_cast<std::string>(value.ui64);
+ case VAR_INT8: return boost::lexical_cast<std::string>((int) value.i8);
+ case VAR_INT16: return boost::lexical_cast<std::string>(value.i16);
+ case VAR_INT32: return boost::lexical_cast<std::string>(value.i32);
+ case VAR_INT64: return boost::lexical_cast<std::string>(value.i64);
+ case VAR_DOUBLE: return boost::lexical_cast<std::string>(value.d);
+ case VAR_FLOAT: return boost::lexical_cast<std::string>(value.f);
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_STRING)));
}
}
const Variant::Map& VariantImpl::asMap() const
{
switch(type) {
- case MAP: return *reinterpret_cast<Variant::Map*>(value.v);
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(MAP)));
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
}
}
Variant::Map& VariantImpl::asMap()
{
switch(type) {
- case MAP: return *reinterpret_cast<Variant::Map*>(value.v);
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(MAP)));
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
}
}
const Variant::List& VariantImpl::asList() const
{
switch(type) {
- case LIST: return *reinterpret_cast<Variant::List*>(value.v);
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(LIST)));
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
}
}
Variant::List& VariantImpl::asList()
{
switch(type) {
- case LIST: return *reinterpret_cast<Variant::List*>(value.v);
- default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(LIST)));
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
}
}
std::string& VariantImpl::getString()
{
switch(type) {
- case STRING: return *reinterpret_cast<std::string*>(value.v);
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
}
}
@@ -345,7 +345,7 @@ std::string& VariantImpl::getString()
const std::string& VariantImpl::getString() const
{
switch(type) {
- case STRING: return *reinterpret_cast<std::string*>(value.v);
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
}
}
@@ -356,21 +356,21 @@ const std::string& VariantImpl::getEncoding() const { return encoding; }
std::string VariantImpl::getTypeName(VariantType type) const
{
switch (type) {
- case VOID: return "void";
- case BOOL: return "bool";
- case UINT8: return "uint8";
- case UINT16: return "uint16";
- case UINT32: return "uint32";
- case UINT64: return "uint64";
- case INT8: return "int8";
- case INT16: return "int16";
- case INT32: return "int32";
- case INT64: return "int64";
- case FLOAT: return "float";
- case DOUBLE: return "double";
- case STRING: return "string";
- case MAP: return "map";
- case LIST: return "list";
+ case VAR_VOID: return "void";
+ case VAR_BOOL: return "bool";
+ case VAR_UINT8: return "uint8";
+ case VAR_UINT16: return "uint16";
+ case VAR_UINT32: return "uint32";
+ case VAR_UINT64: return "uint64";
+ case VAR_INT8: return "int8";
+ case VAR_INT16: return "int16";
+ case VAR_INT32: return "int32";
+ case VAR_INT64: return "int64";
+ case VAR_FLOAT: return "float";
+ case VAR_DOUBLE: return "double";
+ case VAR_STRING: return "string";
+ case VAR_MAP: return "map";
+ case VAR_LIST: return "list";
}
return "<unknown>";//should never happen
}
@@ -378,20 +378,20 @@ std::string VariantImpl::getTypeName(VariantType type) const
VariantImpl* VariantImpl::create(const Variant& v)
{
switch (v.getType()) {
- case BOOL: return new VariantImpl(v.asBool());
- case UINT8: return new VariantImpl(v.asUint8());
- case UINT16: return new VariantImpl(v.asUint16());
- case UINT32: return new VariantImpl(v.asUint32());
- case UINT64: return new VariantImpl(v.asUint64());
- case INT8: return new VariantImpl(v.asInt8());
- case INT16: return new VariantImpl(v.asInt16());
- case INT32: return new VariantImpl(v.asInt32());
- case INT64: return new VariantImpl(v.asInt64());
- case FLOAT: return new VariantImpl(v.asFloat());
- case DOUBLE: return new VariantImpl(v.asDouble());
- case STRING: return new VariantImpl(v.asString());
- case MAP: return new VariantImpl(v.asMap());
- case LIST: return new VariantImpl(v.asList());
+ case VAR_BOOL: return new VariantImpl(v.asBool());
+ case VAR_UINT8: return new VariantImpl(v.asUint8());
+ case VAR_UINT16: return new VariantImpl(v.asUint16());
+ case VAR_UINT32: return new VariantImpl(v.asUint32());
+ case VAR_UINT64: return new VariantImpl(v.asUint64());
+ case VAR_INT8: return new VariantImpl(v.asInt8());
+ case VAR_INT16: return new VariantImpl(v.asInt16());
+ case VAR_INT32: return new VariantImpl(v.asInt32());
+ 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_MAP: return new VariantImpl(v.asMap());
+ case VAR_LIST: return new VariantImpl(v.asList());
default: return new VariantImpl();
}
}
@@ -584,13 +584,13 @@ std::ostream& operator<<(std::ostream& out, const Variant::List& list)
std::ostream& operator<<(std::ostream& out, const Variant& value)
{
switch (value.getType()) {
- case MAP:
+ case VAR_MAP:
out << "{" << value.asMap() << "}";
break;
- case LIST:
+ case VAR_LIST:
out << "[" << value.asList() << "]";
break;
- case VOID:
+ case VAR_VOID:
out << "<void>";
break;
default:
diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 5d1ac6d034..8545ebd9cb 100644
--- a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -305,6 +305,13 @@ private:
* thread processing this handle.
*/
volatile bool writePending;
+ /**
+ * This records whether we've been reading is flow controlled:
+ * it's safe as a simple boolean as the only way to be stopped
+ * is in calls only allowed in the callback context, the only calls
+ * checking it are also in calls only allowed in callback context.
+ */
+ volatile bool readingStopped;
};
AsynchIO::AsynchIO(const Socket& s,
@@ -323,7 +330,8 @@ AsynchIO::AsynchIO(const Socket& s,
idleCallback(iCb),
socket(s),
queuedClose(false),
- writePending(false) {
+ writePending(false),
+ readingStopped(false) {
s.setNonblocking();
}
@@ -351,8 +359,11 @@ void AsynchIO::queueReadBuffer(BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
buff->dataCount = 0;
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_back(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::unread(BufferBase* buff) {
@@ -361,15 +372,18 @@ void AsynchIO::unread(BufferBase* buff) {
memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
buff->dataStart = 0;
}
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_front(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::queueWrite(BufferBase* buff) {
assert(buff);
// If we've already closed the socket then throw the write away
if (queuedClose) {
- bufferQueue.push_front(buff);
+ queueReadBuffer(buff);
return;
} else {
writeQueue.push_front(buff);
@@ -378,6 +392,7 @@ void AsynchIO::queueWrite(BufferBase* buff) {
DispatchHandle::rewatchWrite();
}
+// This can happen outside the callback context
void AsynchIO::notifyPendingWrite() {
writePending = true;
DispatchHandle::rewatchWrite();
@@ -392,11 +407,14 @@ bool AsynchIO::writeQueueEmpty() {
return writeQueue.empty();
}
+// This can happen outside the callback context
void AsynchIO::startReading() {
+ readingStopped = false;
DispatchHandle::rewatchRead();
}
void AsynchIO::stopReading() {
+ readingStopped = true;
DispatchHandle::unwatchRead();
}
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
index 52208d0519..9da6c835ce 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -45,6 +45,9 @@ using qpid::sys::Duration;
using qpid::sys::TIME_SEC;
using qpid::sys::TIME_INFINITE;
+namespace qpid {
+namespace tests {
+
// count of messages
int64_t smsgs = 0;
int64_t sbytes = 0;
@@ -144,6 +147,10 @@ void rejected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&, con
p->shutdown();
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
index 1ab5268596..07d6379362 100644
--- a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
+++ b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,6 +39,9 @@ using qpid::sys::Poller;
using qpid::sys::Dispatcher;
// All the accepted connections
+namespace qpid {
+namespace tests {
+
struct ConRec {
Rdma::Connection::intrusive_ptr connection;
Rdma::AsynchIO* data;
@@ -134,6 +137,10 @@ void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
cr->data->start(poller);
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
diff --git a/qpid/cpp/include/qpid/sys/uuid.h b/qpid/cpp/src/qpid/sys/uuid.h
index 804ab34463..804ab34463 100644
--- a/qpid/cpp/include/qpid/sys/uuid.h
+++ b/qpid/cpp/src/qpid/sys/uuid.h
diff --git a/qpid/cpp/include/qpid/sys/windows/uuid.h b/qpid/cpp/src/qpid/sys/windows/uuid.h
index c79abe95c6..c79abe95c6 100644
--- a/qpid/cpp/include/qpid/sys/windows/uuid.h
+++ b/qpid/cpp/src/qpid/sys/windows/uuid.h
diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
index a41c8840ff..8a1ef6149e 100644
--- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
@@ -156,7 +156,7 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
// This will parse the document using either Xerces or FastXDM, depending
// on your XQilla configuration. FastXDM can be as much as 10x faster.
-
+
Sequence seq(context->parseDocument(xml));
if(!seq.isEmpty() && seq.first()->isNode()) {
@@ -206,11 +206,11 @@ void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldT
PreRoute pr(msg, this);
try {
XmlBinding::vector::ConstPtr p;
- {
+ {
RWlock::ScopedRlock l(lock);
- p = bindingsMap[routingKey].snapshot();
- if (!p) return;
- }
+ p = bindingsMap[routingKey].snapshot();
+ if (!p) return;
+ }
int count(0);
for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) {
@@ -222,24 +222,24 @@ void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldT
if ((*i)->mgmtBinding != 0)
(*i)->mgmtBinding->inc_msgMatched ();
}
- }
- if (!count) {
- QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- } else {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- }
+ }
+ if (!count) {
+ QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ } else {
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ }
} catch (...) {
QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey);
}
diff --git a/qpid/cpp/src/tests/AccumulatedAckTest.cpp b/qpid/cpp/src/tests/AccumulatedAckTest.cpp
index 028ce71907..c736a519d2 100644
--- a/qpid/cpp/src/tests/AccumulatedAckTest.cpp
+++ b/qpid/cpp/src/tests/AccumulatedAckTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@ using std::list;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
bool covers(const AccumulatedAck& ack, int i)
{
return ack.covers(SequenceNumber(i));
@@ -97,7 +100,7 @@ QPID_AUTO_TEST_CASE(testUpdateFromCompletionData)
ack.update(mark, ranges);
- for(int i = 0; i <= 15; i++) {
+ for(int i = 0; i <= 15; i++) {
BOOST_CHECK(covers(ack, i));
}
BOOST_CHECK(!covers(ack, 16));
@@ -221,7 +224,7 @@ QPID_AUTO_TEST_CASE(testConsolidation4)
ack.update(SequenceNumber(9), SequenceNumber(9));
ack.update(SequenceNumber(3), SequenceNumber(4));
- for(int i = 0; i <= 15; i++) {
+ for(int i = 0; i <= 15; i++) {
BOOST_CHECK(covers(ack, i));
}
BOOST_CHECK(!covers(ack, 16));
@@ -230,3 +233,5 @@ QPID_AUTO_TEST_CASE(testConsolidation4)
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Array.cpp b/qpid/cpp/src/tests/Array.cpp
index c779cbe901..7622b89d15 100644
--- a/qpid/cpp/src/tests/Array.cpp
+++ b/qpid/cpp/src/tests/Array.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,6 +25,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ArrayTestSuite)
using namespace qpid::framing;
@@ -69,7 +72,7 @@ QPID_AUTO_TEST_CASE(testArrayAssignment)
Array a(data);
b = a;
BOOST_CHECK_EQUAL(a, b);
- }
+ }
std::vector<std::string> data2;
b.collect(data2);
//BOOST_CHECK_EQUAL(data, data2);
@@ -77,3 +80,5 @@ QPID_AUTO_TEST_CASE(testArrayAssignment)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/AsyncCompletion.cpp b/qpid/cpp/src/tests/AsyncCompletion.cpp
index 41423d8245..4492e6b6bc 100644
--- a/qpid/cpp/src/tests/AsyncCompletion.cpp
+++ b/qpid/cpp/src/tests/AsyncCompletion.cpp
@@ -49,10 +49,13 @@ using boost::intrusive_ptr;
* message enqueues at the correct time.
*/
+namespace qpid {
+namespace tests {
+
class AsyncCompletionMessageStore : public NullMessageStore {
public:
sys::BlockingQueue<boost::intrusive_ptr<PersistableMessage> > enqueued;
-
+
AsyncCompletionMessageStore() : NullMessageStore() {}
~AsyncCompletionMessageStore(){}
@@ -82,10 +85,10 @@ QPID_AUTO_TEST_CASE(testWaitTillComplete) {
transfers[i] = s.messageTransfer(arg::content=msg);
}
- // Get hold of the broker-side messages.
+ // Get hold of the broker-side messages.
typedef vector<intrusive_ptr<PersistableMessage> > BrokerMessages;
BrokerMessages enqueued;
- for (int j = 0; j < count; ++j)
+ for (int j = 0; j < count; ++j)
enqueued.push_back(store->enqueued.pop(TIME_SEC));
// Send a sync, make sure it does not complete till all messages are complete.
@@ -111,3 +114,5 @@ QPID_AUTO_TEST_CASE(testGetResult) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/AtomicValue.cpp b/qpid/cpp/src/tests/AtomicValue.cpp
index 05083ad177..d855d993a7 100644
--- a/qpid/cpp/src/tests/AtomicValue.cpp
+++ b/qpid/cpp/src/tests/AtomicValue.cpp
@@ -21,6 +21,9 @@
#include "test_tools.h"
#include "qpid/sys/AtomicValue.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(AtomicValueTestSuite)
QPID_AUTO_TEST_CASE(test) {
@@ -47,3 +50,5 @@ QPID_AUTO_TEST_CASE(test) {
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/BrokerFixture.h b/qpid/cpp/src/tests/BrokerFixture.h
index 397045d00b..bb985cf7e1 100644
--- a/qpid/cpp/src/tests/BrokerFixture.h
+++ b/qpid/cpp/src/tests/BrokerFixture.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -35,6 +35,9 @@
#include "qpid/sys/Thread.h"
#include <boost/noncopyable.hpp>
+namespace qpid {
+namespace tests {
+
/**
* A fixture with an in-process broker.
*/
@@ -55,7 +58,7 @@ struct BrokerFixture : private boost::noncopyable {
}
opts.port=0;
// Management doesn't play well with multiple in-process brokers.
- opts.enableMgmt=false;
+ opts.enableMgmt=false;
opts.workerThreads=1;
opts.dataDir="";
opts.auth=false;
@@ -144,5 +147,6 @@ struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> {
typedef SessionFixtureT<LocalConnection> SessionFixture;
typedef SessionFixtureT<ProxyConnection> ProxySessionFixture;
+}} // namespace qpid::tests
#endif /*!TESTS_BROKERFIXTURE_H*/
diff --git a/qpid/cpp/src/tests/CMakeLists.txt b/qpid/cpp/src/tests/CMakeLists.txt
index 56a4aaf2b0..b1219aad74 100644
--- a/qpid/cpp/src/tests/CMakeLists.txt
+++ b/qpid/cpp/src/tests/CMakeLists.txt
@@ -95,7 +95,7 @@ set(unit_tests_to_build
InlineAllocator
InlineVector
ClientSessionTest
- MessagingSessionTest
+ MessagingSessionTests
SequenceSet
StringUtils
IncompleteMessageList
diff --git a/qpid/cpp/src/tests/ClientMessageTest.cpp b/qpid/cpp/src/tests/ClientMessageTest.cpp
index bc0945674f..f925f1c234 100644
--- a/qpid/cpp/src/tests/ClientMessageTest.cpp
+++ b/qpid/cpp/src/tests/ClientMessageTest.cpp
@@ -24,6 +24,9 @@
using namespace qpid::client;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ClientMessageTestSuite)
QPID_AUTO_TEST_CASE(MessageCopyAssign) {
@@ -33,7 +36,7 @@ QPID_AUTO_TEST_CASE(MessageCopyAssign) {
Message c(m);
BOOST_CHECK_EQUAL("foo", c.getData());
Message a;
- BOOST_CHECK_EQUAL("", a.getData());
+ BOOST_CHECK_EQUAL("", a.getData());
a = m;
BOOST_CHECK_EQUAL("foo", a.getData());
a.setData("a");
@@ -44,3 +47,5 @@ QPID_AUTO_TEST_CASE(MessageCopyAssign) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ClientSessionTest.cpp b/qpid/cpp/src/tests/ClientSessionTest.cpp
index 3ed7491f7d..6ca0aa6d44 100644
--- a/qpid/cpp/src/tests/ClientSessionTest.cpp
+++ b/qpid/cpp/src/tests/ClientSessionTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -40,6 +40,9 @@
#include <vector>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ClientSessionTest)
using namespace qpid::client;
@@ -122,12 +125,12 @@ QPID_AUTO_TEST_CASE(testDispatcher)
ClientSessionFixture fix;
fix.session =fix.connection.newSession();
size_t count = 100;
- for (size_t i = 0; i < count; ++i)
+ for (size_t i = 0; i < count; ++i)
fix.session.messageTransfer(arg::content=Message(boost::lexical_cast<string>(i), "my-queue"));
DummyListener listener(fix.session, "my-queue", count);
listener.run();
- BOOST_CHECK_EQUAL(count, listener.messages.size());
- for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
}
@@ -142,8 +145,8 @@ QPID_AUTO_TEST_CASE(testDispatcherThread)
fix.session.messageTransfer(arg::content=Message(boost::lexical_cast<string>(i), "my-queue"));
}
t.join();
- BOOST_CHECK_EQUAL(count, listener.messages.size());
- for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
}
@@ -215,7 +218,7 @@ QPID_AUTO_TEST_CASE(testLocalQueue) {
BOOST_CHECK_EQUAL("foo1", lq.pop().getData());
BOOST_CHECK(lq.empty()); // Credit exhausted.
fix.subs.getSubscription("lq").setFlowControl(FlowControl::unlimited());
- BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
+ BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
}
struct DelayedTransfer : sys::Runnable
@@ -246,7 +249,7 @@ QPID_AUTO_TEST_CASE(testGet) {
Thread t(sender);
//test timed get where message shows up after a short delay
BOOST_CHECK(fix.subs.get(got, "getq", 5*TIME_SEC));
- BOOST_CHECK_EQUAL("foo2", got.getData());
+ BOOST_CHECK_EQUAL("foo2", got.getData());
t.join();
}
@@ -271,8 +274,8 @@ QPID_AUTO_TEST_CASE(testPeriodicExpiration) {
ClientSessionFixture fix(opts);
fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
- for (uint i = 0; i < 10; i++) {
- Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
if (i % 2) m.getDeliveryProperties().setTtl(500);
fix.session.messageTransfer(arg::content=m);
}
@@ -286,15 +289,15 @@ QPID_AUTO_TEST_CASE(testExpirationOnPop) {
ClientSessionFixture fix;
fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
- for (uint i = 0; i < 10; i++) {
- Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
if (i % 2) m.getDeliveryProperties().setTtl(200);
fix.session.messageTransfer(arg::content=m);
}
qpid::sys::usleep(300* 1000);
- for (uint i = 0; i < 10; i++) {
+ for (uint i = 0; i < 10; i++) {
if (i % 2) continue;
Message m;
BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
@@ -306,8 +309,8 @@ QPID_AUTO_TEST_CASE(testRelease) {
ClientSessionFixture fix;
const uint count=10;
- for (uint i = 0; i < count; i++) {
- Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
fix.session.messageTransfer(arg::content=m);
}
@@ -334,7 +337,7 @@ QPID_AUTO_TEST_CASE(testRelease) {
for (uint i = 0; i < count; i++) {
BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l2.messages[i].getData());
}
-
+
fix.subs.stop();
fix.subs.wait();
fix.session.close();
@@ -344,8 +347,8 @@ QPID_AUTO_TEST_CASE(testCompleteOnAccept) {
ClientSessionFixture fix;
const uint count = 8;
const uint chunk = 4;
- for (uint i = 0; i < count; i++) {
- Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
fix.session.messageTransfer(arg::content=m);
}
@@ -358,25 +361,25 @@ QPID_AUTO_TEST_CASE(testCompleteOnAccept) {
Subscription s = fix.subs.subscribe(q, "my-queue", settings);
fix.session.messageFlush(arg::destination=s.getName());
SequenceSet accepted;
- for (uint i = 0; i < chunk; i++) {
+ for (uint i = 0; i < chunk; i++) {
Message m;
BOOST_CHECK(q.get(m));
BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
accepted.add(m.getId());
- }
+ }
Message m;
BOOST_CHECK(!q.get(m));
-
+
s.accept(accepted);
fix.session.messageFlush(arg::destination=s.getName());
accepted.clear();
-
- for (uint i = chunk; i < count; i++) {
+
+ for (uint i = chunk; i < count; i++) {
Message m;
BOOST_CHECK(q.get(m));
BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
accepted.add(m.getId());
- }
+ }
fix.session.messageAccept(accepted);
}
@@ -424,7 +427,7 @@ QPID_AUTO_TEST_CASE(testConcurrentSenders)
connection.open(settings);
AsyncSession session = connection.newSession();
Message message(string(512, 'X'));
-
+
boost::ptr_vector<Publisher> publishers;
for (size_t i = 0; i < 5; i++) {
publishers.push_back(new Publisher(connection, message, 100));
@@ -447,7 +450,7 @@ QPID_AUTO_TEST_CASE(testExclusiveSubscribe)
ScopedSuppressLogging sl;
BOOST_CHECK_THROW(fix.subs.subscribe(q, "myq", "second"), ResourceLockedException);
;
-
+
}
QPID_AUTO_TEST_CASE(testExclusiveBinding) {
@@ -478,7 +481,7 @@ QPID_AUTO_TEST_CASE(testResubscribeWithLocalQueue) {
fix.subs.subscribe(p, "some-queue");
fix.subs.cancel("some-queue");
fix.subs.subscribe(q, "some-queue");
-
+
fix.session.messageTransfer(arg::content=Message("some-data", "some-queue"));
fix.session.messageFlush(arg::destination="some-queue");
@@ -542,10 +545,10 @@ QPID_AUTO_TEST_CASE(testLVQVariedSize) {
std::ostringstream data;
size_t size = 100 - ((i % 10) * 10);
data << std::string(size, 'x');
-
+
Message m(data.str(), queue);
m.getHeaders().setString(key, "abc");
- fix.session.messageTransfer(arg::content=m);
+ fix.session.messageTransfer(arg::content=m);
}
}
@@ -594,7 +597,7 @@ QPID_AUTO_TEST_CASE(testExpirationNotAltered) {
ClientSessionFixture fix;
fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
- Message m("my-message", "my-queue");
+ Message m("my-message", "my-queue");
m.getDeliveryProperties().setTtl(60000);
m.getDeliveryProperties().setExpiration(12345);
fix.session.messageTransfer(arg::content=m);
@@ -606,4 +609,4 @@ QPID_AUTO_TEST_CASE(testExpirationNotAltered) {
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ClusterFailover.cpp b/qpid/cpp/src/tests/ClusterFailover.cpp
index 9ce9c4a36b..c2fb1282b1 100644
--- a/qpid/cpp/src/tests/ClusterFailover.cpp
+++ b/qpid/cpp/src/tests/ClusterFailover.cpp
@@ -32,6 +32,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/bind.hpp>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ClusterFailoverTestSuite)
using namespace std;
@@ -60,3 +63,5 @@ QPID_AUTO_TEST_CASE(testReconnectSameSessionName) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ClusterFixture.cpp b/qpid/cpp/src/tests/ClusterFixture.cpp
index e12106c464..7c357c3cd1 100644
--- a/qpid/cpp/src/tests/ClusterFixture.cpp
+++ b/qpid/cpp/src/tests/ClusterFixture.cpp
@@ -61,6 +61,9 @@ using boost::assign::list_of;
#include "ClusterFixture.h"
+namespace qpid {
+namespace tests {
+
ClusterFixture::ClusterFixture(size_t n, const Args& args_, int localIndex_)
: name(Uuid(true).str()), localIndex(localIndex_), userArgs(args_)
{
@@ -152,3 +155,5 @@ std::set<int> knownBrokerPorts(qpid::client::Connection& source, int n) {
s.insert((*i)[0].get<qpid::TcpAddress>()->port);
return s;
}
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ClusterFixture.h b/qpid/cpp/src/tests/ClusterFixture.h
index 08b314499e..5952cc1736 100644
--- a/qpid/cpp/src/tests/ClusterFixture.h
+++ b/qpid/cpp/src/tests/ClusterFixture.h
@@ -60,6 +60,9 @@ using qpid::broker::Broker;
using boost::shared_ptr;
using qpid::cluster::Cluster;
+namespace qpid {
+namespace tests {
+
/** Cluster fixture is a vector of ports for the replicas.
*
* At most one replica (by default replica 0) is in the current
@@ -107,4 +110,6 @@ class ClusterFixture : public vector<uint16_t> {
*/
std::set<int> knownBrokerPorts(qpid::client::Connection& source, int n=-1);
+}} // namespace qpid::tests
+
#endif /*!CLUSTER_FIXTURE_H*/
diff --git a/qpid/cpp/src/tests/ConnectionOptions.h b/qpid/cpp/src/tests/ConnectionOptions.h
index cf86894235..6fd6c2c63f 100644
--- a/qpid/cpp/src/tests/ConnectionOptions.h
+++ b/qpid/cpp/src/tests/ConnectionOptions.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,6 +25,8 @@
#include "qpid/client/ConnectionSettings.h"
#include "qpid/Options.h"
+namespace qpid {
+
/**
* Options parser for ConnectionOptions.
*/
@@ -35,9 +37,9 @@ struct ConnectionOptions : public qpid::Options,
{
using namespace qpid;
addOptions()
- ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
("port,p", optValue(port, "PORT"), "Broker port to connect to")
- ("protocol,P", optValue(protocol, "tcp|rdma"), "Protocol to use for broker connection")
+ ("protocol,P", optValue(protocol, "tcp|rdma"), "Protocol to use for broker connection")
("virtualhost,v", optValue(virtualhost, "VHOST"), "virtual host")
("username", optValue(username, "USER"), "user name for broker log in.")
("password", optValue(password, "PASSWORD"), "password for broker log in.")
@@ -46,7 +48,7 @@ struct ConnectionOptions : public qpid::Options,
("max-channels", optValue(maxChannels, "N"), "the maximum number of channels the client requires.")
("heartbeat", optValue(heartbeat, "N"), "Desired heartbeat interval in seconds.")
("max-frame-size", optValue(maxFrameSize, "N"), "the maximum frame size to request.")
- ("bounds-multiplier", optValue(bounds, "N"),
+ ("bounds-multiplier", optValue(bounds, "N"),
"bound size of write queue (as a multiple of the max frame size).")
("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
("service", optValue(service, "SERVICE-NAME"), "SASL service name.")
@@ -55,4 +57,6 @@ struct ConnectionOptions : public qpid::Options,
}
};
+} // namespace qpid
+
#endif /*!QPID_CLIENT_CONNECTIONOPTIONS_H*/
diff --git a/qpid/cpp/src/tests/ConsoleTest.cpp b/qpid/cpp/src/tests/ConsoleTest.cpp
index 1d55b13f3c..107472ed9e 100644
--- a/qpid/cpp/src/tests/ConsoleTest.cpp
+++ b/qpid/cpp/src/tests/ConsoleTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
#include "qpid/console/ClassKey.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ConsoleTestSuite)
using namespace qpid::framing;
@@ -40,4 +43,4 @@ QPID_AUTO_TEST_CASE(testClassKey) {
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/DeliveryRecordTest.cpp b/qpid/cpp/src/tests/DeliveryRecordTest.cpp
index 8ff7ad3584..17f9a0d148 100644
--- a/qpid/cpp/src/tests/DeliveryRecordTest.cpp
+++ b/qpid/cpp/src/tests/DeliveryRecordTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,6 +31,9 @@ using namespace qpid::framing;
using boost::dynamic_pointer_cast;
using std::list;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(DeliveryRecordTestSuite)
QPID_AUTO_TEST_CASE(testSort)
@@ -60,3 +63,4 @@ QPID_AUTO_TEST_CASE(testSort)
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/DispatcherTest.cpp b/qpid/cpp/src/tests/DispatcherTest.cpp
index c619a36438..17b3b4e3e6 100644
--- a/qpid/cpp/src/tests/DispatcherTest.cpp
+++ b/qpid/cpp/src/tests/DispatcherTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,6 +39,9 @@
using namespace std;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
int writeALot(int fd, const string& s) {
int bytesWritten = 0;
do {
@@ -46,7 +49,7 @@ int writeALot(int fd, const string& s) {
int lastWrite = ::write(fd, s.c_str(), s.size());
if ( lastWrite >= 0) {
bytesWritten += lastWrite;
- }
+ }
} while (errno != EAGAIN);
return bytesWritten;
}
@@ -54,13 +57,13 @@ int writeALot(int fd, const string& s) {
int readALot(int fd) {
int bytesRead = 0;
char buf[10240];
-
+
do {
errno = 0;
int lastRead = ::read(fd, buf, sizeof(buf));
if ( lastRead >= 0) {
bytesRead += lastRead;
- }
+ }
} while (errno != EAGAIN);
return bytesRead;
}
@@ -83,7 +86,7 @@ void rInterrupt(DispatchHandle&) {
}
void wInterrupt(DispatchHandle&) {
- cerr << "W";
+ cerr << "W";
}
DispatchHandle::Callback rcb = rInterrupt;
@@ -108,15 +111,19 @@ void timer_handler(int /*signo*/, siginfo_t* /*info*/, void* /*context*/) {
wh->call(wcb);
} else {
phase1finished = true;
- assert(::timer_delete(timer) == 0);
+ assert(::timer_delete(timer) == 0);
}
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int /*argc*/, char** /*argv*/)
{
// Create poller
Poller::shared_ptr poller(new Poller);
-
+
// Create dispatcher thread
Dispatcher d(poller);
Dispatcher d1(poller);
@@ -131,14 +138,14 @@ int main(int /*argc*/, char** /*argv*/)
int sv[2];
int rc = ::socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
assert(rc >= 0);
-
+
// Set non-blocking
rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
-
+
// Make up a large string
string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
for (int i = 0; i < 8; i++)
@@ -148,19 +155,19 @@ int main(int /*argc*/, char** /*argv*/)
PosixIOHandle f1(sv[1]);
rh = new DispatchHandleRef(f0, boost::bind(reader, _1, sv[0]), 0, 0);
- wh = new DispatchHandleRef(f1, 0, boost::bind(writer, _1, sv[1], testString), 0);
+ wh = new DispatchHandleRef(f1, 0, boost::bind(writer, _1, sv[1], testString), 0);
rh->startWatch(poller);
wh->startWatch(poller);
// Set up a regular itimer interupt
-
+
// Ignore signal in this thread
::sigset_t sm;
::sigemptyset(&sm);
::sigaddset(&sm, SIGRTMIN);
::pthread_sigmask(SIG_BLOCK, &sm, 0);
-
+
// Signal handling
struct ::sigaction sa;
sa.sa_sigaction = timer_handler;
@@ -168,18 +175,18 @@ int main(int /*argc*/, char** /*argv*/)
::sigemptyset(&sa.sa_mask);
rc = ::sigaction(SIGRTMIN, &sa,0);
assert(rc == 0);
-
+
::sigevent se;
::memset(&se, 0, sizeof(se)); // Clear to make valgrind happy (this *is* the neatest way to do this portably - sigh)
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = SIGRTMIN;
rc = ::timer_create(CLOCK_REALTIME, &se, &timer);
assert(rc == 0);
-
+
itimerspec ts = {
/*.it_value = */ {2, 0}, // s, ns
/*.it_interval = */ {2, 0}}; // s, ns
-
+
rc = ::timer_settime(timer, 0, &ts, 0);
assert(rc == 0);
@@ -200,11 +207,11 @@ int main(int /*argc*/, char** /*argv*/)
sa.sa_sigaction = stop_handler;
rc = ::sigaction(SIGRTMIN, &sa,0);
assert(rc == 0);
-
+
itimerspec nts = {
/*.it_value = */ {30, 0}, // s, ns
/*.it_interval = */ {30, 0}}; // s, ns
-
+
rc = ::timer_create(CLOCK_REALTIME, &se, &timer);
assert(rc == 0);
rc = ::timer_settime(timer, 0, &nts, 0);
@@ -228,7 +235,7 @@ int main(int /*argc*/, char** /*argv*/)
rc = ::timer_delete(timer);
assert(rc == 0);
-
+
poller->shutdown();
dt.join();
dt1.join();
@@ -237,6 +244,6 @@ int main(int /*argc*/, char** /*argv*/)
cout << "\nWrote: " << writtenBytes << "\n";
cout << "Read: " << readBytes << "\n";
-
+
return 0;
}
diff --git a/qpid/cpp/src/tests/DtxWorkRecordTest.cpp b/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
index c7c1b460ff..9d7666dca4 100644
--- a/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
+++ b/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
using namespace qpid::broker;
using boost::static_pointer_cast;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(DtxWorkRecordTestSuite)
QPID_AUTO_TEST_CASE(testOnePhaseCommit){
@@ -44,7 +47,7 @@ QPID_AUTO_TEST_CASE(testOnePhaseCommit){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -77,7 +80,7 @@ QPID_AUTO_TEST_CASE(testFailOnOnePhaseCommit){
DtxBuffer::shared_ptr bufferC(new DtxBuffer());
bufferC->enlist(static_pointer_cast<TxOp>(opC));
bufferC->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -108,7 +111,7 @@ QPID_AUTO_TEST_CASE(testTwoPhaseCommit){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -142,7 +145,7 @@ QPID_AUTO_TEST_CASE(testFailOnTwoPhaseCommit){
DtxBuffer::shared_ptr bufferC(new DtxBuffer());
bufferC->enlist(static_pointer_cast<TxOp>(opC));
bufferC->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -171,7 +174,7 @@ QPID_AUTO_TEST_CASE(testRollback){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -187,3 +190,4 @@ QPID_AUTO_TEST_CASE(testRollback){
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ExchangeTest.cpp b/qpid/cpp/src/tests/ExchangeTest.cpp
index 2100fb5ed7..44835c6184 100644
--- a/qpid/cpp/src/tests/ExchangeTest.cpp
+++ b/qpid/cpp/src/tests/ExchangeTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,9 +39,12 @@ using namespace qpid::framing;
using namespace qpid::sys;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ExchangeTestSuite)
-QPID_AUTO_TEST_CASE(testMe)
+QPID_AUTO_TEST_CASE(testMe)
{
Queue::shared_ptr queue(new Queue("queue", true));
Queue::shared_ptr queue2(new Queue("queue2", true));
@@ -70,7 +73,7 @@ QPID_AUTO_TEST_CASE(testIsBound)
Queue::shared_ptr b(new Queue("b", true));
Queue::shared_ptr c(new Queue("c", true));
Queue::shared_ptr d(new Queue("d", true));
-
+
string k1("abc");
string k2("def");
string k3("xyz");
@@ -139,7 +142,7 @@ QPID_AUTO_TEST_CASE(testIsBound)
headers.bind(a, "", &args3);
headers.bind(b, "", &args2);
headers.bind(c, "", &args1);
-
+
BOOST_CHECK(headers.isBound(a, 0, 0));
BOOST_CHECK(headers.isBound(a, 0, &args1));
BOOST_CHECK(headers.isBound(a, 0, &args3));
@@ -153,7 +156,7 @@ QPID_AUTO_TEST_CASE(testIsBound)
BOOST_CHECK(!headers.isBound(d, 0, &args3));
}
-QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
+QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
{
ExchangeRegistry exchanges;
exchanges.declare("my-exchange", "direct", false, FieldTable());
@@ -162,7 +165,7 @@ QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
exchanges.get("my-exchange");
} catch (const NotFoundException&) {}
std::pair<Exchange::shared_ptr, bool> response = exchanges.declare("my-exchange", "direct", false, FieldTable());
- BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
+ BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
}
intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
@@ -175,7 +178,7 @@ intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
return msg;
}
-QPID_AUTO_TEST_CASE(testSequenceOptions)
+QPID_AUTO_TEST_CASE(testSequenceOptions)
{
FieldTable args;
args.setInt("qpid.msg_sequence",1);
@@ -225,22 +228,22 @@ QPID_AUTO_TEST_CASE(testSequenceOptions)
direct.encode(buffer);
}
{
-
+
ExchangeRegistry exchanges;
buffer.reset();
DirectExchange::shared_ptr exch_dec = Exchange::decode(exchanges, buffer);
-
+
intrusive_ptr<Message> msg1 = cmessage("e", "A");
DeliverableMessage dmsg1(msg1);
exch_dec->route(dmsg1, "abc", 0);
BOOST_CHECK_EQUAL(4, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
-
+
}
delete [] buff;
}
-QPID_AUTO_TEST_CASE(testIVEOption)
+QPID_AUTO_TEST_CASE(testIVEOption)
{
FieldTable args;
args.setInt("qpid.ive",1);
@@ -248,7 +251,7 @@ QPID_AUTO_TEST_CASE(testIVEOption)
FanOutExchange fanout("fanout1", false, args);
HeadersExchange header("headers1", false, args);
TopicExchange topic ("topic1", false, args);
-
+
intrusive_ptr<Message> msg1 = cmessage("direct1", "abc");
msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString("a", "abc");
DeliverableMessage dmsg1(msg1);
@@ -256,7 +259,7 @@ QPID_AUTO_TEST_CASE(testIVEOption)
FieldTable args2;
args2.setString("x-match", "any");
args2.setString("a", "abc");
-
+
direct.route(dmsg1, "abc", 0);
fanout.route(dmsg1, "abc", 0);
header.route(dmsg1, "abc", &args2);
@@ -265,20 +268,22 @@ QPID_AUTO_TEST_CASE(testIVEOption)
Queue::shared_ptr queue1(new Queue("queue1", true));
Queue::shared_ptr queue2(new Queue("queue2", true));
Queue::shared_ptr queue3(new Queue("queue3", true));
-
+
BOOST_CHECK(HeadersExchange::match(args2, msg1->getProperties<MessageProperties>()->getApplicationHeaders()));
-
+
BOOST_CHECK(direct.bind(queue, "abc", 0));
BOOST_CHECK(fanout.bind(queue1, "abc", 0));
BOOST_CHECK(header.bind(queue2, "", &args2));
BOOST_CHECK(topic.bind(queue3, "abc", 0));
-
+
BOOST_CHECK_EQUAL(1u,queue->getMessageCount());
BOOST_CHECK_EQUAL(1u,queue1->getMessageCount());
BOOST_CHECK_EQUAL(1u,queue2->getMessageCount());
BOOST_CHECK_EQUAL(1u,queue3->getMessageCount());
-
+
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/FieldTable.cpp b/qpid/cpp/src/tests/FieldTable.cpp
index 5b43871f6d..fe2a14ec03 100644
--- a/qpid/cpp/src/tests/FieldTable.cpp
+++ b/qpid/cpp/src/tests/FieldTable.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -29,6 +29,9 @@
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FieldTableTestSuite)
QPID_AUTO_TEST_CASE(testMe)
@@ -57,7 +60,7 @@ QPID_AUTO_TEST_CASE(testAssignment)
a.setInt("B", 1234);
b = a;
a.setString("A", "CCCC");
-
+
BOOST_CHECK(string("CCCC") == a.getAsString("A"));
BOOST_CHECK(string("BBBB") == b.getAsString("A"));
BOOST_CHECK_EQUAL(1234, a.getAsInt("B"));
@@ -69,7 +72,7 @@ QPID_AUTO_TEST_CASE(testAssignment)
{
FieldTable c;
c = a;
-
+
char* buff = static_cast<char*>(::alloca(c.encodedSize()));
Buffer wbuffer(buff, c.encodedSize());
wbuffer.put(c);
@@ -102,7 +105,7 @@ QPID_AUTO_TEST_CASE(testNestedValues)
list.push_back(List::ValuePtr(new Unsigned32Value(u)));
list.push_back(List::ValuePtr(new Str8Value("yellow")));
list.push_back(List::ValuePtr(new DoubleValue(d)));
-
+
a.setString("id", "A");
b.setString("id", "B");
a.setTable("B", b);
@@ -192,7 +195,7 @@ QPID_AUTO_TEST_CASE(test64GetAndSetConverts)
FieldTable args;
args.setInt64("a",100);
args.setInt64("b",-(int64_t) ((int64_t) 1<<34));
-
+
args.setUInt64("c",1u);
args.setUInt64("d",(uint64_t) ((uint64_t) 1<<34));
BOOST_CHECK_EQUAL(1u, args.getAsUInt64("c"));
@@ -204,5 +207,7 @@ QPID_AUTO_TEST_CASE(test64GetAndSetConverts)
BOOST_CHECK_EQUAL((int64_t) ((int64_t) 1<<34), args.getAsInt64("d"));
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/FieldValue.cpp b/qpid/cpp/src/tests/FieldValue.cpp
index 448f068107..0ebd0d7d44 100644
--- a/qpid/cpp/src/tests/FieldValue.cpp
+++ b/qpid/cpp/src/tests/FieldValue.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,6 +20,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FieldValueTestSuite)
using namespace qpid::framing;
@@ -32,7 +35,7 @@ IntegerValue i(42);
QPID_AUTO_TEST_CASE(testStr16ValueEquals)
{
-
+
BOOST_CHECK(Str16Value("abc") == s);
BOOST_CHECK(Str16Value("foo") != s);
BOOST_CHECK(s != i);
@@ -73,7 +76,7 @@ QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
BOOST_CHECK_EQUAL(std::string("FOO"),
ft.getValue().getString("foo"));
BOOST_CHECK_EQUAL(7, ft.getValue().getInt("magic"));
-
+
FieldTableValue f2;
BOOST_CHECK(ft != f2);
f2.getValue().setString("foo", "FOO");
@@ -88,3 +91,5 @@ QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
#endif
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ForkedBroker.cpp b/qpid/cpp/src/tests/ForkedBroker.cpp
index 30c346850c..e1a96c8e90 100644
--- a/qpid/cpp/src/tests/ForkedBroker.cpp
+++ b/qpid/cpp/src/tests/ForkedBroker.cpp
@@ -30,6 +30,16 @@
using namespace std;
using qpid::ErrnoException;
+namespace std {
+static ostream& operator<<(ostream& o, const qpid::tests::ForkedBroker::Args& a) {
+copy(a.begin(), a.end(), ostream_iterator<string>(o, " "));
+return o;
+}
+}
+
+namespace qpid {
+namespace tests {
+
ForkedBroker::ForkedBroker(const Args& constArgs) {
Args args(constArgs);
Args::iterator i = find(args.begin(), args.end(), string("TMP_DATA_DIR"));
@@ -71,12 +81,6 @@ void ForkedBroker::kill(int sig) {
throw qpid::Exception(QPID_MSG("Forked broker exited with: " << WEXITSTATUS(status)));
}
-namespace std {
-static ostream& operator<<(ostream& o, const ForkedBroker::Args& a) {
- copy(a.begin(), a.end(), ostream_iterator<string>(o, " "));
- return o;
-}
-
bool isLogOption(const std::string& s) {
const char * log_enable = "--log-enable",
* trace = "--trace";
@@ -85,8 +89,6 @@ bool isLogOption(const std::string& s) {
);
}
-}
-
void ForkedBroker::init(const Args& userArgs) {
using qpid::ErrnoException;
port = 0;
@@ -125,3 +127,5 @@ void ForkedBroker::init(const Args& userArgs) {
::exit(1);
}
}
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ForkedBroker.h b/qpid/cpp/src/tests/ForkedBroker.h
index 45b522068c..ddbad185d8 100644
--- a/qpid/cpp/src/tests/ForkedBroker.h
+++ b/qpid/cpp/src/tests/ForkedBroker.h
@@ -11,9 +11,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,9 +31,12 @@
#include <stdio.h>
#include <sys/wait.h>
+namespace qpid {
+namespace tests {
+
/**
* Class to fork a broker child process.
- *
+ *
* For most tests a BrokerFixture may be more convenient as it starts
* a broker in the same process which allows you to easily debug into
* the broker.
@@ -42,17 +45,17 @@
* those brokers can't coexist in the same process (e.g. for cluster
* tests where CPG doesn't allow multiple group members in a single
* process.)
- *
+ *
*/
class ForkedBroker {
public:
typedef std::vector<std::string> Args;
// argv args are passed to broker.
- //
+ //
// Special value "TMP_DATA_DIR" is substituted with a temporary
// data directory for the broker.
- //
+ //
ForkedBroker(const Args& argv);
~ForkedBroker();
@@ -70,4 +73,6 @@ class ForkedBroker {
std::string dataDir;
};
+}} // namespace qpid::tests
+
#endif /*!TESTS_FORKEDBROKER_H*/
diff --git a/qpid/cpp/src/tests/Frame.cpp b/qpid/cpp/src/tests/Frame.cpp
index 11905911fa..1270eabba3 100644
--- a/qpid/cpp/src/tests/Frame.cpp
+++ b/qpid/cpp/src/tests/Frame.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
#include <boost/lexical_cast.hpp>
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FrameTestSuite)
using namespace std;
@@ -78,3 +81,5 @@ QPID_AUTO_TEST_CASE(testLoop) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/FrameDecoder.cpp b/qpid/cpp/src/tests/FrameDecoder.cpp
index f5db66d5fe..9eeff2a41e 100644
--- a/qpid/cpp/src/tests/FrameDecoder.cpp
+++ b/qpid/cpp/src/tests/FrameDecoder.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
#include <string>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FrameDecoderTest)
using namespace std;
@@ -69,5 +72,7 @@ QPID_AUTO_TEST_CASE(testByteFragments) {
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/FramingTest.cpp b/qpid/cpp/src/tests/FramingTest.cpp
index e09ee19bc2..3d0fa0c0de 100644
--- a/qpid/cpp/src/tests/FramingTest.cpp
+++ b/qpid/cpp/src/tests/FramingTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,8 +39,11 @@ using namespace qpid;
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
template <class T>
-std::string tostring(const T& x)
+std::string tostring(const T& x)
{
std::ostringstream out;
out << x;
@@ -49,7 +52,7 @@ std::string tostring(const T& x)
QPID_AUTO_TEST_SUITE(FramingTestSuite)
-QPID_AUTO_TEST_CASE(testMessageTransferBody)
+QPID_AUTO_TEST_CASE(testMessageTransferBody)
{
char buffer[1024];
ProtocolVersion version(highestProtocolVersion);
@@ -62,8 +65,8 @@ QPID_AUTO_TEST_CASE(testMessageTransferBody)
out.decode(rbuff);
BOOST_CHECK_EQUAL(tostring(in), tostring(out));
}
-
-QPID_AUTO_TEST_CASE(testConnectionSecureBody)
+
+QPID_AUTO_TEST_CASE(testConnectionSecureBody)
{
char buffer[1024];
ProtocolVersion version(highestProtocolVersion);
@@ -88,10 +91,10 @@ QPID_AUTO_TEST_CASE(testConnectionRedirectBody)
Array hosts(0x95);
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
-
+
ConnectionRedirectBody in(version, a, hosts);
in.encode(wbuff);
-
+
Buffer rbuff(buffer, sizeof(buffer));
ConnectionRedirectBody out(version);
out.decode(rbuff);
@@ -111,7 +114,7 @@ QPID_AUTO_TEST_CASE(testQueueDeclareBody)
out.decode(rbuff);
BOOST_CHECK_EQUAL(tostring(in), tostring(out));
}
-
+
QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
{
char buffer[1024];
@@ -122,7 +125,7 @@ QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
Array hosts(0x95);
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
-
+
AMQFrame in((ConnectionRedirectBody(version, a, hosts)));
in.setChannel(999);
in.encode(wbuff);
@@ -149,3 +152,5 @@ QPID_AUTO_TEST_CASE(testMessageCancelBodyFrame)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/HeaderTest.cpp b/qpid/cpp/src/tests/HeaderTest.cpp
index 01e7c22ee6..4b16f3c793 100644
--- a/qpid/cpp/src/tests/HeaderTest.cpp
+++ b/qpid/cpp/src/tests/HeaderTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -26,9 +26,12 @@
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(HeaderTestSuite)
-QPID_AUTO_TEST_CASE(testGenericProperties)
+QPID_AUTO_TEST_CASE(testGenericProperties)
{
AMQHeaderBody body;
body.get<MessageProperties>(true)->getApplicationHeaders().setString(
@@ -47,10 +50,10 @@ QPID_AUTO_TEST_CASE(testGenericProperties)
props->getApplicationHeaders().get("A")->get<string>());
}
-QPID_AUTO_TEST_CASE(testMessageProperties)
+QPID_AUTO_TEST_CASE(testMessageProperties)
{
AMQFrame out((AMQHeaderBody()));
- MessageProperties* props1 =
+ MessageProperties* props1 =
out.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
props1->setContentLength(42);
@@ -82,10 +85,10 @@ QPID_AUTO_TEST_CASE(testMessageProperties)
}
-QPID_AUTO_TEST_CASE(testDeliveryProperies)
+QPID_AUTO_TEST_CASE(testDeliveryProperies)
{
AMQFrame out((AMQHeaderBody()));
- DeliveryProperties* props1 =
+ DeliveryProperties* props1 =
out.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
props1->setDiscardUnroutable(true);
@@ -108,3 +111,4 @@ QPID_AUTO_TEST_CASE(testDeliveryProperies)
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/HeadersExchangeTest.cpp b/qpid/cpp/src/tests/HeadersExchangeTest.cpp
index 46933f955a..40deb59c86 100644
--- a/qpid/cpp/src/tests/HeadersExchangeTest.cpp
+++ b/qpid/cpp/src/tests/HeadersExchangeTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,9 +28,12 @@
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(HeadersExchangeTestSuite)
-
-QPID_AUTO_TEST_CASE(testMatchAll)
+
+QPID_AUTO_TEST_CASE(testMatchAll)
{
FieldTable b, m, n;
b.setString("x-match", "all");
@@ -43,7 +46,7 @@ QPID_AUTO_TEST_CASE(testMatchAll)
// Ignore extras.
m.setString("extra", "x");
BOOST_CHECK(HeadersExchange::match(b, m));
-
+
// Fail mismatch, wrong value.
m.setString("foo", "NotFoo");
BOOST_CHECK(!HeadersExchange::match(b, m));
@@ -54,7 +57,7 @@ QPID_AUTO_TEST_CASE(testMatchAll)
BOOST_CHECK(!HeadersExchange::match(b, n));
}
-QPID_AUTO_TEST_CASE(testMatchAny)
+QPID_AUTO_TEST_CASE(testMatchAny)
{
FieldTable b, m, n;
b.setString("x-match", "any");
@@ -67,7 +70,7 @@ QPID_AUTO_TEST_CASE(testMatchAny)
BOOST_CHECK(HeadersExchange::match(b, m));
}
-QPID_AUTO_TEST_CASE(testMatchEmptyValue)
+QPID_AUTO_TEST_CASE(testMatchEmptyValue)
{
FieldTable b, m;
b.setString("x-match", "all");
@@ -82,23 +85,23 @@ QPID_AUTO_TEST_CASE(testMatchEmptyArgs)
{
FieldTable b, m;
m.setString("foo", "FOO");
-
+
b.setString("x-match", "all");
BOOST_CHECK(HeadersExchange::match(b, m));
b.setString("x-match", "any");
BOOST_CHECK(!HeadersExchange::match(b, m));
}
-
-QPID_AUTO_TEST_CASE(testMatchNoXMatch)
+
+QPID_AUTO_TEST_CASE(testMatchNoXMatch)
{
FieldTable b, m;
b.setString("foo", "FOO");
m.setString("foo", "FOO");
BOOST_CHECK(!HeadersExchange::match(b, m));
}
-
-QPID_AUTO_TEST_CASE(testBindNoXMatch)
+
+QPID_AUTO_TEST_CASE(testBindNoXMatch)
{
HeadersExchange exchange("test");
Queue::shared_ptr queue;
@@ -112,4 +115,6 @@ QPID_AUTO_TEST_CASE(testBindNoXMatch)
}
}
-QPID_AUTO_TEST_SUITE_END()
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/IncompleteMessageList.cpp b/qpid/cpp/src/tests/IncompleteMessageList.cpp
index e830df0e8b..303d83cd66 100644
--- a/qpid/cpp/src/tests/IncompleteMessageList.cpp
+++ b/qpid/cpp/src/tests/IncompleteMessageList.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(IncompleteMessageListTestSuite)
using namespace qpid::broker;
@@ -41,7 +44,7 @@ struct Checker
Checker(uint start, uint end) {
for (uint i = start; i <= end; i++) {
ids.push_back(i);
- }
+ }
}
Checker& expect(const SequenceNumber& id) {
@@ -49,11 +52,11 @@ struct Checker
return *this;
}
- void operator()(boost::intrusive_ptr<Message> msg) {
+ void operator()(boost::intrusive_ptr<Message> msg) {
BOOST_CHECK(!ids.empty());
BOOST_CHECK_EQUAL(msg->getCommandId(), ids.front());
ids.pop_front();
- }
+ }
};
QPID_AUTO_TEST_CASE(testProcessSimple)
@@ -91,7 +94,7 @@ QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
list.process(Checker(1, 2), false);
//mark message complete and re-process to get remaining messages sent to listener
middle->enqueueComplete();
- list.process(Checker(3, 5), false);
+ list.process(Checker(3, 5), false);
}
@@ -127,3 +130,5 @@ QPID_AUTO_TEST_CASE(testSyncProcessWithIncomplete)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/InlineAllocator.cpp b/qpid/cpp/src/tests/InlineAllocator.cpp
index fe6eaefaf4..a4c4d64cea 100644
--- a/qpid/cpp/src/tests/InlineAllocator.cpp
+++ b/qpid/cpp/src/tests/InlineAllocator.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,6 +22,9 @@
#include "qpid/InlineAllocator.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(InlineAllocatorTestSuite)
using namespace qpid;
@@ -48,16 +51,18 @@ QPID_AUTO_TEST_CASE(testAllocateFull) {
char* p = alloc.allocate(1);
BOOST_CHECK(p == (char*)&alloc);
-
+
char* q = alloc.allocate(1);
BOOST_CHECK(q != (char*)&alloc);
alloc.deallocate(p,1);
p = alloc.allocate(1);
BOOST_CHECK(p == (char*)&alloc);
-
+
alloc.deallocate(p,1);
alloc.deallocate(q,1);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/InlineVector.cpp b/qpid/cpp/src/tests/InlineVector.cpp
index 009f10af9d..ba5165886d 100644
--- a/qpid/cpp/src/tests/InlineVector.cpp
+++ b/qpid/cpp/src/tests/InlineVector.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,6 +22,9 @@
#include "qpid/InlineVector.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(InlineVectorTestSuite)
using namespace qpid;
@@ -117,7 +120,9 @@ QPID_AUTO_TEST_CASE(testAssign) {
QPID_AUTO_TEST_CASE(testResize) {
Vec v;
v.resize(5);
- BOOST_CHECK(!isInline(v));
+ BOOST_CHECK(!isInline(v));
}
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 2e04c85b93..a15ba3578c 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -270,6 +270,11 @@ check_PROGRAMS+=qrsh
qrsh_SOURCES=qrsh.cpp
qrsh_LDADD=$(lib_client)
+check_PROGRAMS+=qpid_stream
+qpid_stream_INCLUDES=$(PUBLIC_INCLUDES)
+qpid_stream_SOURCES=qpid_stream.cpp
+qpid_stream_LDADD=$(lib_client)
+
TESTS_ENVIRONMENT = \
VALGRIND=$(VALGRIND) \
diff --git a/qpid/cpp/src/tests/ManagementTest.cpp b/qpid/cpp/src/tests/ManagementTest.cpp
index e6f2e2e3fd..d05b4676ba 100644
--- a/qpid/cpp/src/tests/ManagementTest.cpp
+++ b/qpid/cpp/src/tests/ManagementTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -24,6 +24,9 @@
#include "qpid/console/ObjectId.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ManagementTestSuite)
using namespace qpid::framing;
@@ -109,4 +112,4 @@ QPID_AUTO_TEST_CASE(testConsoleObjectId) {
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/MessageBuilderTest.cpp b/qpid/cpp/src/tests/MessageBuilderTest.cpp
index 1f3f830633..c2fb8ad32e 100644
--- a/qpid/cpp/src/tests/MessageBuilderTest.cpp
+++ b/qpid/cpp/src/tests/MessageBuilderTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,15 +31,18 @@ using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
class MockMessageStore : public NullMessageStore
{
enum Op {STAGE=1, APPEND=2};
uint64_t id;
- boost::intrusive_ptr<PersistableMessage> expectedMsg;
+ boost::intrusive_ptr<PersistableMessage> expectedMsg;
string expectedData;
std::list<Op> ops;
-
+
void checkExpectation(Op actual)
{
BOOST_CHECK_EQUAL(ops.front(), actual);
@@ -49,17 +52,17 @@ class MockMessageStore : public NullMessageStore
public:
MockMessageStore() : id(0), expectedMsg(0) {}
- void expectStage(PersistableMessage& msg)
- {
+ void expectStage(PersistableMessage& msg)
+ {
expectedMsg = &msg;
- ops.push_back(STAGE);
+ ops.push_back(STAGE);
}
- void expectAppendContent(PersistableMessage& msg, const string& data)
- {
+ void expectAppendContent(PersistableMessage& msg, const string& data)
+ {
expectedMsg = &msg;
expectedData = data;
- ops.push_back(APPEND);
+ ops.push_back(APPEND);
}
void stage(const boost::intrusive_ptr<PersistableMessage>& msg)
@@ -74,7 +77,7 @@ class MockMessageStore : public NullMessageStore
{
checkExpectation(APPEND);
BOOST_CHECK_EQUAL(boost::static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
- BOOST_CHECK_EQUAL(expectedData, data);
+ BOOST_CHECK_EQUAL(expectedData, data);
}
bool expectationsMet()
@@ -89,7 +92,7 @@ class MockMessageStore : public NullMessageStore
}
};
-
+
QPID_AUTO_TEST_SUITE(MessageBuilderTestSuite)
QPID_AUTO_TEST_CASE(testHeaderOnly)
@@ -103,7 +106,7 @@ QPID_AUTO_TEST_CASE(testHeaderOnly)
AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
AMQFrame header((AMQHeaderBody()));
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -132,7 +135,7 @@ QPID_AUTO_TEST_CASE(test1ContentFrame)
header.setEof(false);
content.setBof(false);
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -143,7 +146,7 @@ QPID_AUTO_TEST_CASE(test1ContentFrame)
BOOST_CHECK(builder.getMessage());
BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
- builder.handle(content);
+ builder.handle(content);
BOOST_CHECK(builder.getMessage());
BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
}
@@ -169,7 +172,7 @@ QPID_AUTO_TEST_CASE(test2ContentFrames)
content1.setEof(false);
content2.setBof(false);
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -188,7 +191,7 @@ QPID_AUTO_TEST_CASE(testStaging)
MockMessageStore store;
MessageBuilder builder(&store, 5);
builder.start(SequenceNumber());
-
+
std::string data1("abcdefg");
std::string data2("hijklmn");
std::string exchange("builder-exchange");
@@ -199,7 +202,7 @@ QPID_AUTO_TEST_CASE(testStaging)
AMQFrame content1((AMQContentBody(data1)));
AMQFrame content2((AMQContentBody(data2)));
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -223,7 +226,7 @@ QPID_AUTO_TEST_CASE(testNoManagementStaging)
MockMessageStore store;
MessageBuilder builder(&store, 5);
builder.start(SequenceNumber());
-
+
std::string data1("abcdefg");
std::string exchange("qpid.management");
std::string key("builder-exchange");
@@ -232,7 +235,7 @@ QPID_AUTO_TEST_CASE(testNoManagementStaging)
AMQFrame header((AMQHeaderBody()));
AMQFrame content1((AMQContentBody(data1)));
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -242,4 +245,7 @@ QPID_AUTO_TEST_CASE(testNoManagementStaging)
BOOST_CHECK(store.expectationsMet());
BOOST_CHECK_EQUAL((uint64_t) 0, builder.getMessage()->getPersistenceId());
}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/MessageReplayTracker.cpp b/qpid/cpp/src/tests/MessageReplayTracker.cpp
index a5121cdeb7..3d79ee53c2 100644
--- a/qpid/cpp/src/tests/MessageReplayTracker.cpp
+++ b/qpid/cpp/src/tests/MessageReplayTracker.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
#include "qpid/client/MessageReplayTracker.h"
#include "qpid/sys/Time.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(MessageReplayTrackerTests)
using namespace qpid::client;
@@ -53,8 +56,8 @@ QPID_AUTO_TEST_CASE(testReplay)
MessageReplayTracker tracker(10);
tracker.init(fix.session);
- for (uint i = 0; i < 5; i++) {
- Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
tracker.send(message);
}
ReplayBufferChecker checker(1, 10);
@@ -62,7 +65,7 @@ QPID_AUTO_TEST_CASE(testReplay)
tracker.replay(fix.session);
for (uint j = 0; j < 2; j++) {//each message should have been sent twice
- for (uint i = 0; i < 5; i++) {
+ for (uint i = 0; i < 5; i++) {
Message m;
BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
@@ -79,15 +82,15 @@ QPID_AUTO_TEST_CASE(testCheckCompletion)
MessageReplayTracker tracker(10);
tracker.init(fix.session);
- for (uint i = 0; i < 5; i++) {
- Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
tracker.send(message);
}
fix.session.sync();//ensures all messages are complete
tracker.checkCompletion();
tracker.replay(fix.session);
Message received;
- for (uint i = 0; i < 5; i++) {
+ for (uint i = 0; i < 5; i++) {
BOOST_CHECK(fix.subs.get(received, "my-queue"));
BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), received.getData());
}
@@ -96,4 +99,4 @@ QPID_AUTO_TEST_CASE(testCheckCompletion)
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/MessageTest.cpp b/qpid/cpp/src/tests/MessageTest.cpp
index cd63f64a37..7d67c92b37 100644
--- a/qpid/cpp/src/tests/MessageTest.cpp
+++ b/qpid/cpp/src/tests/MessageTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,6 +33,9 @@
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(MessageTestSuite)
QPID_AUTO_TEST_CASE(testEncodeDecode)
@@ -56,7 +59,7 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
msg->getFrames().append(content2);
MessageProperties* mProps = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- mProps->setContentLength(data1.size() + data2.size());
+ mProps->setContentLength(data1.size() + data2.size());
mProps->setMessageId(messageId);
FieldTable applicationHeaders;
applicationHeaders.setString("abc", "xyz");
@@ -69,7 +72,7 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
char* buff = static_cast<char*>(::alloca(msg->encodedSize()));
Buffer wbuffer(buff, msg->encodedSize());
msg->encode(wbuffer);
-
+
Buffer rbuffer(buff, msg->encodedSize());
msg = new Message();
msg->decodeHeader(rbuffer);
@@ -86,3 +89,4 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/MessageUtils.h b/qpid/cpp/src/tests/MessageUtils.h
index 6a12c72007..dae74cce7d 100644
--- a/qpid/cpp/src/tests/MessageUtils.h
+++ b/qpid/cpp/src/tests/MessageUtils.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,9 +28,12 @@ using namespace qpid;
using namespace broker;
using namespace framing;
+namespace qpid {
+namespace tests {
+
struct MessageUtils
{
- static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
+ static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
const Uuid& messageId=Uuid(true), uint64_t contentSize = 0)
{
boost::intrusive_ptr<broker::Message> msg(new broker::Message());
@@ -41,7 +44,7 @@ struct MessageUtils
msg->getFrames().append(method);
msg->getFrames().append(header);
MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- props->setContentLength(contentSize);
+ props->setContentLength(contentSize);
props->setMessageId(messageId);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
return msg;
@@ -53,3 +56,5 @@ struct MessageUtils
msg->getFrames().append(content);
}
};
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp
index 6eebf717bf..f5a5420d3a 100644
--- a/qpid/cpp/src/tests/MessagingSessionTests.cpp
+++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -36,6 +36,9 @@
#include <string>
#include <vector>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(MessagingSessionTests)
using namespace qpid::messaging;
@@ -86,7 +89,7 @@ struct MessagingFixture : public BrokerFixture
Session session;
BrokerAdmin admin;
- MessagingFixture(Broker::Options opts = Broker::Options()) :
+ MessagingFixture(Broker::Options opts = Broker::Options()) :
BrokerFixture(opts),
connection(Connection::open((boost::format("amqp:tcp:localhost:%1%") % (broker->getPort(Broker::TCP_TRANSPORT))).str())),
session(connection.newSession()),
@@ -133,7 +136,7 @@ struct TopicFixture : MessagingFixture
struct MultiQueueFixture : MessagingFixture
{
- typedef std::vector<std::string>::const_iterator const_iterator;
+ typedef std::vector<std::string>::const_iterator const_iterator;
std::vector<std::string> queues;
MultiQueueFixture(const std::vector<std::string>& names = boost::assign::list_of<std::string>("q1")("q2")("q3")) : queues(names)
@@ -161,7 +164,7 @@ struct MessageDataCollector : MessageListener
}
};
-std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duration timeout=qpid::sys::TIME_SEC*5)
+std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duration timeout=qpid::sys::TIME_SEC*5)
{
std::vector<std::string> data;
Message message;
@@ -183,6 +186,25 @@ QPID_AUTO_TEST_CASE(testSimpleSendReceive)
BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
}
+QPID_AUTO_TEST_CASE(testSendReceiveHeaders)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out("test-message");
+ for (uint i = 0; i < 10; ++i) {
+ out.getHeaders()["a"] = i;
+ sender.send(out);
+ }
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in;
+ for (uint i = 0; i < 10; ++i) {
+ BOOST_CHECK(receiver.fetch(in, 5 * qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+ BOOST_CHECK_EQUAL(in.getHeaders()["a"].asUint32(), i);
+ fix.session.acknowledge();
+ }
+}
+
QPID_AUTO_TEST_CASE(testSenderError)
{
MessagingFixture fix;
@@ -229,14 +251,14 @@ QPID_AUTO_TEST_CASE(testSimpleTopic)
Message in;
BOOST_CHECK(!sub2.fetch(in, 0));//TODO: or should this raise an error?
-
+
//TODO: check pending messages...
}
QPID_AUTO_TEST_CASE(testSessionFetch)
{
MultiQueueFixture fix;
-
+
for (uint i = 0; i < fix.queues.size(); i++) {
Receiver r = fix.session.createReceiver(fix.queues[i]);
r.setCapacity(10u);
@@ -247,8 +269,8 @@ QPID_AUTO_TEST_CASE(testSessionFetch)
Sender s = fix.session.createSender(fix.queues[i]);
Message msg((boost::format("Message_%1%") % (i+1)).str());
s.send(msg);
- }
-
+ }
+
for (uint i = 0; i < fix.queues.size(); i++) {
Message msg;
BOOST_CHECK(fix.session.fetch(msg, qpid::sys::TIME_SEC));
@@ -259,7 +281,7 @@ QPID_AUTO_TEST_CASE(testSessionFetch)
QPID_AUTO_TEST_CASE(testSessionDispatch)
{
MultiQueueFixture fix;
-
+
MessageDataCollector collector;
for (uint i = 0; i < fix.queues.size(); i++) {
Receiver r = fix.session.createReceiver(fix.queues[i]);
@@ -272,10 +294,10 @@ QPID_AUTO_TEST_CASE(testSessionDispatch)
Sender s = fix.session.createSender(fix.queues[i]);
Message msg((boost::format("Message_%1%") % (i+1)).str());
s.send(msg);
- }
+ }
while (fix.session.dispatch(qpid::sys::TIME_SEC)) ;
-
+
BOOST_CHECK_EQUAL(collector.messageData, boost::assign::list_of<std::string>("Message_1")("Message_2")("Message_3"));
}
@@ -289,8 +311,7 @@ QPID_AUTO_TEST_CASE(testMapMessage)
out.getContent().asMap()["pi"] = 3.14f;
sender.send(out);
Receiver receiver = fix.session.createReceiver(fix.queue);
- Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
BOOST_CHECK_EQUAL(in.getContent().asMap()["abc"].asString(), "def");
BOOST_CHECK_EQUAL(in.getContent().asMap()["pi"].asFloat(), 3.14f);
fix.session.acknowledge();
@@ -305,12 +326,11 @@ QPID_AUTO_TEST_CASE(testListMessage)
out.getContent() << "abc";
out.getContent() << 1234;
out.getContent() << "def";
- out.getContent() << 56.789;
+ out.getContent() << 56.789;
sender.send(out);
Receiver receiver = fix.session.createReceiver(fix.queue);
- Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
- BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
- Variant::List& list = in.getContent().asList();
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ Variant::List& list = in.getContent().asList();
BOOST_CHECK_EQUAL(list.size(), out.getContent().asList().size());
BOOST_CHECK_EQUAL(list.front().asString(), "abc");
list.pop_front();
@@ -322,4 +342,100 @@ QPID_AUTO_TEST_CASE(testListMessage)
fix.session.acknowledge();
}
+QPID_AUTO_TEST_CASE(testReject)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message m1("reject-me");
+ sender.send(m1);
+ Message m2("accept-me");
+ sender.send(m2);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getBytes(), m1.getBytes());
+ fix.session.reject(in);
+ in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getBytes(), m2.getBytes());
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testAvailable)
+{
+ MultiQueueFixture fix;
+
+ Receiver r1 = fix.session.createReceiver(fix.queues[0]);
+ r1.setCapacity(100);
+ r1.start();
+
+ Receiver r2 = fix.session.createReceiver(fix.queues[1]);
+ r2.setCapacity(100);
+ r2.start();
+
+ Sender s1 = fix.session.createSender(fix.queues[0]);
+ Sender s2 = fix.session.createSender(fix.queues[1]);
+
+ for (uint i = 0; i < 10; ++i) {
+ s1.send(Message((boost::format("A_%1%") % (i+1)).str()));
+ }
+ for (uint i = 0; i < 5; ++i) {
+ s2.send(Message((boost::format("B_%1%") % (i+1)).str()));
+ }
+ qpid::sys::sleep(1);//is there any avoid an arbitrary sleep while waiting for messages to be dispatched?
+ for (uint i = 0; i < 5; ++i) {
+ BOOST_CHECK_EQUAL(fix.session.available(), 15u - 2*i);
+ BOOST_CHECK_EQUAL(r1.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(r2.available(), 5u - i);
+ BOOST_CHECK_EQUAL(r2.fetch().getBytes(), (boost::format("B_%1%") % (i+1)).str());
+ fix.session.acknowledge();
+ }
+ for (uint i = 5; i < 10; ++i) {
+ BOOST_CHECK_EQUAL(fix.session.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testPendingAck)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ sender.send(Message((boost::format("Message_%1%") % (i+1)).str()));
+ }
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ }
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u);
+ fix.session.acknowledge();
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 10u);
+ fix.session.sync();
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u);
+}
+
+QPID_AUTO_TEST_CASE(testPendingSend)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ sender.send(Message((boost::format("Message_%1%") % (i+1)).str()));
+ }
+ //Note: this test relies on 'inside knowledge' of the sender
+ //implementation and the fact that the simple test case makes it
+ //possible to predict when completion information will be sent to
+ //the client. TODO: is there a better way of testing this?
+ BOOST_CHECK_EQUAL(sender.pending(), 10u);
+ fix.session.sync();
+ BOOST_CHECK_EQUAL(sender.pending(), 0u);
+
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ }
+ fix.session.acknowledge();
+}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/PartialFailure.cpp b/qpid/cpp/src/tests/PartialFailure.cpp
index f77a1401f8..8d9970f909 100644
--- a/qpid/cpp/src/tests/PartialFailure.cpp
+++ b/qpid/cpp/src/tests/PartialFailure.cpp
@@ -31,6 +31,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/bind.hpp>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(PartialFailureTestSuite)
using namespace std;
@@ -257,3 +260,5 @@ QPID_AUTO_TEST_CASE(testPartialFailureMemberLeaves) {
#endif
#endif // FIXME aconway 2009-07-30:
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/PollableCondition.cpp b/qpid/cpp/src/tests/PollableCondition.cpp
index b5cf1b4cd2..f9b3c25c93 100644
--- a/qpid/cpp/src/tests/PollableCondition.cpp
+++ b/qpid/cpp/src/tests/PollableCondition.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,8 @@
#include "qpid/sys/Thread.h"
#include <boost/bind.hpp>
+namespace qpid {
+namespace tests {
QPID_AUTO_TEST_SUITE(PollableConditionTest)
@@ -37,7 +39,7 @@ const Duration SHORT = TIME_SEC/100;
const Duration LONG = TIME_SEC/10;
class Callback {
- public:
+ public:
enum Action { NONE, CLEAR };
Callback() : count(), action(NONE) {}
@@ -46,7 +48,7 @@ class Callback {
Mutex::ScopedLock l(lock);
++count;
switch(action) {
- case NONE: break;
+ case NONE: break;
case CLEAR: pc.clear(); break;
}
action = NONE;
@@ -62,9 +64,9 @@ class Callback {
action = a;
return wait(LONG);
}
-
+
private:
- bool wait(Duration timeout) {
+ bool wait(Duration timeout) {
int n = count;
AbsTime deadline(now(), timeout);
while (n == count && lock.wait(deadline))
@@ -83,7 +85,7 @@ QPID_AUTO_TEST_CASE(testPollableCondition) {
PollableCondition pc(boost::bind(&Callback::call, &callback, _1), poller);
Thread runner = Thread(*poller);
-
+
BOOST_CHECK(callback.isNotCalling()); // condition is not set.
pc.set();
@@ -104,4 +106,4 @@ QPID_AUTO_TEST_CASE(testPollableCondition) {
QPID_AUTO_TEST_SUITE_END()
-
+}} //namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ProxyTest.cpp b/qpid/cpp/src/tests/ProxyTest.cpp
index 4ea10f7be9..a926b28395 100644
--- a/qpid/cpp/src/tests/ProxyTest.cpp
+++ b/qpid/cpp/src/tests/ProxyTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ProxyTestSuite)
@@ -47,5 +50,7 @@ QPID_AUTO_TEST_CASE(testScopedSync)
Proxy::ScopedSync s(p);
p.send(ExecutionSyncBody(p.getVersion()));
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueueEvents.cpp b/qpid/cpp/src/tests/QueueEvents.cpp
index cd9439355e..bd18fa45fb 100644
--- a/qpid/cpp/src/tests/QueueEvents.cpp
+++ b/qpid/cpp/src/tests/QueueEvents.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,6 +31,9 @@
#include <boost/bind.hpp>
#include <boost/format.hpp>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueueEventsSuite)
using namespace qpid::client;
@@ -156,7 +159,7 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing)
fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
//send and consume some messages
LocalQueue incoming;
- Subscription sub = fixture.subs.subscribe(incoming, q);
+ Subscription sub = fixture.subs.subscribe(incoming, q);
for (int i = 0; i < 5; i++) {
fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
}
@@ -177,7 +180,7 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing)
SequenceNumber dequeueId(1);
for (int i = 0; i < 5; i++) {
listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
+ }
for (int i = 0; i < 3; i++) {
listener.checkDequeue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), dequeueId++);
}
@@ -203,7 +206,7 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly)
fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
//send and consume some messages
LocalQueue incoming;
- Subscription sub = fixture.subs.subscribe(incoming, q);
+ Subscription sub = fixture.subs.subscribe(incoming, q);
for (int i = 0; i < 5; i++) {
fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
}
@@ -224,7 +227,7 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly)
SequenceNumber dequeueId(1);
for (int i = 0; i < 5; i++) {
listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
+ }
for (int i = 5; i < 10; i++) {
listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
}
@@ -232,4 +235,4 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly)
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueueOptionsTest.cpp b/qpid/cpp/src/tests/QueueOptionsTest.cpp
index 93d1961caa..f2fbaba2c1 100644
--- a/qpid/cpp/src/tests/QueueOptionsTest.cpp
+++ b/qpid/cpp/src/tests/QueueOptionsTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,14 +27,17 @@
using namespace qpid::client;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueueOptionsTestSuite)
QPID_AUTO_TEST_CASE(testSizePolicy)
{
QueueOptions ft;
-
+
ft.setSizePolicy(REJECT,1,2);
-
+
BOOST_CHECK(QueueOptions::strREJECT == ft.getAsString(QueueOptions::strTypeKey));
BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
@@ -49,7 +52,7 @@ QPID_AUTO_TEST_CASE(testSizePolicy)
ft.setSizePolicy(RING_STRICT,1,0);
BOOST_CHECK(QueueOptions::strRING_STRICT == ft.getAsString(QueueOptions::strTypeKey));
-
+
ft.clearSizePolicy();
BOOST_CHECK(!ft.isSet(QueueOptions::strTypeKey));
BOOST_CHECK(!ft.isSet(QueueOptions::strMaxSizeKey));
@@ -59,13 +62,13 @@ QPID_AUTO_TEST_CASE(testSizePolicy)
QPID_AUTO_TEST_CASE(testFlags)
{
QueueOptions ft;
-
+
ft.setPersistLastNode();
ft.setOrdering(LVQ);
-
+
BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strPersistLastNode));
BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strLastValueQueue));
-
+
ft.clearPersistLastNode();
ft.setOrdering(FIFO);
@@ -78,8 +81,8 @@ QPID_AUTO_TEST_CASE(testSetOrdering)
{
//ensure setOrdering(FIFO) works even if not preceded by a call to
//setOrdering(LVQ)
- QueueOptions ft;
- ft.setOrdering(FIFO);
+ QueueOptions ft;
+ ft.setOrdering(FIFO);
BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
}
@@ -88,10 +91,12 @@ QPID_AUTO_TEST_CASE(testClearPersistLastNode)
{
//ensure clear works even if not preceded by the setting on the
//option
- QueueOptions ft;
+ QueueOptions ft;
ft.clearPersistLastNode();
BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueuePolicyTest.cpp b/qpid/cpp/src/tests/QueuePolicyTest.cpp
index 7c7f8b7a10..f40d30b588 100644
--- a/qpid/cpp/src/tests/QueuePolicyTest.cpp
+++ b/qpid/cpp/src/tests/QueuePolicyTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -32,6 +32,9 @@ using namespace qpid::broker;
using namespace qpid::client;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite)
QueuedMessage createMessage(uint32_t size)
@@ -50,11 +53,11 @@ QPID_AUTO_TEST_CASE(testCount)
BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
QueuedMessage msg = createMessage(10);
- for (size_t i = 0; i < 5; i++) {
+ for (size_t i = 0; i < 5; i++) {
policy->tryEnqueue(msg);
}
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg);
BOOST_FAIL("Policy did not fail on enqueuing sixth message");
} catch (const ResourceLimitExceededException&) {}
@@ -62,7 +65,7 @@ QPID_AUTO_TEST_CASE(testCount)
policy->tryEnqueue(msg);
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg);
BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
} catch (const ResourceLimitExceededException&) {}
}
@@ -71,12 +74,12 @@ QPID_AUTO_TEST_CASE(testSize)
{
std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(0, 50));
QueuedMessage msg = createMessage(10);
-
- for (size_t i = 0; i < 5; i++) {
+
+ for (size_t i = 0; i < 5; i++) {
policy->tryEnqueue(msg);
}
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg);
BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
} catch (const ResourceLimitExceededException&) {}
@@ -84,7 +87,7 @@ QPID_AUTO_TEST_CASE(testSize)
policy->tryEnqueue(msg);
try {
- policy->tryEnqueue(msg);
+ policy->tryEnqueue(msg);
BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
} catch (const ResourceLimitExceededException&) {}
}
@@ -104,7 +107,7 @@ QPID_AUTO_TEST_CASE(testBoth)
messages.push_back(createMessage(11));
messages.push_back(createMessage(2));
messages.push_back(createMessage(7));
- for (size_t i = 0; i < messages.size(); i++) {
+ for (size_t i = 0; i < messages.size(); i++) {
policy->tryEnqueue(messages[i]);
}
//size = 45 at this point, count = 5
@@ -140,7 +143,7 @@ QPID_AUTO_TEST_CASE(testSettings)
BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
}
-QPID_AUTO_TEST_CASE(testRingPolicy)
+QPID_AUTO_TEST_CASE(testRingPolicy)
{
FieldTable args;
std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING);
@@ -169,7 +172,7 @@ QPID_AUTO_TEST_CASE(testRingPolicy)
BOOST_CHECK(!f.subs.get(msg, q));
}
-QPID_AUTO_TEST_CASE(testStrictRingPolicy)
+QPID_AUTO_TEST_CASE(testStrictRingPolicy)
{
FieldTable args;
std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING_STRICT);
@@ -181,7 +184,7 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy)
LocalQueue incoming;
SubscriptionSettings settings(FlowControl::unlimited());
settings.autoAck = 0; // no auto ack.
- Subscription sub = f.subs.subscribe(incoming, q, settings);
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
for (int i = 0; i < 5; i++) {
f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
}
@@ -192,10 +195,10 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy)
ScopedSuppressLogging sl; // Suppress messages for expected errors.
f.session.messageTransfer(arg::content=client::Message("Message_6", q));
BOOST_FAIL("expecting ResourceLimitExceededException.");
- } catch (const ResourceLimitExceededException&) {}
+ } catch (const ResourceLimitExceededException&) {}
}
-QPID_AUTO_TEST_CASE(testPolicyWithDtx)
+QPID_AUTO_TEST_CASE(testPolicyWithDtx)
{
FieldTable args;
std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::REJECT);
@@ -207,7 +210,7 @@ QPID_AUTO_TEST_CASE(testPolicyWithDtx)
LocalQueue incoming;
SubscriptionSettings settings(FlowControl::unlimited());
settings.autoAck = 0; // no auto ack.
- Subscription sub = f.subs.subscribe(incoming, q, settings);
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
f.session.dtxSelect();
Xid tx1(1, "test-dtx-mgr", "tx1");
f.session.dtxStart(arg::xid=tx1);
@@ -244,7 +247,7 @@ QPID_AUTO_TEST_CASE(testPolicyWithDtx)
ScopedSuppressLogging sl; // Suppress messages for expected errors.
other.messageTransfer(arg::content=client::Message("Message_6", q));
BOOST_FAIL("expecting ResourceLimitExceededException.");
- } catch (const ResourceLimitExceededException&) {}
+ } catch (const ResourceLimitExceededException&) {}
f.session.dtxCommit(arg::xid=tx3);
//now retry and this time should succeed
@@ -252,7 +255,7 @@ QPID_AUTO_TEST_CASE(testPolicyWithDtx)
other.messageTransfer(arg::content=client::Message("Message_6", q));
}
-QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
+QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
{
//Ensure that with no store loaded, we don't flow to disk but
//fallback to rejecting messages
@@ -265,7 +268,7 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
LocalQueue incoming;
SubscriptionSettings settings(FlowControl::unlimited());
settings.autoAck = 0; // no auto ack.
- Subscription sub = f.subs.subscribe(incoming, q, settings);
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
for (int i = 0; i < 5; i++) {
f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
}
@@ -276,8 +279,10 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
ScopedSuppressLogging sl; // Suppress messages for expected errors.
f.session.messageTransfer(arg::content=client::Message("Message_6", q));
BOOST_FAIL("expecting ResourceLimitExceededException.");
- } catch (const ResourceLimitExceededException&) {}
+ } catch (const ResourceLimitExceededException&) {}
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueueRegistryTest.cpp b/qpid/cpp/src/tests/QueueRegistryTest.cpp
index 7ad4e0b89d..712cb568c3 100644
--- a/qpid/cpp/src/tests/QueueRegistryTest.cpp
+++ b/qpid/cpp/src/tests/QueueRegistryTest.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
using namespace qpid::broker;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueueRegistryTest)
QPID_AUTO_TEST_CASE(testDeclare)
@@ -49,7 +52,7 @@ QPID_AUTO_TEST_CASE(testDeclare)
BOOST_CHECK_EQUAL(bar, q->getName());
}
-QPID_AUTO_TEST_CASE(testDeclareTmp)
+QPID_AUTO_TEST_CASE(testDeclareTmp)
{
QueueRegistry reg;
std::pair<Queue::shared_ptr, bool> qc;
@@ -58,8 +61,8 @@ QPID_AUTO_TEST_CASE(testDeclareTmp)
BOOST_CHECK(qc.second);
BOOST_CHECK_EQUAL(std::string("tmp_1"), qc.first->getName());
}
-
-QPID_AUTO_TEST_CASE(testFind)
+
+QPID_AUTO_TEST_CASE(testFind)
{
std::string foo("foo");
std::string bar("bar");
@@ -75,7 +78,7 @@ QPID_AUTO_TEST_CASE(testFind)
BOOST_CHECK_EQUAL(bar, q->getName());
}
-QPID_AUTO_TEST_CASE(testDestroy)
+QPID_AUTO_TEST_CASE(testDestroy)
{
std::string foo("foo");
QueueRegistry reg;
@@ -92,3 +95,5 @@ QPID_AUTO_TEST_CASE(testDestroy)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/QueueTest.cpp b/qpid/cpp/src/tests/QueueTest.cpp
index b70afa52a7..841a19f7c1 100644
--- a/qpid/cpp/src/tests/QueueTest.cpp
+++ b/qpid/cpp/src/tests/QueueTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,9 +39,12 @@ using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
class TestConsumer : public virtual Consumer{
public:
- typedef boost::shared_ptr<TestConsumer> shared_ptr;
+ typedef boost::shared_ptr<TestConsumer> shared_ptr;
intrusive_ptr<Message> last;
bool received;
@@ -82,68 +85,68 @@ QPID_AUTO_TEST_SUITE(QueueTestSuite)
QPID_AUTO_TEST_CASE(testAsyncMessage) {
Queue::shared_ptr queue(new Queue("my_test_queue", true));
intrusive_ptr<Message> received;
-
+
TestConsumer::shared_ptr c1(new TestConsumer());
queue->consume(c1);
-
-
+
+
//Test basic delivery:
intrusive_ptr<Message> msg1 = create_message("e", "A");
msg1->enqueueAsync(queue, 0);//this is done on enqueue which is not called from process
queue->process(msg1);
sleep(2);
-
+
BOOST_CHECK(!c1->received);
msg1->enqueueComplete();
-
+
received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg1.get(), received.get());
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
}
-
-
+
+
QPID_AUTO_TEST_CASE(testAsyncMessageCount){
Queue::shared_ptr queue(new Queue("my_test_queue", true));
intrusive_ptr<Message> msg1 = create_message("e", "A");
msg1->enqueueAsync(queue, 0);//this is done on enqueue which is not called from process
-
+
queue->process(msg1);
sleep(2);
uint32_t compval=0;
BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
msg1->enqueueComplete();
compval=1;
- BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
}
QPID_AUTO_TEST_CASE(testConsumers){
Queue::shared_ptr queue(new Queue("my_queue", true));
-
+
//Test adding consumers:
TestConsumer::shared_ptr c1(new TestConsumer());
TestConsumer::shared_ptr c2(new TestConsumer());
queue->consume(c1);
queue->consume(c2);
-
+
BOOST_CHECK_EQUAL(uint32_t(2), queue->getConsumerCount());
-
+
//Test basic delivery:
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "B");
intrusive_ptr<Message> msg3 = create_message("e", "C");
-
+
queue->deliver(msg1);
BOOST_CHECK(queue->dispatch(c1));
BOOST_CHECK_EQUAL(msg1.get(), c1->last.get());
-
+
queue->deliver(msg2);
BOOST_CHECK(queue->dispatch(c2));
BOOST_CHECK_EQUAL(msg2.get(), c2->last.get());
-
+
c1->received = false;
queue->deliver(msg3);
BOOST_CHECK(queue->dispatch(c1));
- BOOST_CHECK_EQUAL(msg3.get(), c1->last.get());
-
+ BOOST_CHECK_EQUAL(msg3.get(), c1->last.get());
+
//Test cancellation:
queue->cancel(c1);
BOOST_CHECK_EQUAL(uint32_t(1), queue->getConsumerCount());
@@ -157,15 +160,15 @@ QPID_AUTO_TEST_CASE(testRegistry){
registry.declare("queue1", true, true);
registry.declare("queue2", true, true);
registry.declare("queue3", true, true);
-
+
BOOST_CHECK(registry.find("queue1"));
BOOST_CHECK(registry.find("queue2"));
BOOST_CHECK(registry.find("queue3"));
-
+
registry.destroy("queue1");
registry.destroy("queue2");
registry.destroy("queue3");
-
+
BOOST_CHECK(!registry.find("queue1"));
BOOST_CHECK(!registry.find("queue2"));
BOOST_CHECK(!registry.find("queue3"));
@@ -177,13 +180,13 @@ QPID_AUTO_TEST_CASE(testDequeue){
intrusive_ptr<Message> msg2 = create_message("e", "B");
intrusive_ptr<Message> msg3 = create_message("e", "C");
intrusive_ptr<Message> received;
-
+
queue->deliver(msg1);
queue->deliver(msg2);
queue->deliver(msg3);
-
+
BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount());
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg1.get(), received.get());
BOOST_CHECK_EQUAL(uint32_t(2), queue->getMessageCount());
@@ -204,7 +207,7 @@ QPID_AUTO_TEST_CASE(testDequeue){
received = queue->get().payload;
BOOST_CHECK(!received);
BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
-
+
}
QPID_AUTO_TEST_CASE(testBound)
@@ -236,7 +239,7 @@ QPID_AUTO_TEST_CASE(testBound)
queue->unbind(exchanges, queue);
//ensure the remaining exchanges don't still have the queue bound to them:
- FailOnDeliver deliverable;
+ FailOnDeliver deliverable;
exchange1->route(deliverable, key, &args);
exchange3->route(deliverable, key, &args);
}
@@ -245,10 +248,10 @@ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
client::QueueOptions args;
args.setPersistLastNode();
-
+
Queue::shared_ptr queue(new Queue("my-queue", true));
queue->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "B");
intrusive_ptr<Message> msg3 = create_message("e", "C");
@@ -256,13 +259,13 @@ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
//enqueue 2 messages
queue->deliver(msg1);
queue->deliver(msg2);
-
+
//change mode
queue->setLastNodeFailure();
-
+
//enqueue 1 message
queue->deliver(msg3);
-
+
//check all have persistent ids.
BOOST_CHECK(msg1->isPersistent());
BOOST_CHECK(msg2->isPersistent());
@@ -277,7 +280,7 @@ class TestMessageStoreOC : public NullMessageStore
uint enqCnt;
uint deqCnt;
bool error;
-
+
virtual void dequeue(TransactionContext*,
const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
const PersistableQueue& /*queue*/)
@@ -298,7 +301,7 @@ class TestMessageStoreOC : public NullMessageStore
{
error=true;
}
-
+
TestMessageStoreOC() : NullMessageStore(),enqCnt(0),deqCnt(0),error(false) {}
~TestMessageStoreOC(){}
};
@@ -312,7 +315,7 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){
Queue::shared_ptr queue(new Queue("my-queue", true ));
queue->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "B");
intrusive_ptr<Message> msg3 = create_message("e", "C");
@@ -324,27 +327,27 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){
string key;
args.getLVQKey(key);
BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
+
msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
-
+
//enqueue 4 message
queue->deliver(msg1);
queue->deliver(msg2);
queue->deliver(msg3);
queue->deliver(msg4);
-
+
BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg4.get(), received.get());
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg2.get(), received.get());
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg3.get(), received.get());
@@ -357,18 +360,18 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){
queue->deliver(msg5);
queue->deliver(msg6);
queue->deliver(msg7);
-
+
BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg5.get(), received.get());
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg6.get(), received.get());
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg7.get(), received.get());
-
+
}
QPID_AUTO_TEST_CASE(testLVQEmptyKey){
@@ -379,20 +382,20 @@ QPID_AUTO_TEST_CASE(testLVQEmptyKey){
Queue::shared_ptr queue(new Queue("my-queue", true ));
queue->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "B");
string key;
args.getLVQKey(key);
BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
+
msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
queue->deliver(msg1);
queue->deliver(msg2);
BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
-
+
}
QPID_AUTO_TEST_CASE(testLVQAcquire){
@@ -403,7 +406,7 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){
Queue::shared_ptr queue(new Queue("my-queue", true ));
queue->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "B");
intrusive_ptr<Message> msg3 = create_message("e", "C");
@@ -416,7 +419,7 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){
string key;
args.getLVQKey(key);
BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
+
msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
@@ -424,13 +427,13 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){
msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
-
+
//enqueue 4 message
queue->deliver(msg1);
queue->deliver(msg2);
queue->deliver(msg3);
queue->deliver(msg4);
-
+
BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
framing::SequenceNumber sequence(1);
@@ -439,9 +442,9 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){
BOOST_CHECK(!queue->acquire(qmsg));
BOOST_CHECK(queue->acquire(qmsg2));
-
+
BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
-
+
queue->deliver(msg5);
BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
@@ -449,11 +452,11 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){
args.setOrdering(client::LVQ_NO_BROWSE);
queue->configure(args);
TestConsumer::shared_ptr c1(new TestConsumer(false));
-
+
queue->dispatch(c1);
queue->dispatch(c1);
queue->dispatch(c1);
-
+
queue->deliver(msg6);
BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
@@ -474,7 +477,7 @@ QPID_AUTO_TEST_CASE(testLVQMultiQueue){
intrusive_ptr<Message> received;
queue1->configure(args);
queue2->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "A");
@@ -484,17 +487,17 @@ QPID_AUTO_TEST_CASE(testLVQMultiQueue){
msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
-
+
queue1->deliver(msg1);
queue2->deliver(msg1);
queue1->deliver(msg2);
-
+
received = queue1->get().payload;
BOOST_CHECK_EQUAL(msg2.get(), received.get());
received = queue2->get().payload;
BOOST_CHECK_EQUAL(msg1.get(), received.get());
-
+
}
QPID_AUTO_TEST_CASE(testLVQRecover){
@@ -518,7 +521,7 @@ QPID_AUTO_TEST_CASE(testLVQRecover){
Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
intrusive_ptr<Message> received;
queue1->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
intrusive_ptr<Message> msg2 = create_message("e", "A");
// 2
@@ -544,7 +547,7 @@ QPID_AUTO_TEST_CASE(testLVQRecover){
BOOST_CHECK_EQUAL(testStore.deqCnt, 1u);
}
-void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
+void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
{
for (uint i = 0; i < count; i++) {
intrusive_ptr<Message> m = create_message("exchange", "key");
@@ -592,7 +595,7 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
queue1->configure(args);
Queue::shared_ptr queue2(new Queue("queue2", true, &testStore ));
queue2->configure(args);
-
+
intrusive_ptr<Message> msg1 = create_message("e", "A");
queue1->deliver(msg1);
@@ -623,7 +626,7 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
// check no failure messages are stored
queue1->clearLastNodeFailure();
queue2->clearLastNodeFailure();
-
+
intrusive_ptr<Message> msg3 = create_message("e", "B");
queue1->deliver(msg3);
queue2->deliver(msg3);
@@ -631,7 +634,7 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
queue1->setLastNodeFailure();
queue2->setLastNodeFailure();
BOOST_CHECK_EQUAL(testStore.enqCnt, 6u);
-
+
// check requeue 1
intrusive_ptr<Message> msg4 = create_message("e", "C");
intrusive_ptr<Message> msg5 = create_message("e", "D");
@@ -639,17 +642,17 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
framing::SequenceNumber sequence(1);
QueuedMessage qmsg1(queue1.get(), msg4, sequence);
QueuedMessage qmsg2(queue2.get(), msg5, ++sequence);
-
+
queue1->requeue(qmsg1);
BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
-
+
// check requeue 2
queue2->clearLastNodeFailure();
queue2->requeue(qmsg2);
BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
queue2->setLastNodeFailure();
BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
-
+
queue2->clearLastNodeFailure();
queue2->setLastNodeFailure();
BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
@@ -664,8 +667,8 @@ simulate this:
4. stop and recover remaining node
5. add another node
6. kill that new node again
-make sure that an attempt to re-enqueue a message does not happen which will
-result in the last man standing exiting with an error.
+make sure that an attempt to re-enqueue a message does not happen which will
+result in the last man standing exiting with an error.
we need to make sure that recover is safe, i.e. messages are
not requeued to the store.
@@ -678,7 +681,7 @@ not requeued to the store.
Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
intrusive_ptr<Message> received;
queue1->configure(args);
-
+
// check requeue 1
intrusive_ptr<Message> msg1 = create_message("e", "C");
intrusive_ptr<Message> msg2 = create_message("e", "D");
@@ -711,17 +714,29 @@ simulate store excption going into last node standing
Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
intrusive_ptr<Message> received;
queue1->configure(args);
-
+
// check requeue 1
intrusive_ptr<Message> msg1 = create_message("e", "C");
queue1->deliver(msg1);
testStore.createError();
-
+
ScopedSuppressLogging sl; // Suppress messages for expected errors.
queue1->setLastNodeFailure();
BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
-}QPID_AUTO_TEST_SUITE_END()
+}
+
+intrusive_ptr<Message> mkMsg(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/RangeSet.cpp b/qpid/cpp/src/tests/RangeSet.cpp
index 9c602de78d..db3a964086 100644
--- a/qpid/cpp/src/tests/RangeSet.cpp
+++ b/qpid/cpp/src/tests/RangeSet.cpp
@@ -24,6 +24,9 @@
using namespace std;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(RangeSetTestSuite)
typedef qpid::Range<int> TestRange;
@@ -44,8 +47,8 @@ QPID_AUTO_TEST_CASE(testRangeSetAddPoint) {
BOOST_CHECK_MESSAGE(r.contains(TestRange(3,4)), r);
BOOST_CHECK(!r.empty());
r += 5;
- BOOST_CHECK_MESSAGE(r.contains(5), r);
- BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
+ BOOST_CHECK_MESSAGE(r.contains(5), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
BOOST_CHECK_MESSAGE(!r.contains(TestRange(3,6)), r);
r += 4;
BOOST_CHECK_MESSAGE(r.contains(TestRange(3,6)), r);
@@ -139,3 +142,5 @@ QPID_AUTO_TEST_CASE(testRangeContaining) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/RateFlowcontrolTest.cpp b/qpid/cpp/src/tests/RateFlowcontrolTest.cpp
index b8fda09f61..80ad06af8c 100644
--- a/qpid/cpp/src/tests/RateFlowcontrolTest.cpp
+++ b/qpid/cpp/src/tests/RateFlowcontrolTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,25 +27,28 @@
using namespace qpid::broker;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(RateFlowcontrolTestSuite)
QPID_AUTO_TEST_CASE(RateFlowcontrolTest)
{
// BOOST_CHECK(predicate);
// BOOST_CHECK_EQUAL(a, b);
-
+
RateFlowcontrol fc(100);
AbsTime n=AbsTime::now();
-
+
BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 0U );
-
+
fc.sentCredit(n, 0);
-
+
BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 0U );
fc.sentCredit(n, 50);
Duration d=250*TIME_MSEC;
-
+
n = AbsTime(n,d);
BOOST_CHECK_EQUAL( fc.receivedMessage(n, 25), 0U );
BOOST_CHECK_EQUAL( fc.availableCredit(n), 25U );
@@ -64,3 +67,5 @@ QPID_AUTO_TEST_CASE(RateFlowcontrolTest)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/RefCounted.cpp b/qpid/cpp/src/tests/RefCounted.cpp
index 8c679a3d2e..e4c1da5696 100644
--- a/qpid/cpp/src/tests/RefCounted.cpp
+++ b/qpid/cpp/src/tests/RefCounted.cpp
@@ -27,6 +27,9 @@ using boost::intrusive_ptr;
using namespace std;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
struct CountMe : public RefCounted {
static int instances;
CountMe() { ++instances; }
@@ -48,3 +51,5 @@ QPID_AUTO_TEST_CASE(testRefCounted) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/ReplicationTest.cpp b/qpid/cpp/src/tests/ReplicationTest.cpp
index 38dc1a9e52..ed768f1306 100644
--- a/qpid/cpp/src/tests/ReplicationTest.cpp
+++ b/qpid/cpp/src/tests/ReplicationTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -42,6 +42,9 @@ using namespace qpid::framing;
using namespace qpid::replication::constants;
using boost::assign::list_of;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ReplicationTestSuite)
// The CMake-based build passes in the module suffix; if it's not there, this
@@ -63,7 +66,7 @@ qpid::broker::Broker::Options getBrokerOpts(const std::vector<std::string>& args
return opts;
}
-QPID_AUTO_TEST_CASE(testReplicationExchange)
+QPID_AUTO_TEST_CASE(testReplicationExchange)
{
qpid::broker::Broker::Options brokerOpts(getBrokerOpts(list_of<string>("qpidd")
("--replication-exchange-name=qpid.replication")));
@@ -79,7 +82,7 @@ QPID_AUTO_TEST_CASE(testReplicationExchange)
f.session.queueDeclare(arg::queue=eventQ, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ, arg::bindingKey=dataQ);
-
+
f.session.queueDeclare(arg::queue=eventQ2, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ2, arg::bindingKey=dataQ2);
@@ -133,3 +136,5 @@ QPID_AUTO_TEST_CASE(testReplicationExchange)
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/RetryList.cpp b/qpid/cpp/src/tests/RetryList.cpp
index 80f59bf15f..d1d22348a3 100644
--- a/qpid/cpp/src/tests/RetryList.cpp
+++ b/qpid/cpp/src/tests/RetryList.cpp
@@ -24,6 +24,9 @@
using namespace qpid;
using namespace qpid::broker;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(RetryListTestSuite)
struct RetryListFixture
@@ -36,7 +39,7 @@ struct RetryListFixture
{
urls.push_back(Url(s));
}
-
+
void addExpectation(const std::string& host, uint16_t port)
{
expected.push_back(TcpAddress(host, port));
@@ -57,7 +60,7 @@ struct RetryListFixture
}
};
-QPID_AUTO_TEST_CASE(testWithSingleAddress)
+QPID_AUTO_TEST_CASE(testWithSingleAddress)
{
RetryListFixture test;
test.addUrl("amqp:host:5673");
@@ -65,7 +68,7 @@ QPID_AUTO_TEST_CASE(testWithSingleAddress)
test.check();
}
-QPID_AUTO_TEST_CASE(testWithSingleUrlOfMultipleAddresses)
+QPID_AUTO_TEST_CASE(testWithSingleUrlOfMultipleAddresses)
{
RetryListFixture test;
test.addUrl("amqp:host1,host2:2222,tcp:host3:5673,host4:1");
@@ -78,7 +81,7 @@ QPID_AUTO_TEST_CASE(testWithSingleUrlOfMultipleAddresses)
test.check();
}
-QPID_AUTO_TEST_CASE(testWithMultipleUrlsOfMultipleAddresses)
+QPID_AUTO_TEST_CASE(testWithMultipleUrlsOfMultipleAddresses)
{
RetryListFixture test;
test.addUrl("amqp:my-host");
@@ -97,10 +100,12 @@ QPID_AUTO_TEST_CASE(testWithMultipleUrlsOfMultipleAddresses)
test.check();
}
-QPID_AUTO_TEST_CASE(testEmptyList)
+QPID_AUTO_TEST_CASE(testEmptyList)
{
RetryListFixture test;
test.check();
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/SequenceNumberTest.cpp b/qpid/cpp/src/tests/SequenceNumberTest.cpp
index e4c6d066ef..f3c934e3ca 100644
--- a/qpid/cpp/src/tests/SequenceNumberTest.cpp
+++ b/qpid/cpp/src/tests/SequenceNumberTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -26,6 +26,8 @@
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
void checkDifference(SequenceNumber& a, SequenceNumber& b, int gap)
{
@@ -54,7 +56,7 @@ void checkComparison(SequenceNumber& a, SequenceNumber& b, int gap)
BOOST_CHECK(++a < ++b);//test prefix
}
//keep incrementing until a also wraps around
- for (int i = 0; i < (gap + 2); i++) {
+ for (int i = 0; i < (gap + 2); i++) {
BOOST_CHECK(a++ < b++);//test postfix
}
//let a 'catch up'
@@ -91,7 +93,7 @@ QPID_AUTO_TEST_CASE(testIncrementPostfix)
BOOST_CHECK(b != c);
}
-QPID_AUTO_TEST_CASE(testIncrementPrefix)
+QPID_AUTO_TEST_CASE(testIncrementPrefix)
{
SequenceNumber a;
SequenceNumber b;
@@ -203,3 +205,5 @@ QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround2)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/SequenceSet.cpp b/qpid/cpp/src/tests/SequenceSet.cpp
index ba2f1391a1..aaeb68e3c5 100644
--- a/qpid/cpp/src/tests/SequenceSet.cpp
+++ b/qpid/cpp/src/tests/SequenceSet.cpp
@@ -20,6 +20,9 @@
#include "unit_test.h"
#include <list>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(SequenceSetTestSuite)
using namespace qpid::framing;
@@ -72,7 +75,7 @@ QPID_AUTO_TEST_CASE(testAdd) {
BOOST_CHECK(!s.contains(i));
RangeExpectations().expect(2, 5).expect(8, 8).check(s);
-
+
SequenceSet t;
t.add(6, 10);
t.add(s);
@@ -90,7 +93,7 @@ QPID_AUTO_TEST_CASE(testAdd2) {
SequenceSet s;
s.add(7,6);
s.add(4,4);
- s.add(3,10);
+ s.add(3,10);
s.add(2);
RangeExpectations().expect(2, 10).check(s);
}
@@ -137,4 +140,4 @@ QPID_AUTO_TEST_CASE(testRemove) {
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/SessionState.cpp b/qpid/cpp/src/tests/SessionState.cpp
index 5e21ff2b70..157cabfb63 100644
--- a/qpid/cpp/src/tests/SessionState.cpp
+++ b/qpid/cpp/src/tests/SessionState.cpp
@@ -28,6 +28,9 @@
#include <functional>
#include <numeric>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(SessionStateTestSuite)
using namespace std;
@@ -94,7 +97,7 @@ size_t transfer1(qpid::SessionState& s, string content) {
size_t transfer1Char(qpid::SessionState& s, char content) {
return transfer1(s, string(1,content));
}
-
+
// Send transfer frame with multiple single-byte content frames.
size_t transferN(qpid::SessionState& s, string content) {
size_t size=send(s, transferFrame(!content.empty()));
@@ -134,7 +137,7 @@ QPID_AUTO_TEST_CASE(testSendGetReplyList) {
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))),"CabcCdCeCfCxyz");
// Ignore controls.
s.senderRecord(AMQFrame(new SessionFlushBody()));
- BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
}
QPID_AUTO_TEST_CASE(testNeedFlush) {
@@ -185,7 +188,7 @@ QPID_AUTO_TEST_CASE(testPeerConfirmed) {
s.senderConfirmed(SessionPoint(5));
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(5,0))), "CxCy");
BOOST_CHECK(s.senderNeedFlush());
-
+
s.senderConfirmed(SessionPoint(6));
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(6,0))), "Cy");
BOOST_CHECK(!s.senderNeedFlush());
@@ -195,7 +198,7 @@ QPID_AUTO_TEST_CASE(testPeerCompleted) {
qpid::SessionState s;
s.setTimeout(1);
s.senderGetCommandPoint();
- // Completion implies confirmation
+ // Completion implies confirmation
transfers(s, "abc");
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCc");
SequenceSet set(SequenceSet() + 0 + 1);
@@ -205,7 +208,7 @@ QPID_AUTO_TEST_CASE(testPeerCompleted) {
transfers(s, "def");
// We dont do out-of-order confirmation, so this will only confirm up to 3:
set = SequenceSet(SequenceSet() + 2 + 3 + 5);
- s.senderCompleted(set);
+ s.senderCompleted(set);
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CeCf");
}
@@ -215,11 +218,11 @@ QPID_AUTO_TEST_CASE(testReceive) {
s.receiverSetCommandPoint(SessionPoint());
BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(0));
BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(0));
-
+
BOOST_CHECK(s.receiverRecord(transferFrame(false)));
BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(1));
BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(1));
-
+
BOOST_CHECK(s.receiverRecord(transferFrame(true)));
SessionPoint point = SessionPoint(1, transferFrameSize());
BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
@@ -297,3 +300,5 @@ QPID_AUTO_TEST_CASE(testNeedKnownCompleted) {
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Shlib.cpp b/qpid/cpp/src/tests/Shlib.cpp
index 7d2f2456c7..692cfcdff9 100644
--- a/qpid/cpp/src/tests/Shlib.cpp
+++ b/qpid/cpp/src/tests/Shlib.cpp
@@ -24,6 +24,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ShlibTestSuite)
using namespace qpid::sys;
@@ -51,7 +54,7 @@ QPID_AUTO_TEST_CASE(testShlib) {
}
catch (const qpid::Exception&) {}
}
-
+
QPID_AUTO_TEST_CASE(testAutoShlib) {
int unloaded = 0;
{
@@ -66,6 +69,8 @@ QPID_AUTO_TEST_CASE(testAutoShlib) {
}
BOOST_CHECK_EQUAL(42, unloaded);
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/SocketProxy.h b/qpid/cpp/src/tests/SocketProxy.h
index ccce3c8842..9df32a1336 100644
--- a/qpid/cpp/src/tests/SocketProxy.h
+++ b/qpid/cpp/src/tests/SocketProxy.h
@@ -35,8 +35,11 @@
#include "qpid/sys/Mutex.h"
#include "qpid/log/Statement.h"
+namespace qpid {
+namespace tests {
+
/**
- * A simple socket proxy that forwards to another socket.
+ * A simple socket proxy that forwards to another socket.
* Used between client & local broker to simulate network failures.
*/
class SocketProxy : private qpid::sys::Runnable
@@ -59,7 +62,7 @@ class SocketProxy : private qpid::sys::Runnable
joined = false;
thread = qpid::sys::Thread(static_cast<qpid::sys::Runnable*>(this));
}
-
+
~SocketProxy() { close(); if (!joined) thread.join(); }
/** Simulate a network disconnect. */
@@ -88,7 +91,7 @@ class SocketProxy : private qpid::sys::Runnable
}
uint16_t getPort() const { return port; }
-
+
private:
static void throwErrno(const std::string& msg) {
throw qpid::Exception(msg+":"+qpid::sys::strError(errno));
@@ -153,7 +156,7 @@ class SocketProxy : private qpid::sys::Runnable
}
try {
if (server.get()) server->close();
- close();
+ close();
}
catch (const std::exception& e) {
QPID_LOG(debug, "SocketProxy::run exception in client/server close()" << e.what());
@@ -169,4 +172,6 @@ class SocketProxy : private qpid::sys::Runnable
bool dropClient, dropServer;
};
+}} // namespace qpid::tests
+
#endif
diff --git a/qpid/cpp/src/tests/TestMessageStore.h b/qpid/cpp/src/tests/TestMessageStore.h
index be1ed57349..20e0b755b2 100644
--- a/qpid/cpp/src/tests/TestMessageStore.h
+++ b/qpid/cpp/src/tests/TestMessageStore.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@ using namespace qpid;
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
typedef std::pair<string, boost::intrusive_ptr<PersistableMessage> > msg_queue_pair;
class TestMessageStore : public NullMessageStore
@@ -35,7 +38,7 @@ class TestMessageStore : public NullMessageStore
public:
std::vector<boost::intrusive_ptr<PersistableMessage> > dequeued;
std::vector<msg_queue_pair> enqueued;
-
+
void dequeue(TransactionContext*,
const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& /*queue*/)
@@ -47,7 +50,7 @@ class TestMessageStore : public NullMessageStore
const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& queue)
{
- msg->enqueueComplete();
+ msg->enqueueComplete();
enqueued.push_back(msg_queue_pair(queue.getName(), msg));
}
@@ -55,4 +58,6 @@ class TestMessageStore : public NullMessageStore
~TestMessageStore(){}
};
+}} // namespace qpid::tests
+
#endif
diff --git a/qpid/cpp/src/tests/TestOptions.h b/qpid/cpp/src/tests/TestOptions.h
index a400fe5ecb..f8da0f59cf 100644
--- a/qpid/cpp/src/tests/TestOptions.h
+++ b/qpid/cpp/src/tests/TestOptions.h
@@ -9,9 +9,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -67,7 +67,7 @@ struct TestOptions : public qpid::Options
connection.open(con);
}
-
+
bool help;
ConnectionOptions con;
qpid::log::Options log;
diff --git a/qpid/cpp/src/tests/TimerTest.cpp b/qpid/cpp/src/tests/TimerTest.cpp
index 2642c980ba..1552421ba0 100644
--- a/qpid/cpp/src/tests/TimerTest.cpp
+++ b/qpid/cpp/src/tests/TimerTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -32,6 +32,9 @@ using namespace qpid::sys;
using boost::intrusive_ptr;
using boost::dynamic_pointer_cast;
+namespace qpid {
+namespace tests {
+
class Counter
{
Mutex lock;
@@ -44,7 +47,7 @@ class Counter
return ++counter;
}
};
-
+
class TestTask : public TimerTask
{
const AbsTime start;
@@ -56,7 +59,7 @@ class TestTask : public TimerTask
Counter& counter;
public:
- TestTask(Duration timeout, Counter& _counter)
+ TestTask(Duration timeout, Counter& _counter)
: TimerTask(timeout), start(now()), expected(timeout), end(start), fired(false), counter(_counter) {}
void fire()
@@ -106,14 +109,14 @@ QPID_AUTO_TEST_CASE(testGeneral)
intrusive_ptr<TestTask> task2(new TestTask(Duration(1 * TIME_SEC), counter));
intrusive_ptr<TestTask> task3(new TestTask(Duration(4 * TIME_SEC), counter));
intrusive_ptr<TestTask> task4(new TestTask(Duration(2 * TIME_SEC), counter));
-
+
timer.add(task1);
timer.add(task2);
timer.add(task3);
timer.add(task4);
-
+
dynamic_pointer_cast<TestTask>(task3)->wait(Duration(6 * TIME_SEC));
-
+
dynamic_pointer_cast<TestTask>(task1)->check(3);
dynamic_pointer_cast<TestTask>(task2)->check(1);
dynamic_pointer_cast<TestTask>(task3)->check(4);
@@ -121,3 +124,5 @@ QPID_AUTO_TEST_CASE(testGeneral)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/TopicExchangeTest.cpp b/qpid/cpp/src/tests/TopicExchangeTest.cpp
index d707066534..c103620dbf 100644
--- a/qpid/cpp/src/tests/TopicExchangeTest.cpp
+++ b/qpid/cpp/src/tests/TopicExchangeTest.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,11 +22,15 @@
using namespace qpid::broker;
using namespace std;
+
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(TopicExchangeTestSuite)
#define CHECK_NORMALIZED(expect, pattern) BOOST_CHECK_EQUAL(expect, TopicExchange::normalize(pattern));
-QPID_AUTO_TEST_CASE(testNormalize)
+QPID_AUTO_TEST_CASE(testNormalize)
{
CHECK_NORMALIZED("", "");
CHECK_NORMALIZED("a.b.c", "a.b.c");
@@ -38,8 +42,8 @@ QPID_AUTO_TEST_CASE(testNormalize)
CHECK_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*");
CHECK_NORMALIZED("*.*.*.#", "*.#.#.*.*.#");
}
-
-QPID_AUTO_TEST_CASE(testPlain)
+
+QPID_AUTO_TEST_CASE(testPlain)
{
string pattern("ab.cd.e");
BOOST_CHECK(TopicExchange::match(pattern, "ab.cd.e"));
@@ -57,7 +61,7 @@ QPID_AUTO_TEST_CASE(testPlain)
}
-QPID_AUTO_TEST_CASE(testStar)
+QPID_AUTO_TEST_CASE(testStar)
{
string pattern("a.*.b");
BOOST_CHECK(TopicExchange::match(pattern, "a.xx.b"));
@@ -75,7 +79,7 @@ QPID_AUTO_TEST_CASE(testStar)
BOOST_CHECK(!TopicExchange::match(pattern, "q.x.y"));
}
-QPID_AUTO_TEST_CASE(testHash)
+QPID_AUTO_TEST_CASE(testHash)
{
string pattern("a.#.b");
BOOST_CHECK(TopicExchange::match(pattern, "a.b"));
@@ -99,7 +103,7 @@ QPID_AUTO_TEST_CASE(testHash)
BOOST_CHECK(TopicExchange::match(pattern, "a.x.x.b.y.y.c"));
}
-QPID_AUTO_TEST_CASE(testMixed)
+QPID_AUTO_TEST_CASE(testMixed)
{
string pattern("*.x.#.y");
BOOST_CHECK(TopicExchange::match(pattern, "a.x.y"));
@@ -119,3 +123,5 @@ QPID_AUTO_TEST_CASE(testMixed)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/TxBufferTest.cpp b/qpid/cpp/src/tests/TxBufferTest.cpp
index 3d6a12cacc..4807026ab7 100644
--- a/qpid/cpp/src/tests/TxBufferTest.cpp
+++ b/qpid/cpp/src/tests/TxBufferTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
using namespace qpid::broker;
using boost::static_pointer_cast;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(TxBufferTestSuite)
QPID_AUTO_TEST_CASE(testCommitLocal)
@@ -174,3 +177,5 @@ QPID_AUTO_TEST_CASE(testBufferIsClearedAfterCommit)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/TxMocks.h b/qpid/cpp/src/tests/TxMocks.h
index fe103c5fe5..a34d864bae 100644
--- a/qpid/cpp/src/tests/TxMocks.h
+++ b/qpid/cpp/src/tests/TxMocks.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -32,6 +32,9 @@ using namespace qpid::broker;
using boost::static_pointer_cast;
using std::string;
+namespace qpid {
+namespace tests {
+
template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){
unsigned int i = 0;
while(i < expected.size() && i < actual.size()){
@@ -62,15 +65,15 @@ class MockTxOp : public TxOp, public TxOpConstants{
string debugName;
public:
typedef boost::shared_ptr<MockTxOp> shared_ptr;
-
+
MockTxOp() : failOnPrepare(false) {}
MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {}
-
+
void setDebugName(string name){
debugName = name;
}
- void printExpected(){
+ void printExpected(){
std::cout << std::endl << "MockTxOp[" << debugName << "] expects: ";
for (std::vector<string>::iterator i = expected.begin(); i < expected.end(); i++) {
if(i != expected.begin()) std::cout << ", ";
@@ -79,7 +82,7 @@ public:
std::cout << std::endl;
}
- void printActual(){
+ void printActual(){
std::cout << std::endl << "MockTxOp[" << debugName << "] actual: ";
for (std::vector<string>::iterator i = actual.begin(); i < actual.end(); i++) {
if(i != actual.begin()) std::cout << ", ";
@@ -87,7 +90,7 @@ public:
}
std::cout << std::endl;
}
-
+
bool prepare(TransactionContext*) throw(){
actual.push_back(PREPARE);
return !failOnPrepare;
@@ -116,8 +119,8 @@ public:
}
void accept(TxOpConstVisitor&) const {}
-
- ~MockTxOp(){}
+
+ ~MockTxOp(){}
};
class MockTransactionalStore : public TransactionalStore{
@@ -128,10 +131,10 @@ class MockTransactionalStore : public TransactionalStore{
const string ABORT;
std::vector<string> expected;
std::vector<string> actual;
-
+
enum states {OPEN = 1, PREPARED = 2, COMMITTED = 3, ABORTED = 4};
int state;
-
+
class TestTransactionContext : public TPCTransactionContext{
MockTransactionalStore* store;
public:
@@ -145,29 +148,29 @@ class MockTransactionalStore : public TransactionalStore{
if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
store->state = COMMITTED;
}
-
+
void abort(){
if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
store->state = ABORTED;
}
~TestTransactionContext(){}
};
-
+
public:
MockTransactionalStore() :
BEGIN("BEGIN"), BEGIN2PC("BEGIN2PC"), PREPARE("PREPARE"), COMMIT("COMMIT"), ABORT("ABORT"), state(OPEN){}
void collectPreparedXids(std::set<std::string>&)
{
- throw "Operation not supported";
+ throw "Operation not supported";
}
-
- std::auto_ptr<TPCTransactionContext> begin(const std::string&){
+
+ std::auto_ptr<TPCTransactionContext> begin(const std::string&){
actual.push_back(BEGIN2PC);
std::auto_ptr<TPCTransactionContext> txn(new TestTransactionContext(this));
return txn;
}
- std::auto_ptr<TransactionContext> begin(){
+ std::auto_ptr<TransactionContext> begin(){
actual.push_back(BEGIN);
std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this));
return txn;
@@ -183,7 +186,7 @@ public:
void abort(TransactionContext& ctxt){
actual.push_back(ABORT);
dynamic_cast<TestTransactionContext&>(ctxt).abort();
- }
+ }
MockTransactionalStore& expectBegin(){
expected.push_back(BEGIN);
return *this;
@@ -207,23 +210,25 @@ public:
void check(){
assertEqualVector(expected, actual);
}
-
+
bool isPrepared(){
return state == PREPARED;
}
-
+
bool isCommitted(){
return state == COMMITTED;
}
-
+
bool isAborted(){
return state == ABORTED;
}
-
+
bool isOpen() const{
return state == OPEN;
}
~MockTransactionalStore(){}
};
+}} // namespace qpid::tests
+
#endif
diff --git a/qpid/cpp/src/tests/TxPublishTest.cpp b/qpid/cpp/src/tests/TxPublishTest.cpp
index 63dbf99266..fabb01b864 100644
--- a/qpid/cpp/src/tests/TxPublishTest.cpp
+++ b/qpid/cpp/src/tests/TxPublishTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -35,30 +35,33 @@ using boost::intrusive_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
struct TxPublishTest
{
-
+
TestMessageStore store;
Queue::shared_ptr queue1;
Queue::shared_ptr queue2;
intrusive_ptr<Message> msg;
TxPublish op;
-
+
TxPublishTest() :
- queue1(new Queue("queue1", false, &store, 0)),
- queue2(new Queue("queue2", false, &store, 0)),
+ queue1(new Queue("queue1", false, &store, 0)),
+ queue2(new Queue("queue2", false, &store, 0)),
msg(MessageUtils::createMessage("exchange", "routing_key", "id")),
op(msg)
{
msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
op.deliverTo(queue1);
op.deliverTo(queue2);
- }
+ }
};
QPID_AUTO_TEST_SUITE(TxPublishTestSuite)
-
+
QPID_AUTO_TEST_CASE(testPrepare)
{
TxPublishTest t;
@@ -88,7 +91,9 @@ QPID_AUTO_TEST_CASE(testCommit)
BOOST_CHECK_EQUAL(t.msg, msg_dequeue);
BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount());
- BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
+ BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Url.cpp b/qpid/cpp/src/tests/Url.cpp
index f3b42a7208..343186eb1f 100644
--- a/qpid/cpp/src/tests/Url.cpp
+++ b/qpid/cpp/src/tests/Url.cpp
@@ -26,6 +26,9 @@ using namespace std;
using namespace qpid;
using namespace boost::assign;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(UrlTestSuite)
#define URL_CHECK_STR(STR) BOOST_CHECK_EQUAL(Url(STR).str(), STR)
@@ -65,3 +68,5 @@ QPID_AUTO_TEST_CASE(TestInvalidAddress) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Uuid.cpp b/qpid/cpp/src/tests/Uuid.cpp
index ea2e80b63b..a6ddb9b5a5 100644
--- a/qpid/cpp/src/tests/Uuid.cpp
+++ b/qpid/cpp/src/tests/Uuid.cpp
@@ -24,6 +24,9 @@
#include <set>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(UuidTestSuite)
using namespace std;
@@ -77,3 +80,5 @@ QPID_AUTO_TEST_CASE(testUuidEncodeDecode) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/Variant.cpp b/qpid/cpp/src/tests/Variant.cpp
index 1bf2ed98ce..2d68bb842c 100644
--- a/qpid/cpp/src/tests/Variant.cpp
+++ b/qpid/cpp/src/tests/Variant.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,6 +25,9 @@
using namespace qpid::messaging;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(VariantSuite)
QPID_AUTO_TEST_CASE(testConversions)
@@ -87,20 +90,20 @@ QPID_AUTO_TEST_CASE(testAssignment)
{
Variant value("abc");
Variant other = value;
- BOOST_CHECK_EQUAL(STRING, value.getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, value.getType());
BOOST_CHECK_EQUAL(other.getType(), value.getType());
BOOST_CHECK_EQUAL(other.asString(), value.asString());
const uint32_t i(1000);
value = i;
- BOOST_CHECK_EQUAL(UINT32, value.getType());
- BOOST_CHECK_EQUAL(STRING, other.getType());
+ BOOST_CHECK_EQUAL(VAR_UINT32, value.getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, other.getType());
}
QPID_AUTO_TEST_CASE(testList)
-{
+{
const std::string s("abc");
- const float f(9.876);
+ const float f(9.876f);
const int16_t x(1000);
Variant value = Variant::List();
@@ -108,20 +111,20 @@ QPID_AUTO_TEST_CASE(testList)
value.asList().push_back(Variant(f));
value.asList().push_back(Variant(x));
BOOST_CHECK_EQUAL(3u, value.asList().size());
- Variant::List::const_iterator i = value.asList().begin();
+ Variant::List::const_iterator i = value.asList().begin();
BOOST_CHECK(i != value.asList().end());
- BOOST_CHECK_EQUAL(STRING, i->getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, i->getType());
BOOST_CHECK_EQUAL(s, i->asString());
i++;
BOOST_CHECK(i != value.asList().end());
- BOOST_CHECK_EQUAL(FLOAT, i->getType());
+ BOOST_CHECK_EQUAL(VAR_FLOAT, i->getType());
BOOST_CHECK_EQUAL(f, i->asFloat());
i++;
BOOST_CHECK(i != value.asList().end());
- BOOST_CHECK_EQUAL(INT16, i->getType());
+ BOOST_CHECK_EQUAL(VAR_INT16, i->getType());
BOOST_CHECK_EQUAL(x, i->asInt16());
i++;
@@ -129,9 +132,9 @@ QPID_AUTO_TEST_CASE(testList)
}
QPID_AUTO_TEST_CASE(testMap)
-{
+{
const std::string red("red");
- const float pi(3.14);
+ const float pi(3.14f);
const int16_t x(1000);
Variant value = Variant::Map();
@@ -140,18 +143,20 @@ QPID_AUTO_TEST_CASE(testMap)
value.asMap()["my-key"] = x;
BOOST_CHECK_EQUAL(3u, value.asMap().size());
- BOOST_CHECK_EQUAL(STRING, value.asMap()["colour"].getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["colour"].getType());
BOOST_CHECK_EQUAL(red, value.asMap()["colour"].asString());
- BOOST_CHECK_EQUAL(FLOAT, value.asMap()["pi"].getType());
+ BOOST_CHECK_EQUAL(VAR_FLOAT, value.asMap()["pi"].getType());
BOOST_CHECK_EQUAL(pi, value.asMap()["pi"].asFloat());
-
- BOOST_CHECK_EQUAL(INT16, value.asMap()["my-key"].getType());
+
+ BOOST_CHECK_EQUAL(VAR_INT16, value.asMap()["my-key"].getType());
BOOST_CHECK_EQUAL(x, value.asMap()["my-key"].asInt16());
value.asMap()["my-key"] = "now it's a string";
- BOOST_CHECK_EQUAL(STRING, value.asMap()["my-key"].getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["my-key"].getType());
BOOST_CHECK_EQUAL(std::string("now it's a string"), value.asMap()["my-key"].asString());
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/XmlClientSessionTest.cpp b/qpid/cpp/src/tests/XmlClientSessionTest.cpp
index b6b8520bd8..46a4c826a3 100644
--- a/qpid/cpp/src/tests/XmlClientSessionTest.cpp
+++ b/qpid/cpp/src/tests/XmlClientSessionTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,6 +39,9 @@
#include <vector>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(XmlClientSessionTest)
using namespace qpid::client;
@@ -118,10 +121,10 @@ QPID_AUTO_TEST_CASE(testXmlBinding) {
FieldTable binding;
binding.setString("xquery", "declare variable $color external;"
"(./message/id mod 2 = 1) and ($color = 'blue')");
- f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
+ f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
Message message;
- message.getDeliveryProperties().setRoutingKey("query_name");
+ message.getDeliveryProperties().setRoutingKey("query_name");
message.getHeaders().setString("color", "blue");
string m = "<message><id>1</id></message>";
@@ -130,7 +133,7 @@ QPID_AUTO_TEST_CASE(testXmlBinding) {
f.session.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="xml");
Message m2 = localQueue.get();
- BOOST_CHECK_EQUAL(m, m2.getData());
+ BOOST_CHECK_EQUAL(m, m2.getData());
}
/**
@@ -146,10 +149,10 @@ QPID_AUTO_TEST_CASE(testXMLBindMultipleQueues) {
FieldTable blue;
blue.setString("xquery", "./colour = 'blue'");
- f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-colour", arg::arguments=blue);
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-colour", arg::arguments=blue);
FieldTable red;
red.setString("xquery", "./colour = 'red'");
- f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-colour", arg::arguments=red);
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-colour", arg::arguments=red);
Message sent1("<colour>blue</colour>", "by-colour");
f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
@@ -223,3 +226,4 @@ olour", arg::arguments=blue);
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index b62288a769..fc53d2ce8b 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -61,7 +61,7 @@ class ACLTests(TestBase010):
# ACL general tests
#=====================================
- def test_deny_all(self):
+ def test_deny_mode(self):
"""
Test the deny all mode
"""
@@ -71,7 +71,9 @@ class ACLTests(TestBase010):
aclf.write('acl deny all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
try:
@@ -87,7 +89,7 @@ class ACLTests(TestBase010):
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
- def test_allow_all(self):
+ def test_allow_mode(self):
"""
Test the allow all mode
"""
@@ -96,7 +98,9 @@ class ACLTests(TestBase010):
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
try:
@@ -124,7 +128,9 @@ class ACLTests(TestBase010):
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
try:
@@ -208,9 +214,9 @@ class ACLTests(TestBase010):
# ACL queue tests
#=====================================
- def test_queue_acl(self):
+ def test_queue_allow_mode(self):
"""
- Test various modes for queue acl
+ Test cases for queue acl in allow mode
"""
aclf = ACLFile()
aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n')
@@ -221,27 +227,35 @@ class ACLTests(TestBase010):
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q1", durable='true', passive='true')
+ session.queue_declare(queue="q1", durable=True, passive=True)
self.fail("ACL should deny queue create request with name=q1 durable=true passive=true");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q2", exclusive='true')
+ session.queue_declare(queue="q2", exclusive=True)
self.fail("ACL should deny queue create request with name=q2 exclusive=true");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue="q3", exclusive='true')
- session.queue_declare(queue="q4", durable='true')
+ session.queue_declare(queue="q2", durable=True)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q2 with any parameter other than exclusive=true");
+
+ try:
+ session.queue_declare(queue="q3", exclusive=True)
+ session.queue_declare(queue="q4", durable=True)
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
self.fail("ACL should allow queue create request for q3 and q4 with any parameter");
@@ -279,57 +293,185 @@ class ACLTests(TestBase010):
if (530 == e.args[0].error_code):
self.fail("ACL should allow queue delete request for q3");
+
+ def test_queue_deny_mode(self):
+ """
+ Test cases for queue acl in deny mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID create queue name=q1 durable=true passive=true\n')
+ aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true\n')
+ aclf.write('acl allow bob@QPID access queue name=q3\n')
+ aclf.write('acl allow bob@QPID purge queue name=q3\n')
+ aclf.write('acl allow bob@QPID create queue name=q3\n')
+ aclf.write('acl allow bob@QPID create queue name=q4\n')
+ aclf.write('acl allow bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow guest@QPID all all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q1", durable=True, passive=True)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q1 durable=true passive=true");
+
+ try:
+ session.queue_declare(queue="q1", durable=False, passive=False)
+ self.fail("ACL should deny queue create request with name=q1 durable=true passive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q2", exclusive=False)
+ self.fail("ACL should deny queue create request with name=q2 exclusive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q2", exclusive=True)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q2 with exclusive=true");
+
+ try:
+ session.queue_declare(queue="q3")
+ session.queue_declare(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q3 and q4");
+
+ try:
+ session.queue_query(queue="q4")
+ self.fail("ACL should deny queue query request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q4")
+ self.fail("ACL should deny queue purge request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue purge request for q3");
+
+ try:
+ session.queue_query(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue query request for q3");
+
+ try:
+ session.queue_delete(queue="q3")
+ self.fail("ACL should deny queue delete request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_delete(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue delete request for q4");
+
#=====================================
# ACL exchange tests
#=====================================
- def test_exchange_acl(self):
+ def test_exchange_acl_allow_mode(self):
+ session = self.get_session('bob','bob')
+ session.queue_declare(queue="baz")
+
"""
- Test various modes for exchange acl
+ Test cases for exchange acl in allow mode
"""
aclf = ACLFile()
aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n')
aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n')
- aclf.write('acl deny bob@QPID access exchange name=myEx\n')
+ aclf.write('acl deny bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n')
aclf.write('acl deny bob@QPID bind exchange name=myEx queuename=q1 routingkey=rk1\n')
aclf.write('acl deny bob@QPID unbind exchange name=myEx queuename=q1 routingkey=rk1\n')
- aclf.write('acl deny bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl deny bob@QPID delete exchange name=myEx\n')
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
-
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.exchange_declare(exchange='myEx', type='direct')
+
try:
- session.exchange_declare(exchange='testEx', durable='true', passive='true')
+ session.exchange_declare(exchange='testEx', durable=True, passive=True)
self.fail("ACL should deny exchange create request with name=testEx durable=true passive=true");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
+ session.exchange_declare(exchange='testEx', type='direct', durable=True, passive=False)
+ except qpid.session.SessionException, e:
+ print e
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for testEx with any parameter other than durable=true and passive=true");
+
+ try:
session.exchange_declare(exchange='ex1', type='direct')
self.fail("ACL should deny exchange create request with name=ex1 type=direct");
- except qpid.session.SessionException, e:
+ except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
session.exchange_declare(exchange='myXml', type='direct')
- session.queue_declare(queue='q1')
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
self.fail("ACL should allow exchange create request for myXml with any parameter");
try:
session.exchange_query(name='myEx')
- self.fail("ACL should deny queue query request for q3");
+ self.fail("ACL should deny exchange query request for myEx");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk1.*')
+ self.fail("ACL should deny exchange bound request for myEx with queuename=q1 and routing_key='rk1.*' ");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='amq.topic')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange query request for exchange='amq.topic'");
try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk2.*')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bound request for myEx with queuename=q1 and binding_key='rk2.*'");
+
+ try:
session.exchange_bind(exchange='myEx', queue='q1', binding_key='rk1')
self.fail("ACL should deny exchange bind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
except qpid.session.SessionException, e:
@@ -337,10 +479,17 @@ class ACLTests(TestBase010):
session = self.get_session('bob','bob')
try:
- session.exchange_bind(exchange='myXml', queue='q1', binding_key='x')
+ session.exchange_bind(exchange='myEx', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='myEx', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q2', binding_key='rk1')
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow exchange bind request for exchange='myXml', queue='q1', binding_key='x'");
+ self.fail("ACL should allow exchange bind request for exchange='myEx', queue='q2', binding_key='rk1'");
+
try:
session.exchange_unbind(exchange='myEx', queue='q1', binding_key='rk1')
self.fail("ACL should deny exchange unbind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
@@ -349,10 +498,16 @@ class ACLTests(TestBase010):
session = self.get_session('bob','bob')
try:
- session.exchange_unbind(exchange='myXml', queue='q1', binding_key='x')
+ session.exchange_unbind(exchange='myEx', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='myEx', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q2', binding_key='rk1')
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow exchange unbind request for exchange='myXml', queue='q1', binding_key='x'");
+ self.fail("ACL should allow exchange unbind request for exchange='myEx', queue='q2', binding_key='rk1'");
try:
session.exchange_delete(exchange='myEx')
@@ -366,45 +521,161 @@ class ACLTests(TestBase010):
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
self.fail("ACL should allow exchange delete request for myXml");
-
+
+
+ def test_exchange_acl_deny_mode(self):
+ session = self.get_session('bob','bob')
+ session.queue_declare(queue='bar')
+
+ """
+ Test cases for exchange acl in deny mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID create exchange name=myEx durable=true passive=false\n')
+ aclf.write('acl allow bob@QPID bind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
+ aclf.write('acl allow bob@QPID unbind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
+ aclf.write('acl allow bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n')
+ aclf.write('acl allow bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl allow guest@QPID all all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=True, passive=False)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myEx with durable=true and passive=false");
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
+ self.fail("ACL should deny exchange create request with name=myEx durable=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='bar', binding_key='foo.bar')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='amq.topic', queue='bar', binding_key='foor.bar'");
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='baz', binding_key='foo.bar')
+ self.fail("ACL should deny exchange bind request for exchange='amq.topic', queue='baz', binding_key='foo.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='bar', binding_key='fooz.bar')
+ self.fail("ACL should deny exchange bind request for exchange='amq.topic', queue='bar', binding_key='fooz.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='bar', binding_key='foo.bar')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='amq.topic', queue='bar', binding_key='foor.bar'");
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='baz', binding_key='foo.bar')
+ self.fail("ACL should deny exchange unbind request for exchange='amq.topic', queue='baz', binding_key='foo.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='bar', binding_key='fooz.bar')
+ self.fail("ACL should deny exchange unbind request for exchange='amq.topic', queue='bar', binding_key='fooz.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='amq.topic')
+ self.fail("ACL should deny exchange query request for amq.topic");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk2.*')
+ self.fail("ACL should deny exchange bound request for amq.topic with queuename=q1 and routing_key='rk2.*' ");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='myEx')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange query request for exchange='myEx'");
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk1.*')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bound request for myEx with queuename=q1 and binding_key='rk1.*'");
+
+ try:
+ session.exchange_delete(exchange='myXml')
+ self.fail("ACL should deny exchange delete request for myXml");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_delete(exchange='myEx')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange delete request for myEx");
+
#=====================================
# ACL consume tests
#=====================================
- def test_consume_acl(self):
+ def test_consume_allow_mode(self):
"""
- Test various consume acl
+ Test cases for consume in allow mode
"""
aclf = ACLFile()
- aclf.write('acl deny bob@QPID consume queue name=q1 durable=true\n')
- aclf.write('acl deny bob@QPID consume queue name=q2 exclusive=true\n')
+ aclf.write('acl deny bob@QPID consume queue name=q1\n')
+ aclf.write('acl deny bob@QPID consume queue name=q2\n')
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
try:
- session.queue_declare(queue='q1', durable='true')
- session.queue_declare(queue='q2', exclusive='true')
- session.queue_declare(queue='q3', durable='true')
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.queue_declare(queue='q3')
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
self.fail("ACL should allow create queue request");
try:
session.message_subscribe(queue='q1', destination='myq1')
- self.fail("ACL should deny message subscriber request for queue='q1'");
+ self.fail("ACL should deny subscription for queue='q1'");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
try:
session.message_subscribe(queue='q2', destination='myq1')
- self.fail("ACL should deny message subscriber request for queue='q2'");
+ self.fail("ACL should deny subscription for queue='q2'");
except qpid.session.SessionException, e:
self.assertEqual(530,e.args[0].error_code)
session = self.get_session('bob','bob')
@@ -413,9 +684,51 @@ class ACLTests(TestBase010):
session.message_subscribe(queue='q3', destination='myq1')
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
- self.fail("ACL should allow create message subscribe");
+ self.fail("ACL should allow subscription for q3");
+ def test_consume_deny_mode(self):
+ """
+ Test cases for consume in allow mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID consume queue name=q1\n')
+ aclf.write('acl allow bob@QPID consume queue name=q2\n')
+ aclf.write('acl allow bob@QPID create queue\n')
+ aclf.write('acl allow guest@QPID all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+
+ try:
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.queue_declare(queue='q3')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create queue request");
+
+ try:
+ session.message_subscribe(queue='q1', destination='myq1')
+ session.message_subscribe(queue='q2', destination='myq2')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow subscription for q1 and q2");
+
+ try:
+ session.message_subscribe(queue='q3', destination='myq3')
+ self.fail("ACL should deny subscription for queue='q3'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+
#=====================================
# ACL publish tests
#=====================================
@@ -431,15 +744,11 @@ class ACLTests(TestBase010):
aclf.write('acl allow all all')
aclf.close()
- self.reload_acl()
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
session = self.get_session('bob','bob')
-
- try:
- session.exchange_declare(exchange='myEx', type='topic')
- except qpid.session.SessionException, e:
- if (530 == e.args[0].error_code):
- self.fail("ACL should allow exchange create request for myEx with any parameter");
props = session.delivery_properties(routing_key="rk1")
@@ -458,6 +767,7 @@ class ACLTests(TestBase010):
session = self.get_session('bob','bob')
try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
session.message_transfer(destination="myEx", message=Message(props,"Test"))
except qpid.session.SessionException, e:
if (530 == e.args[0].error_code):
diff --git a/qpid/cpp/src/tests/client_test.cpp b/qpid/cpp/src/tests/client_test.cpp
index 05b42f620c..2f5e8e5afe 100644
--- a/qpid/cpp/src/tests/client_test.cpp
+++ b/qpid/cpp/src/tests/client_test.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -40,13 +40,16 @@ using namespace qpid::client;
using namespace qpid::framing;
using std::string;
+namespace qpid {
+namespace tests {
+
struct Args : public TestOptions {
uint msgSize;
bool verbose;
Args() : TestOptions("Simple test of Qpid c++ client; sends and receives a single message."), msgSize(26)
{
- addOptions()
+ addOptions()
("size", optValue(msgSize, "N"), "message size")
("verbose", optValue(verbose), "print out some status messages");
}
@@ -58,7 +61,7 @@ std::string generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -78,6 +81,10 @@ void print(const std::string& text, const Message& msg)
std::cout << std::endl;
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
@@ -92,7 +99,7 @@ int main(int argc, char** argv)
//Create and open a session on the connection through which
//most functionality is exposed:
Session session = connection.newSession();
- if (opts.verbose) std::cout << "Opened session." << std::endl;
+ if (opts.verbose) std::cout << "Opened session." << std::endl;
//'declare' the exchange and the queue, which will create them
@@ -116,13 +123,13 @@ int main(int argc, char** argv)
// Using the SubscriptionManager, get the message from the queue.
SubscriptionManager subs(session);
Message msgIn = subs.get("MyQueue");
- if (msgIn.getData() == msgOut.getData())
+ if (msgIn.getData() == msgOut.getData())
if (opts.verbose) std::cout << "Received the exepected message." << std::endl;
//close the session & connection
session.close();
if (opts.verbose) std::cout << "Closed session." << std::endl;
- connection.close();
+ connection.close();
if (opts.verbose) std::cout << "Closed connection." << std::endl;
return 0;
} catch(const std::exception& e) {
diff --git a/qpid/cpp/src/tests/cluster_python_tests_failing.txt b/qpid/cpp/src/tests/cluster_python_tests_failing.txt
index 337fb4a0f2..53b609942d 100644
--- a/qpid/cpp/src/tests/cluster_python_tests_failing.txt
+++ b/qpid/cpp/src/tests/cluster_python_tests_failing.txt
@@ -1,4 +1,5 @@
tests_0-10.management.ManagementTest.test_purge_queue
+tests_0-10.management.ManagementTest.test_connection_close
tests_0-10.dtx.DtxTests.test_bad_resume
tests_0-10.dtx.DtxTests.test_commit_unknown
tests_0-10.dtx.DtxTests.test_end
diff --git a/qpid/cpp/src/tests/cluster_test.cpp b/qpid/cpp/src/tests/cluster_test.cpp
index 50ca241b5d..28fcdd13ad 100644
--- a/qpid/cpp/src/tests/cluster_test.cpp
+++ b/qpid/cpp/src/tests/cluster_test.cpp
@@ -59,8 +59,6 @@ template <class T>
ostream& operator<<(ostream& o, const std::set<T>& s) { return seqPrint(o, s); }
}
-QPID_AUTO_TEST_SUITE(cluster_test)
-
using namespace std;
using namespace qpid;
using namespace qpid::cluster;
@@ -70,6 +68,11 @@ using namespace boost::assign;
using broker::Broker;
using boost::shared_ptr;
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(cluster_test)
+
bool durableFlag = std::getenv("STORE_LIB") != 0;
void prepareArgs(ClusterFixture::Args& args, const bool durableFlag = false) {
@@ -1098,3 +1101,5 @@ QPID_AUTO_TEST_CASE(testRelease) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/consume.cpp b/qpid/cpp/src/tests/consume.cpp
index 3aacf8b3da..69110d151f 100644
--- a/qpid/cpp/src/tests/consume.cpp
+++ b/qpid/cpp/src/tests/consume.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -36,6 +36,9 @@ using namespace qpid::client;
using namespace qpid::sys;
using namespace std;
+namespace qpid {
+namespace tests {
+
typedef vector<string> StringSet;
struct Args : public qpid::TestOptions {
@@ -46,7 +49,7 @@ struct Args : public qpid::TestOptions {
bool summary;
bool print;
bool durable;
-
+
Args() : count(1000), ack(0), queue("publish-consume"),
declare(false), summary(false), print(false)
{
@@ -63,12 +66,12 @@ struct Args : public qpid::TestOptions {
Args opts;
-struct Client
+struct Client
{
Connection connection;
Session session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
@@ -85,7 +88,7 @@ struct Client
settings.flowControl = FlowControl(opts.count, SubscriptionManager::UNLIMITED,false);
Subscription sub = subs.subscribe(lq, opts.queue, settings);
Message msg;
- AbsTime begin=now();
+ AbsTime begin=now();
for (size_t i = 0; i < opts.count; ++i) {
msg=lq.pop();
QPID_LOG(info, "Received: " << msg.getMessageProperties().getCorrelationId());
@@ -99,7 +102,7 @@ struct Client
else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
}
- ~Client()
+ ~Client()
{
try{
session.close();
@@ -110,6 +113,10 @@ struct Client
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
diff --git a/qpid/cpp/src/tests/datagen.cpp b/qpid/cpp/src/tests/datagen.cpp
index 175f14cc57..acbc07d63c 100644
--- a/qpid/cpp/src/tests/datagen.cpp
+++ b/qpid/cpp/src/tests/datagen.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,7 +25,10 @@
#include <time.h>
#include "qpid/Options.h"
-struct Args : public qpid::Options
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::Options
{
uint count;
uint minSize;
@@ -34,12 +37,12 @@ struct Args : public qpid::Options
uint maxChar;
bool help;
- Args() : qpid::Options("Random data generator"),
- count(1), minSize(8), maxSize(4096),
+ Args() : qpid::Options("Random data generator"),
+ count(1), minSize(8), maxSize(4096),
minChar(32), maxChar(126),//safely printable ascii chars
help(false)
{
- addOptions()
+ addOptions()
("count", qpid::optValue(count, "N"), "number of data strings to generate")
("min-size", qpid::optValue(minSize, "N"), "minimum size of data string")
("max-size", qpid::optValue(maxSize, "N"), "maximum size of data string")
@@ -81,6 +84,10 @@ std::string generateData(uint size, uint min, uint max)
return data;
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
Args opts;
diff --git a/qpid/cpp/src/tests/echotest.cpp b/qpid/cpp/src/tests/echotest.cpp
index 98590e35ff..ab26dcf3fd 100644
--- a/qpid/cpp/src/tests/echotest.cpp
+++ b/qpid/cpp/src/tests/echotest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,6 +33,9 @@ using namespace qpid::framing;
using namespace qpid::sys;
using namespace std;
+namespace qpid {
+namespace tests {
+
struct Args : public qpid::Options,
public qpid::client::ConnectionSettings
{
@@ -48,7 +51,7 @@ struct Args : public qpid::Options,
("help", optValue(help), "Print this usage statement")
("count", optValue(count, "N"), "Number of messages to send")
("size", optValue(count, "N"), "Size of messages")
- ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
("port,p", optValue(port, "PORT"), "Broker port to connect to")
("username", optValue(username, "USER"), "user name for broker log in.")
("password", optValue(password, "PASSWORD"), "password for broker log in.")
@@ -75,7 +78,7 @@ class Listener : public MessageListener
Message request;
double total, min, max;
bool summary;
-
+
public:
Listener(Session& session, uint limit, bool summary);
void start(uint size);
@@ -92,7 +95,7 @@ void Listener::start(uint size)
{
session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=true);
request.getDeliveryProperties().setRoutingKey(queue);
- subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
request.getDeliveryProperties().setTimestamp(current_time());
if (size) request.setData(std::string(size, 'X'));
@@ -100,7 +103,7 @@ void Listener::start(uint size)
subscriptions.run();
}
-void Listener::received(Message& response)
+void Listener::received(Message& response)
{
//extract timestamp and compute latency:
uint64_t sentAt = response.getDeliveryProperties().getTimestamp();
@@ -122,7 +125,11 @@ void Listener::received(Message& response)
}
}
-int main(int argc, char** argv)
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv)
{
Args opts;
opts.parse(argc, argv);
diff --git a/qpid/cpp/src/tests/exception_test.cpp b/qpid/cpp/src/tests/exception_test.cpp
index 379e957ef1..0e9a948f00 100644
--- a/qpid/cpp/src/tests/exception_test.cpp
+++ b/qpid/cpp/src/tests/exception_test.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@
#include "qpid/sys/Thread.h"
#include "qpid/framing/reply_exceptions.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(exception_test)
// FIXME aconway 2008-06-12: need to update our exception handling to
@@ -49,12 +52,12 @@ struct Catcher : public Runnable {
function<void ()> f;
bool caught;
Thread thread;
-
+
Catcher(function<void ()> f_) : f(f_), caught(false), thread(this) {}
~Catcher() { join(); }
-
+
void run() {
- try {
+ try {
ScopedSuppressLogging sl; // Suppress messages for expected errors.
f();
}
@@ -110,7 +113,7 @@ QPID_AUTO_TEST_CASE(DisconnectedListen) {
Catcher<TransportFailure> runner(bind(&SubscriptionManager::run, boost::ref(fix.subs)));
fix.connection.proxy.close();
runner.join();
- BOOST_CHECK_THROW(fix.session.close(), TransportFailure);
+ BOOST_CHECK_THROW(fix.session.close(), TransportFailure);
}
QPID_AUTO_TEST_CASE(NoSuchQueueTest) {
@@ -120,3 +123,5 @@ QPID_AUTO_TEST_CASE(NoSuchQueueTest) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/failover_soak.cpp b/qpid/cpp/src/tests/failover_soak.cpp
index 4a59e7b160..16291fe60f 100644
--- a/qpid/cpp/src/tests/failover_soak.cpp
+++ b/qpid/cpp/src/tests/failover_soak.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -52,7 +52,8 @@ using namespace qpid::framing;
using namespace qpid::client;
-
+namespace qpid {
+namespace tests {
typedef vector<ForkedBroker *> brokerVector;
@@ -91,9 +92,9 @@ ostream& operator<< ( ostream& os, const childType& ct ) {
struct child
{
- child ( string & name, pid_t pid, childType type )
+ child ( string & name, pid_t pid, childType type )
: name(name), pid(pid), retval(-999), status(RUNNING), type(type)
- {
+ {
gettimeofday ( & startTime, 0 );
}
@@ -108,7 +109,7 @@ struct child
void
- setType ( childType t )
+ setType ( childType t )
{
type = t;
}
@@ -127,7 +128,7 @@ struct child
struct children : public vector<child *>
-{
+{
void
add ( string & name, pid_t pid, childType type )
@@ -136,7 +137,7 @@ struct children : public vector<child *>
}
- child *
+ child *
get ( pid_t pid )
{
vector<child *>::iterator i;
@@ -156,7 +157,7 @@ struct children : public vector<child *>
{
if ( verbosity > 1 )
{
- cerr << "children::exited warning: Can't find child with pid "
+ cerr << "children::exited warning: Can't find child with pid "
<< pid
<< endl;
}
@@ -193,7 +194,7 @@ struct children : public vector<child *>
<< endl;
return (*i)->retval;
}
-
+
return 0;
}
@@ -227,11 +228,11 @@ struct children : public vector<child *>
children allMyChildren;
-void
-childExit ( int )
+void
+childExit ( int )
{
- int childReturnCode;
- pid_t pid = waitpid ( 0, & childReturnCode, WNOHANG);
+ int childReturnCode;
+ pid_t pid = waitpid ( 0, & childReturnCode, WNOHANG);
if ( pid > 0 )
allMyChildren.exited ( pid, childReturnCode );
@@ -271,10 +272,10 @@ printBrokers ( brokerVector & brokers )
{
cout << "Broker List ------------ size: " << brokers.size() << "\n";
for ( brokerVector::iterator i = brokers.begin(); i != brokers.end(); ++ i) {
- cout << "pid: "
- << (*i)->getPID()
- << " port: "
- << (*i)->getPort()
+ cout << "pid: "
+ << (*i)->getPID()
+ << " port: "
+ << (*i)->getPort()
<< endl;
}
cout << "end Broker List ------------\n";
@@ -294,7 +295,7 @@ wait_for_newbie ( )
if ( ! newbie )
return true;
- try
+ try
{
Connection connection;
connection.open ( "127.0.0.1", newbie_port );
@@ -304,8 +305,8 @@ wait_for_newbie ( )
}
catch ( const std::exception& error )
{
- std::cerr << "wait_for_newbie error: "
- << error.what()
+ std::cerr << "wait_for_newbie error: "
+ << error.what()
<< endl;
return false;
}
@@ -321,7 +322,7 @@ startNewBroker ( brokerVector & brokers,
char const * moduleOrDir,
string const clusterName,
int verbosity,
- int durable )
+ int durable )
{
static int brokerId = 0;
stringstream path, prefix;
@@ -354,8 +355,8 @@ startNewBroker ( brokerVector & brokers,
ForkedBroker * broker = newbie;
if ( verbosity > 0 )
- std::cerr << "new broker created: pid == "
- << broker->getPID()
+ std::cerr << "new broker created: pid == "
+ << broker->getPID()
<< " log-prefix == "
<< "soak-" << brokerId
<< endl;
@@ -382,8 +383,8 @@ killFrontBroker ( brokerVector & brokers, int verbosity )
catch ( const exception& error ) {
if ( verbosity > 0 )
{
- cout << "error killing broker: "
- << error.what()
+ cout << "error killing broker: "
+ << error.what()
<< endl;
}
@@ -399,14 +400,14 @@ killFrontBroker ( brokerVector & brokers, int verbosity )
/*
- * The optional delay is to avoid killing newbie brokers that have just
+ * The optional delay is to avoid killing newbie brokers that have just
* been added and are still in the process of updating. This causes
* spurious, test-generated errors that scare everybody.
*/
void
killAllBrokers ( brokerVector & brokers, int delay )
{
- if ( delay > 0 )
+ if ( delay > 0 )
{
std::cerr << "Killing all brokers after delay of " << delay << endl;
sleep ( delay );
@@ -414,8 +415,8 @@ killAllBrokers ( brokerVector & brokers, int delay )
for ( uint i = 0; i < brokers.size(); ++ i )
try { brokers[i]->kill(9); }
- catch ( const exception& error )
- {
+ catch ( const exception& error )
+ {
std::cerr << "killAllBrokers Warning: exception during kill on broker "
<< i
<< " "
@@ -429,21 +430,21 @@ killAllBrokers ( brokerVector & brokers, int delay )
pid_t
-runDeclareQueuesClient ( brokerVector brokers,
+runDeclareQueuesClient ( brokerVector brokers,
char const * host,
char const * path,
int verbosity,
int durable
- )
+ )
{
string name("declareQueues");
int port = brokers[0]->getPort ( );
if ( verbosity > 1 )
- cout << "startDeclareQueuesClient: host: "
- << host
- << " port: "
- << port
+ cout << "startDeclareQueuesClient: host: "
+ << host
+ << " port: "
+ << port
<< endl;
stringstream portSs;
portSs << port;
@@ -474,12 +475,12 @@ runDeclareQueuesClient ( brokerVector brokers,
pid_t
-startReceivingClient ( brokerVector brokers,
+startReceivingClient ( brokerVector brokers,
char const * host,
char const * receiverPath,
char const * reportFrequency,
int verbosity
- )
+ )
{
string name("receiver");
int port = brokers[0]->getPort ( );
@@ -521,14 +522,14 @@ startReceivingClient ( brokerVector brokers,
pid_t
-startSendingClient ( brokerVector brokers,
+startSendingClient ( brokerVector brokers,
char const * host,
char const * senderPath,
char const * nMessages,
char const * reportFrequency,
int verbosity,
int durability
- )
+ )
{
string name("sender");
int port = brokers[0]->getPort ( );
@@ -581,13 +582,14 @@ startSendingClient ( brokerVector brokers,
#define HANGING 7
#define ERROR_KILLING_BROKER 8
+}} // namespace qpid::tests
-// If you want durability, use the "dir" option of "moduleOrDir" .
-
+using namespace qpid::tests;
+// If you want durability, use the "dir" option of "moduleOrDir" .
int
-main ( int argc, char const ** argv )
-{
+main ( int argc, char const ** argv )
+{
if ( argc != 9 ) {
cerr << "Usage: "
<< argv[0]
@@ -627,10 +629,10 @@ main ( int argc, char const ** argv )
int nBrokers = 3;
for ( int i = 0; i < nBrokers; ++ i ) {
startNewBroker ( brokers,
- moduleOrDir,
+ moduleOrDir,
clusterName,
verbosity,
- durable );
+ durable );
}
@@ -639,7 +641,7 @@ main ( int argc, char const ** argv )
// Run the declareQueues child.
int childStatus;
- pid_t dqClientPid =
+ pid_t dqClientPid =
runDeclareQueuesClient ( brokers, host, declareQueuesPath, verbosity, durable );
if ( -1 == dqClientPid ) {
cerr << "END_OF_TEST ERROR_START_DECLARE_1\n";
@@ -658,8 +660,8 @@ main ( int argc, char const ** argv )
// Start the receiving client.
pid_t receivingClientPid =
- startReceivingClient ( brokers,
- host,
+ startReceivingClient ( brokers,
+ host,
receiverPath,
reportFrequency,
verbosity );
@@ -670,10 +672,10 @@ main ( int argc, char const ** argv )
// Start the sending client.
- pid_t sendingClientPid =
- startSendingClient ( brokers,
- host,
- senderPath,
+ pid_t sendingClientPid =
+ startSendingClient ( brokers,
+ host,
+ senderPath,
nMessages,
reportFrequency,
verbosity,
@@ -688,10 +690,10 @@ main ( int argc, char const ** argv )
maxSleep = 4;
- for ( int totalBrokers = 3;
- totalBrokers < maxBrokers;
- ++ totalBrokers
- )
+ for ( int totalBrokers = 3;
+ totalBrokers < maxBrokers;
+ ++ totalBrokers
+ )
{
if ( verbosity > 0 )
cout << totalBrokers << " brokers have been added to the cluster.\n\n\n";
@@ -722,14 +724,14 @@ main ( int argc, char const ** argv )
cout << "Starting new broker.\n\n";
startNewBroker ( brokers,
- moduleOrDir,
+ moduleOrDir,
clusterName,
verbosity,
- durable );
-
+ durable );
+
if ( verbosity > 1 )
printBrokers ( brokers );
-
+
// If all children have exited, quit.
int unfinished = allMyChildren.unfinished();
if ( ! unfinished ) {
diff --git a/qpid/cpp/src/tests/federation.py b/qpid/cpp/src/tests/federation.py
index 174932adf8..aa68e8198b 100755
--- a/qpid/cpp/src/tests/federation.py
+++ b/qpid/cpp/src/tests/federation.py
@@ -503,6 +503,20 @@ class FederationTests(TestBase010):
self.assertEqual(result.status, 0)
result = bridge2.close()
self.assertEqual(result.status, 0)
+
+ # extra check: verify we don't leak bridge objects - keep the link
+ # around and verify the bridge count has gone to zero
+
+ attempts = 0
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+ while bridgeCount > 0:
+ attempts += 1
+ if attempts >= 5:
+ self.fail("Bridges didn't clean up")
+ return
+ sleep(1)
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+
result = link.close()
self.assertEqual(result.status, 0)
@@ -559,8 +573,13 @@ class FederationTests(TestBase010):
result = bridge.close()
self.assertEqual(result.status, 0)
- result = bridge2.close()
- self.assertEqual(result.status, 0)
+
+ # Extra test: don't explicitly close() bridge2. When the link is closed,
+ # it should clean up bridge2 automagically. verify_cleanup() will detect
+ # if bridge2 isn't cleaned up and will fail the test.
+ #
+ #result = bridge2.close()
+ #self.assertEqual(result.status, 0)
result = link.close()
self.assertEqual(result.status, 0)
diff --git a/qpid/cpp/src/tests/latencytest.cpp b/qpid/cpp/src/tests/latencytest.cpp
index e1c47eab05..a205ef6c7c 100644
--- a/qpid/cpp/src/tests/latencytest.cpp
+++ b/qpid/cpp/src/tests/latencytest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -40,6 +40,9 @@ using namespace qpid::client;
using namespace qpid::sys;
using std::string;
+namespace qpid {
+namespace tests {
+
typedef std::vector<std::string> StringSet;
struct Args : public qpid::TestOptions {
@@ -64,7 +67,7 @@ struct Args : public qpid::TestOptions {
durable(false), base("latency-test"), singleConnect(false)
{
- addOptions()
+ addOptions()
("size", optValue(size, "N"), "message size")
("concurrentTests", optValue(concurrentConnections, "N"), "number of concurrent test setups, will create another publisher,\
@@ -73,9 +76,9 @@ struct Args : public qpid::TestOptions {
("count", optValue(count, "N"), "number of messages to send")
("rate", optValue(rate, "N"), "target message rate (causes count to be ignored)")
("sync", optValue(sync), "send messages synchronously")
- ("report-frequency", optValue(reportFrequency, "N"),
+ ("report-frequency", optValue(reportFrequency, "N"),
"number of milliseconds to wait between reports (ignored unless rate specified)")
- ("time-limit", optValue(timeLimit, "N"),
+ ("time-limit", optValue(timeLimit, "N"),
"test duration, in seconds")
("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
("ack", optValue(ack, "N"), "Ack frequency in messages (defaults to half the prefetch value)")
@@ -98,7 +101,7 @@ uint64_t current_time()
return t;
}
-struct Stats
+struct Stats
{
Mutex lock;
uint count;
@@ -132,7 +135,7 @@ public:
};
class Receiver : public Client, public MessageListener
-{
+{
SubscriptionManager mgr;
uint count;
Stats& stats;
@@ -168,7 +171,7 @@ class Test
Receiver receiver;
Sender sender;
AbsTime begin;
-
+
public:
Test(const string& q) : queue(q), receiver(queue, stats), sender(queue, receiver), begin(now()) {}
void start();
@@ -186,7 +189,7 @@ Client::Client(const string& q) : queue(q)
connection = &localConnection;
opts.open(localConnection);
}
- session = connection->newSession();
+ session = connection->newSession();
}
void Client::start()
@@ -235,7 +238,7 @@ Receiver::Receiver(const string& q, Stats& s) : Client(q), mgr(session), count(0
settings.acceptMode = ACCEPT_MODE_NONE;
settings.flowControl = FlowControl::unlimited();
}
- mgr.subscribe(*this, queue, settings);
+ mgr.subscribe(*this, queue, settings);
}
void Receiver::test()
@@ -283,7 +286,7 @@ void Stats::print()
if (!opts.csv) {
if (count) {
std::cout << "Latency(ms): min=" << minLatency << ", max=" <<
- maxLatency << ", avg=" << aux_avg;
+ maxLatency << ", avg=" << aux_avg;
} else {
std::cout << "Stalled: no samples for interval";
}
@@ -368,7 +371,7 @@ void Sender::sendByRate()
Duration delay(sentAt, waitTill);
if (delay < 0)
++missedRate;
- else
+ else
sys::usleep(delay / TIME_USEC);
if (timeLimit != 0 && Duration(start, now()) > timeLimit) {
session.sync();
@@ -382,7 +385,7 @@ string Sender::generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -392,35 +395,39 @@ string Sender::generateData(uint size)
}
-void Test::start()
-{
- receiver.start();
+void Test::start()
+{
+ receiver.start();
begin = AbsTime(now());
- sender.start();
+ sender.start();
}
-void Test::join()
-{
- sender.join();
- receiver.join();
+void Test::join()
+{
+ sender.join();
+ receiver.join();
AbsTime end = now();
Duration time(begin, end);
double msecs(time / TIME_MSEC);
if (!opts.csv) {
- std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
+ std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
<< " in " << msecs << "ms (" << (receiver.getCount() * 1000 / msecs) << " msgs/s) ";
}
stats.print();
std::cout << std::endl;
}
-void Test::report()
-{
+void Test::report()
+{
stats.print();
std::cout << std::endl;
stats.reset();
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
diff --git a/qpid/cpp/src/tests/logging.cpp b/qpid/cpp/src/tests/logging.cpp
index 00e1d7de85..5cb563c7d3 100644
--- a/qpid/cpp/src/tests/logging.cpp
+++ b/qpid/cpp/src/tests/logging.cpp
@@ -37,6 +37,9 @@
#include <time.h>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(loggingTestSuite)
using namespace std;
@@ -106,7 +109,7 @@ struct TestOutput : public Logger::Output {
TestOutput(Logger& l) {
l.output(std::auto_ptr<Logger::Output>(this));
}
-
+
void log(const Statement& s, const string& m) {
msg.push_back(m);
stmt.push_back(s);
@@ -117,7 +120,7 @@ struct TestOutput : public Logger::Output {
using boost::assign::list_of;
QPID_AUTO_TEST_CASE(testLoggerOutput) {
- Logger l;
+ Logger l;
l.clear();
l.select(Selector(debug));
Statement s=QPID_LOG_STATEMENT_INIT(debug);
@@ -174,7 +177,7 @@ QPID_AUTO_TEST_CASE(testLoggerFormat) {
l.format(Logger::FUNCTION);
QPID_LOG(critical, "foo");
BOOST_CHECK_EQUAL(string(BOOST_CURRENT_FUNCTION) + ": foo\n", out->last());
-
+
l.format(Logger::LEVEL);
QPID_LOG(critical, "foo");
BOOST_CHECK_EQUAL("critical foo\n", out->last());
@@ -228,12 +231,12 @@ clock_t timeLoop(int times, int (*fp)()) {
// Overhead test disabled because it consumes a ton of CPU and takes
// forever under valgrind. Not friendly for regular test runs.
-//
+//
#if 0
QPID_AUTO_TEST_CASE(testOverhead) {
// Ensure that the ratio of CPU time for an incrementing loop
// with and without disabled log statements is in acceptable limits.
- //
+ //
int times=100000000;
clock_t noLog=timeLoop(times, count);
clock_t withLog=timeLoop(times, loggedCount);
@@ -242,9 +245,9 @@ QPID_AUTO_TEST_CASE(testOverhead) {
// NB: in initial tests the ratio was consistently below 1.5,
// 2.5 is reasonable and should avoid spurios failures
// due to machine load.
- //
- BOOST_CHECK_SMALL(ratio, 2.5);
-}
+ //
+ BOOST_CHECK_SMALL(ratio, 2.5);
+}
#endif // 0
Statement statement(
@@ -290,7 +293,7 @@ QPID_AUTO_TEST_CASE(testOptionsParse) {
}
QPID_AUTO_TEST_CASE(testOptionsDefault) {
- Options opts("");
+ qpid::log::Options opts("");
#ifdef _WIN32
qpid::log::windows::SinkOptions sinks("test");
#else
@@ -328,10 +331,10 @@ QPID_AUTO_TEST_CASE(testSelectorFromOptions) {
QPID_AUTO_TEST_CASE(testLoggerStateure) {
Logger& l=Logger::instance();
ScopedSuppressLogging ls(l);
- Options opts("test");
+ qpid::log::Options opts("test");
const char* argv[]={
0,
- "--log-time", "no",
+ "--log-time", "no",
"--log-source", "yes",
"--log-to-stderr", "no",
"--log-to-file", "logging.tmp",
@@ -352,7 +355,7 @@ QPID_AUTO_TEST_CASE(testLoggerStateure) {
QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
Logger& l=Logger::instance();
ScopedSuppressLogging ls(l);
- Options opts("test");
+ qpid::log::Options opts("test");
opts.time=false;
#ifdef _WIN32
qpid::log::windows::SinkOptions *sinks =
@@ -367,7 +370,7 @@ QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
char s[] = "null\0tab\tspace newline\nret\r\x80\x99\xff";
string str(s, sizeof(s));
- QPID_LOG(critical, str);
+ QPID_LOG(critical, str);
ifstream log("logging.tmp");
string line;
getline(log, line, '\0');
@@ -378,3 +381,5 @@ QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/perftest.cpp b/qpid/cpp/src/tests/perftest.cpp
index d383e0eb80..88d9fd15cb 100644
--- a/qpid/cpp/src/tests/perftest.cpp
+++ b/qpid/cpp/src/tests/perftest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -49,6 +49,9 @@ using namespace sys;
using boost::lexical_cast;
using boost::bind;
+namespace qpid {
+namespace tests {
+
enum Mode { SHARED, FANOUT, TOPIC };
const char* modeNames[] = { "shared", "fanout", "topic" };
@@ -105,9 +108,9 @@ struct Opts : public TestOptions {
bool commitAsync;
static const std::string helpText;
-
+
Opts() :
- TestOptions(helpText),
+ TestOptions(helpText),
setup(false), control(false), publish(false), subscribe(false), baseName("perftest"),
pubs(1), count(500000), size(1024), confirm(true), durable(false), uniqueData(false), syncPub(false),
subs(1), ack(0),
@@ -136,16 +139,16 @@ struct Opts : public TestOptions {
("nsubs", optValue(subs, "N"), "Create N subscribers.")
("sub-ack", optValue(ack, "N"), "N>0: Subscriber acks batches of N.\n"
"N==0: Subscriber uses unconfirmed mode")
-
+
("qt", optValue(qt, "N"), "Create N queues or topics.")
("single-connection", optValue(singleConnect, "yes|no"), "Use one connection for multiple sessions.")
-
+
("iterations", optValue(iterations, "N"), "Desired number of iterations of the test.")
("summary,s", optValue(summary), "Summary output: pubs/sec subs/sec transfers/sec Mbytes/sec")
("queue-max-count", optValue(queueMaxCount, "N"), "queue policy: count to trigger 'flow to disk'")
("queue-max-size", optValue(queueMaxSize, "N"), "queue policy: accumulated size to trigger 'flow to disk'")
- ("base-name", optValue(baseName, "NAME"), "base name used for queues or topics")
+ ("base-name", optValue(baseName, "NAME"), "base name used for queues or topics")
("queue-durable", optValue(queueDurable, "N"), "Make queue durable (implied if durable set)")
("interval_sub", optValue(intervalSub, "ms"), ">=0 delay between msg consume")
@@ -171,7 +174,7 @@ struct Opts : public TestOptions {
count += subs - (count % subs);
cout << "WARNING: Adjusted --count to " << count
<< " the nearest multiple of --nsubs" << endl;
- }
+ }
totalPubs = pubs*qt;
totalSubs = subs*qt;
subQuota = (pubs*count)/subs;
@@ -258,7 +261,7 @@ struct Client : public Runnable {
};
struct Setup : public Client {
-
+
void queueInit(string name, bool durable=false, const framing::FieldTable& settings=framing::FieldTable()) {
session.queueDeclare(arg::queue=name, arg::durable=durable, arg::arguments=settings);
session.queuePurge(arg::queue=name);
@@ -278,7 +281,7 @@ struct Setup : public Client {
for (size_t i = 0; i < opts.qt; ++i) {
ostringstream qname;
qname << opts.baseName << i;
- queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
+ queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
}
}
}
@@ -303,7 +306,7 @@ class Stats {
public:
Stats() : sum(0) {}
-
+
// Functor to collect rates.
void operator()(const string& data) {
try {
@@ -314,7 +317,7 @@ class Stats {
throw Exception("Bad report: "+data);
}
}
-
+
double mean() const {
return sum/values.size();
}
@@ -331,7 +334,7 @@ class Stats {
}
return sqrt(ssq/(values.size()-1));
}
-
+
ostream& print(ostream& out) {
ostream_iterator<double> o(out, "\n");
copy(values.begin(), values.end(), o);
@@ -341,11 +344,11 @@ class Stats {
return out << endl;
}
};
-
+
// Manage control queues, collect and print reports.
struct Controller : public Client {
-
+
SubscriptionManager subs;
Controller() : subs(session) {}
@@ -354,7 +357,7 @@ struct Controller : public Client {
void process(size_t n, string queue,
boost::function<void (const string&)> msgFn)
{
- if (!opts.summary)
+ if (!opts.summary)
cout << "Processing " << n << " messages from "
<< queue << " " << flush;
LocalQueue lq;
@@ -370,8 +373,8 @@ struct Controller : public Client {
void process(size_t n, LocalQueue lq, string queue,
boost::function<void (const string&)> msgFn)
{
- session.messageFlow(queue, 0, n);
- if (!opts.summary)
+ session.messageFlow(queue, 0, n);
+ if (!opts.summary)
cout << "Processing " << n << " messages from "
<< queue << " " << flush;
for (size_t i = 0; i < n; ++i) {
@@ -386,7 +389,7 @@ struct Controller : public Client {
cout << "Sending " << data << " " << n << " times to " << queue
<< endl;
Message msg(data, queue);
- for (size_t i = 0; i < n; ++i)
+ for (size_t i = 0; i < n; ++i)
session.messageTransfer(arg::content=msg, arg::acceptMode=1);
}
@@ -419,7 +422,7 @@ struct Controller : public Client {
process(opts.totalPubs, pubDone, fqn("pub_done"), boost::ref(pubRates));
process(opts.totalSubs, subDone, fqn("sub_done"), boost::ref(subRates));
- AbsTime end=now();
+ AbsTime end=now();
double time=secs(start, end);
double txrate=opts.transfers/time;
@@ -469,12 +472,12 @@ struct PublishThread : public Client {
string routingKey;
PublishThread() {};
-
+
PublishThread(string key, string dest=string()) {
destination=dest;
routingKey=key;
}
-
+
void run() { // Publisher
try {
string data;
@@ -492,7 +495,7 @@ struct PublishThread : public Client {
}
} else {
size_t msgSize=max(opts.size, sizeof(size_t));
- data = string(msgSize, 'X');
+ data = string(msgSize, 'X');
}
Message msg(data, routingKey);
@@ -500,21 +503,21 @@ struct PublishThread : public Client {
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
- if (opts.txPub){
+ if (opts.txPub){
session.txSelect();
}
SubscriptionManager subs(session);
LocalQueue lq;
- subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
- subs.subscribe(lq, fqn("pub_start"));
-
+ subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
+ subs.subscribe(lq, fqn("pub_start"));
+
for (size_t j = 0; j < opts.iterations; ++j) {
expect(lq.pop().getData(), "start");
AbsTime start=now();
for (size_t i=0; i<opts.count; i++) {
// Stamp the iteration into the message data, avoid
// any heap allocation.
- const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
+ const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
reinterpret_cast<const char*>(&i), sizeof(size_t));
if (opts.syncPub) {
sync(session).messageTransfer(
@@ -540,7 +543,7 @@ struct PublishThread : public Client {
if (opts.confirm) session.sync();
AbsTime end=now();
double time=secs(start,end);
-
+
// Send result to controller.
Message report(lexical_cast<string>(opts.count/time), fqn("pub_done"));
session.messageTransfer(arg::content=report, arg::acceptMode=1);
@@ -561,7 +564,7 @@ struct SubscribeThread : public Client {
string queue;
SubscribeThread() {}
-
+
SubscribeThread(string q) { queue = q; }
SubscribeThread(string key, string ex) {
@@ -586,7 +589,7 @@ struct SubscribeThread : public Client {
}
void run() { // Subscribe
- try {
+ try {
if (opts.txSub) sync(session).txSelect();
SubscriptionManager subs(session);
SubscriptionSettings settings;
@@ -606,15 +609,15 @@ struct SubscribeThread : public Client {
if (opts.iterations > 1) {
subs.subscribe(iterationControl, fqn("sub_iteration"), SubscriptionSettings(FlowControl::messageCredit(0)));
}
-
+
for (size_t j = 0; j < opts.iterations; ++j) {
if (j > 0) {
//need to wait here until all subs are done
- session.messageFlow(fqn("sub_iteration"), 0, 1);
+ session.messageFlow(fqn("sub_iteration"), 0, 1);
iterationControl.pop();
//need to allocate some more credit for subscription
- session.messageFlow(queue, 0, opts.subQuota);
+ session.messageFlow(queue, 0, opts.subQuota);
}
Message msg;
AbsTime start=now();
@@ -627,7 +630,7 @@ struct SubscribeThread : public Client {
}
if (opts.intervalSub)
qpid::sys::usleep(opts.intervalSub*1000);
- // TODO aconway 2007-11-23: check message order for.
+ // TODO aconway 2007-11-23: check message order for.
// multiple publishers. Need an array of counters,
// one per publisher and a publisher ID in the
// message. Careful not to introduce a lot of overhead
@@ -664,6 +667,10 @@ struct SubscribeThread : public Client {
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv) {
int exitCode = 0;
boost::ptr_vector<Client> subs(opts.subs);
diff --git a/qpid/cpp/src/tests/publish.cpp b/qpid/cpp/src/tests/publish.cpp
index 34c2b8fefc..3f456e7588 100644
--- a/qpid/cpp/src/tests/publish.cpp
+++ b/qpid/cpp/src/tests/publish.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -36,6 +36,9 @@ using namespace qpid::client;
using namespace qpid::sys;
using namespace std;
+namespace qpid {
+namespace tests {
+
typedef vector<string> StringSet;
struct Args : public qpid::TestOptions {
@@ -61,12 +64,12 @@ struct Args : public qpid::TestOptions {
Args opts;
-struct Client
+struct Client
{
Connection connection;
AsyncSession session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
@@ -75,7 +78,7 @@ struct Client
// Cheap hex calculation, avoid expensive ostrstream and string
// creation to generate correlation ids in message loop.
char hex(char i) { return i<10 ? '0'+i : 'A'+i-10; }
- void hex(char i, string& s) {
+ void hex(char i, string& s) {
s[0]=hex(i>>24); s[1]=hex(i>>16); s[2]=hex(i>>8); s[3]=i;
}
@@ -86,7 +89,7 @@ struct Client
string correlationId = "0000";
if (opts.durable)
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
-
+
for (uint i = 0; i < opts.count; i++) {
if (opts.id) {
hex(i+1, correlationId);
@@ -103,7 +106,7 @@ struct Client
else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
}
- ~Client()
+ ~Client()
{
try{
session.close();
@@ -114,6 +117,10 @@ struct Client
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
diff --git a/qpid/cpp/src/tests/qpid_ping.cpp b/qpid/cpp/src/tests/qpid_ping.cpp
index cc07ade7bb..b046fdf54b 100644
--- a/qpid/cpp/src/tests/qpid_ping.cpp
+++ b/qpid/cpp/src/tests/qpid_ping.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -38,6 +38,9 @@ using namespace qpid::framing;
using namespace qpid::client;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
struct PingOptions : public qpid::TestOptions {
int timeout; // Timeout in seconds.
bool quiet; // No output
@@ -58,7 +61,7 @@ class Ping : public Runnable {
public:
Ping() : status(WAITING) {}
-
+
void run() {
try {
opts.open(connection);
@@ -100,6 +103,9 @@ class Ping : public Runnable {
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
int main(int argc, char** argv) {
try {
diff --git a/qpid/cpp/src/tests/qpid_stream.cpp b/qpid/cpp/src/tests/qpid_stream.cpp
new file mode 100644
index 0000000000..8e02baa8a0
--- /dev/null
+++ b/qpid/cpp/src/tests/qpid_stream.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/sys/Runnable.h>
+#include <qpid/sys/Thread.h>
+#include <qpid/sys/Time.h>
+#include <qpid/Options.h>
+#include <iostream>
+#include <string>
+
+using namespace qpid::messaging;
+using namespace qpid::sys;
+
+struct Args : public qpid::Options
+{
+ std::string url;
+ std::string address;
+ uint rate;
+ bool durable;
+
+ Args() : url("amqp:tcp:127.0.0.1:5672"), address("test-queue"), rate(1000), durable(false)
+ {
+ addOptions()
+ ("url", qpid::optValue(url, "URL"), "Url to connect to.")
+ ("address", qpid::optValue(address, "ADDRESS"), "Address to stream messages through.")
+ ("rate", qpid::optValue(rate, "msgs/sec"), "Rate at which to stream messages.")
+ ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.");
+ }
+};
+
+Args opts;
+
+const std::string TIMESTAMP = "ts";
+
+uint64_t timestamp(const AbsTime& time)
+{
+ Duration t(time);
+ return t;
+}
+
+struct Client : Runnable
+{
+ virtual ~Client() {}
+ virtual void doWork(Session&) = 0;
+
+ void run()
+ {
+ try {
+ Connection connection = Connection::open(opts.url);
+ Session session = connection.newSession();
+ doWork(session);
+ session.close();
+ connection.close();
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+
+ Thread thread;
+
+ void start() { thread = Thread(this); }
+ void join() { thread.join(); }
+};
+
+struct Publish : Client
+{
+ void doWork(Session& session)
+ {
+ Sender sender = session.createSender(opts.address);
+ Message msg;
+ uint64_t interval = TIME_SEC / opts.rate;
+ uint64_t sent = 0, missedRate = 0;
+ AbsTime start = now();
+ while (true) {
+ AbsTime sentAt = now();
+ msg.getHeaders()[TIMESTAMP] = timestamp(sentAt);
+ sender.send(msg);
+ ++sent;
+ AbsTime waitTill(start, sent*interval);
+ Duration delay(sentAt, waitTill);
+ if (delay < 0) {
+ ++missedRate;
+ } else {
+ qpid::sys::usleep(delay / TIME_USEC);
+ }
+ }
+ }
+};
+
+struct Consume : Client
+{
+ void doWork(Session& session)
+ {
+ Message msg;
+ uint64_t received = 0;
+ double minLatency = std::numeric_limits<double>::max();
+ double maxLatency = 0;
+ double totalLatency = 0;
+ Receiver receiver = session.createReceiver(opts.address);
+ while (receiver.fetch(msg)) {
+ session.acknowledge();//TODO: add batching option
+ ++received;
+ //calculate latency
+ uint64_t receivedAt = timestamp(now());
+ uint64_t sentAt = msg.getHeaders()[TIMESTAMP].asUint64();
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+
+ //update avg, min & max
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
+ totalLatency += latency;
+
+ if (received % opts.rate == 0) {
+ std::cout << "count=" << received
+ << ", avg=" << (totalLatency/received)
+ << ", min=" << minLatency
+ << ", max=" << maxLatency << std::endl;
+ }
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Publish publish;
+ Consume consume;
+ publish.start();
+ consume.start();
+ consume.join();
+ publish.join();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/src/tests/qrsh.cpp b/qpid/cpp/src/tests/qrsh.cpp
index 2d71b600d5..0cb52b6b05 100644
--- a/qpid/cpp/src/tests/qrsh.cpp
+++ b/qpid/cpp/src/tests/qrsh.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -37,11 +37,13 @@ using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
class ResponseListener : public MessageListener
{
public :
-
+
int exitCode;
ResponseListener ( SubscriptionManager & subscriptions )
@@ -50,7 +52,7 @@ class ResponseListener : public MessageListener
{
}
- virtual void
+ virtual void
received ( Message & message )
{
char first_word[1000];
@@ -66,9 +68,9 @@ class ResponseListener : public MessageListener
if ( ! strcmp ( first_word, "get_response" ) )
{
// The remainder of the message is the file we requested.
- fprintf ( stdout,
- "%s",
- message.getData().c_str() + strlen("get_response" )
+ fprintf ( stdout,
+ "%s",
+ message.getData().c_str() + strlen("get_response" )
);
subscriptions.cancel(message.getDestination());
}
@@ -76,12 +78,13 @@ class ResponseListener : public MessageListener
private :
-
+
SubscriptionManager & subscriptions;
};
+}} // namespace qpid::tests
-
+using namespace qpid::tests;
/*
* argv[1] host
@@ -90,8 +93,8 @@ class ResponseListener : public MessageListener
* argv[4] command name
* argv[5..N] args to the command
*/
-int
-main ( int argc, char ** argv )
+int
+main ( int argc, char ** argv )
{
const char* host = argv[1];
int port = atoi(argv[2]);
@@ -99,14 +102,14 @@ main ( int argc, char ** argv )
Connection connection;
- try
+ try
{
connection.open ( host, port );
Session session = connection.newSession ( );
// Make a queue and bind it to fanout.
string myQueue = session.getId().getName();
-
+
session.queueDeclare ( arg::queue=myQueue,
arg::exclusive=true,
arg::autoDelete=true
@@ -136,7 +139,7 @@ main ( int argc, char ** argv )
response_command = true;
// Send the payload message.
- // Skip "qrsh host_name port"
+ // Skip "qrsh host_name port"
Message message;
stringstream ss;
for ( int i = 3; i < argc; ++ i )
@@ -144,7 +147,7 @@ main ( int argc, char ** argv )
message.setData ( ss.str() );
- session.messageTransfer(arg::content=message,
+ session.messageTransfer(arg::content=message,
arg::destination="amq.fanout");
if ( response_command )
@@ -153,8 +156,8 @@ main ( int argc, char ** argv )
session.close();
connection.close();
return responseListener.exitCode;
- }
- catch ( exception const & e)
+ }
+ catch ( exception const & e)
{
cerr << e.what() << endl;
}
diff --git a/qpid/cpp/src/tests/qrsh_server.cpp b/qpid/cpp/src/tests/qrsh_server.cpp
index 4b80212eae..f1163ba479 100644
--- a/qpid/cpp/src/tests/qrsh_server.cpp
+++ b/qpid/cpp/src/tests/qrsh_server.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -43,7 +43,8 @@ using namespace qpid::framing;
using namespace std;
-
+namespace qpid {
+namespace tests {
int
mrand ( int max_desired_val )
@@ -54,7 +55,7 @@ mrand ( int max_desired_val )
-char *
+char *
file2str ( char const * file_name )
{
FILE * fp = fopen ( file_name, "r" );
@@ -71,9 +72,9 @@ file2str ( char const * file_name )
if ( ! content )
{
- fprintf ( stderr,
- "file2str error: can't malloc %d bytes.\n",
- (int)file_len
+ fprintf ( stderr,
+ "file2str error: can't malloc %d bytes.\n",
+ (int)file_len
);
return 0;
}
@@ -123,9 +124,9 @@ class QrshServer : public MessageListener
bool myMessage ( Message const & message );
/* ----------------------------------------------
- * Special Commands
+ * Special Commands
* These are commands that the qrsh_server executes
- * directly, rather than through a child process
+ * directly, rather than through a child process
* instance of qrsh_run.
*/
void runCommand ( Message const & message );
@@ -157,9 +158,9 @@ class QrshServer : public MessageListener
char const * skipWord ( char const * s );
- void string_replaceAll ( string & str,
- string & target,
- string & replacement
+ void string_replaceAll ( string & str,
+ string & target,
+ string & replacement
);
@@ -186,12 +187,12 @@ class QrshServer : public MessageListener
-QrshServer::QrshServer ( SubscriptionManager & subs,
+QrshServer::QrshServer ( SubscriptionManager & subs,
char const * name,
char const * qrsh_run_path,
char const * host,
int port
- )
+ )
: subscriptions ( subs ),
name ( name ),
qrsh_run_path ( qrsh_run_path ),
@@ -202,11 +203,11 @@ QrshServer::QrshServer ( SubscriptionManager & subs,
{
data_dir << "/tmp/qrsh_"
<< getpid();
-
+
if(mkdir ( data_dir.str().c_str(), 0777 ) )
{
- fprintf ( stderr,
- "QrshServer::QrshServer error: can't mkdir |%s|\n",
+ fprintf ( stderr,
+ "QrshServer::QrshServer error: can't mkdir |%s|\n",
data_dir.str().c_str()
);
exit ( 1 );
@@ -239,21 +240,21 @@ QrshServer::start ( )
<< name;
send ( announcement_data.str() );
-
+
saidHello = true;
}
-void
+void
QrshServer::send ( string const & content )
{
try
{
Message message;
message.setData ( content );
-
+
Connection connection;
connection.open ( host, port );
Session session = connection.newSession ( );
@@ -289,7 +290,7 @@ QrshServer::sayHello ( )
-void
+void
QrshServer::sayName ( )
{
fprintf ( stderr, "My name is: |%s|\n", name.c_str() );
@@ -343,7 +344,7 @@ QrshServer::getStraw ( Message const & message )
break;
}
}
-
+
if ( i_win && (ties <= 0) )
{
myStraw = 0;
@@ -364,10 +365,10 @@ QrshServer::getStraw ( Message const & message )
/*
* "APB" command (all-points-bullitens (commands that are not addressed
* specifically to any server)) are handled directly, here.
- * Because if I return simply "true", the normal command processing code
+ * Because if I return simply "true", the normal command processing code
* will misinterpret the command.
*/
-bool
+bool
QrshServer::myMessage ( Message const & message )
{
int const maxlen = 100;
@@ -414,7 +415,7 @@ QrshServer::myMessage ( Message const & message )
{
return true;
}
- else
+ else
if ( ! strcmp ( first_word, "any" ) )
{
straws.clear();
@@ -443,7 +444,7 @@ QrshServer::rememberIntroduction ( Message const & message )
-void
+void
QrshServer::addAlias ( Message const & message )
{
char alias[1000];
@@ -463,8 +464,8 @@ QrshServer::getNames ( )
if ( ! dir )
{
- fprintf ( stderr,
- "QrshServer::getNames error: could not open dir |%s|.\n",
+ fprintf ( stderr,
+ "QrshServer::getNames error: could not open dir |%s|.\n",
data_dir.str().c_str()
);
return;
@@ -491,8 +492,8 @@ QrshServer::getNames ( )
}
else
{
- /*
- * Fail silently. The non-existence of this file
+ /*
+ * Fail silently. The non-existence of this file
* is not necessarily an error.
*/
}
@@ -504,9 +505,9 @@ QrshServer::getNames ( )
void
-QrshServer::string_replaceAll ( string & str,
- string & target,
- string & replacement
+QrshServer::string_replaceAll ( string & str,
+ string & target,
+ string & replacement
)
{
int target_size = target.size();
@@ -519,7 +520,7 @@ QrshServer::string_replaceAll ( string & str,
-bool
+bool
QrshServer::isProcessName ( char const * str )
{
getNames();
@@ -537,12 +538,12 @@ QrshServer::isProcessName ( char const * str )
-int
+int
QrshServer::string_countWords ( char const * s1 )
{
int count = 0;
char const * s2 = s1 + 1;
-
+
if ( ! isspace(* s1) )
{
++ count;
@@ -603,7 +604,7 @@ QrshServer::get ( Message const & request_message )
*/
char file_or_process_name[1000];
sscanf ( request_message.getData().c_str(), "%*s%*s%s", file_or_process_name );
-
+
if ( isProcessName ( file_or_process_name ) )
{
stringstream desired_file_name;
@@ -612,13 +613,13 @@ QrshServer::get ( Message const & request_message )
<< file_or_process_name
<< '/';
char requested_output_stream[1000];
- if(1 != sscanf ( request_message.getData().c_str(),
- "%*s%*s%*s%s",
- requested_output_stream
+ if(1 != sscanf ( request_message.getData().c_str(),
+ "%*s%*s%*s%s",
+ requested_output_stream
)
)
{
- fprintf ( stderr,
+ fprintf ( stderr,
"QrshServer::get error: Can't read requested data file name from this message: |%s|\n",
request_message.getData().c_str()
);
@@ -674,7 +675,7 @@ QrshServer::exited ( Message const & message )
if ( truncated_command )
{
stringstream ss;
- ss << qrsh_run_path
+ ss << qrsh_run_path
<< ' '
<< data_dir.str()
<< ' '
@@ -706,9 +707,9 @@ QrshServer::exited ( Message const & message )
fprintf ( stderr, "qrsh_server error awaiting child!\n" );
exit ( 1 );
}
-
+
exit_code >>= 8;
-
+
stringstream data;
data << "wait_response "
<< exit_code;
@@ -731,7 +732,7 @@ QrshServer::wait ( Message const & message )
// The second word is "exec_wait".
// The third word is the symbolic name of the command to wait for.
// The fact that there are exactly three words means that this
- // must be a command that has already been named and started --
+ // must be a command that has already been named and started --
// we just need to find its pid and wait on it.
pre_existing = true;
}
@@ -762,7 +763,7 @@ QrshServer::wait ( Message const & message )
if ( truncated_command )
{
stringstream ss;
- ss << qrsh_run_path
+ ss << qrsh_run_path
<< ' '
<< data_dir.str()
<< ' '
@@ -795,7 +796,7 @@ QrshServer::wait ( Message const & message )
exit ( 1 );
}
}
-
+
exit_code >>= 8;
stringstream data;
@@ -810,7 +811,7 @@ QrshServer::wait ( Message const & message )
-char const *
+char const *
QrshServer::skipWord ( char const * s )
{
if(! (s && *s) )
@@ -884,7 +885,7 @@ QrshServer::getArgs ( char const * str )
arg_len = 0;
}
- done:
+ done:
if ( arg_len > 0 )
lengths.push_back ( arg_len );
@@ -896,8 +897,8 @@ QrshServer::getArgs ( char const * str )
for ( int i = 0; i < n_args; ++ i )
{
argv[i] = ( char *) malloc ( lengths[i] + 1 );
- strncpy ( argv[i],
- str + start_positions[i],
+ strncpy ( argv[i],
+ str + start_positions[i],
lengths[i]
);
argv[i][lengths[i]] = 0;
@@ -971,12 +972,12 @@ QrshServer::runCommand ( Message const & message )
* qrsh_run, which will save all its data in the qrsh dir.
*/
stringstream ss;
- ss << qrsh_run_path
+ ss << qrsh_run_path
<< ' '
<< data_dir.str()
<< ' '
<< s;
-
+
if ( ! fork() )
{
char ** argv = getArgs ( ss.str().c_str() );
@@ -988,8 +989,8 @@ QrshServer::runCommand ( Message const & message )
-void
-QrshServer::received ( Message & message )
+void
+QrshServer::received ( Message & message )
{
if ( myMessage ( message ) )
runCommand ( message );
@@ -997,7 +998,9 @@ QrshServer::received ( Message & message )
+}} // namespace qpid::tests
+using namespace qpid::tests;
/*
* fixme mick Mon Aug 3 10:29:26 EDT 2009
@@ -1024,23 +1027,23 @@ main ( int /*argc*/, char** argv )
// Declare queues.
string myQueue = session.getId().getName();
- session.queueDeclare ( arg::queue=myQueue,
+ session.queueDeclare ( arg::queue=myQueue,
arg::exclusive=true,
arg::autoDelete=true);
- session.exchangeBind ( arg::exchange="amq.fanout",
- arg::queue=myQueue,
+ session.exchangeBind ( arg::exchange="amq.fanout",
+ arg::queue=myQueue,
arg::bindingKey="my-key");
-
+
// Create a server and subscribe it to my queue.
SubscriptionManager subscriptions ( session );
- QrshServer server ( subscriptions,
+ QrshServer server ( subscriptions,
argv[1], // server name
argv[2], // qrsh exe path
host,
port
);
- subscriptions.subscribe ( server, myQueue );
+ subscriptions.subscribe ( server, myQueue );
// Receive messages until the subscription is cancelled
// by QrshServer::received()
@@ -1048,7 +1051,7 @@ main ( int /*argc*/, char** argv )
connection.close();
}
- catch(const exception& error)
+ catch(const exception& error)
{
cout << error.what() << endl;
return 1;
diff --git a/qpid/cpp/src/tests/receiver.cpp b/qpid/cpp/src/tests/receiver.cpp
index 49f7ff0338..e01954e31a 100644
--- a/qpid/cpp/src/tests/receiver.cpp
+++ b/qpid/cpp/src/tests/receiver.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -36,7 +36,10 @@ using namespace qpid::framing;
using namespace std;
-struct Args : public qpid::TestOptions
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
{
string queue;
uint messages;
@@ -47,7 +50,7 @@ struct Args : public qpid::TestOptions
Args() : queue("test-queue"), messages(0), ignoreDuplicates(false), creditWindow(0), ackFrequency(1), browse(false)
{
- addOptions()
+ addOptions()
("queue", qpid::optValue(queue, "QUEUE NAME"), "Queue from which to request messages")
("messages", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely")
("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)")
@@ -77,15 +80,15 @@ class Receiver : public MessageListener, public FailoverManager::Command
bool isDuplicate(Message& message);
};
-Receiver::Receiver(const string& q, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency, bool browse) :
- queue(q), count(messages), skipDups(ignoreDuplicates), processed(0), lastSn(0)
+Receiver::Receiver(const string& q, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency, bool browse) :
+ queue(q), count(messages), skipDups(ignoreDuplicates), processed(0), lastSn(0)
{
if (browse) settings.acquireMode = ACQUIRE_MODE_NOT_ACQUIRED;
if (creditWindow) settings.flowControl = FlowControl::messageWindow(creditWindow);
settings.autoAck = ackFrequency;
}
-void Receiver::received(Message& message)
+void Receiver::received(Message& message)
{
if (!(skipDups && isDuplicate(message))) {
bool eos = message.getData() == EOS;
@@ -94,7 +97,7 @@ void Receiver::received(Message& message)
}
}
-bool Receiver::isDuplicate(Message& message)
+bool Receiver::isDuplicate(Message& message)
{
uint sn = message.getHeaders().getAsInt("sn");
if (lastSn < sn) {
@@ -115,6 +118,10 @@ void Receiver::execute(AsyncSession& session, bool /*isRetry*/)
}
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char ** argv)
{
Args opts;
@@ -130,6 +137,3 @@ int main(int argc, char ** argv)
}
return 1;
}
-
-
-
diff --git a/qpid/cpp/src/tests/replaying_sender.cpp b/qpid/cpp/src/tests/replaying_sender.cpp
index 3ee69eec14..bfb4b042b6 100644
--- a/qpid/cpp/src/tests/replaying_sender.cpp
+++ b/qpid/cpp/src/tests/replaying_sender.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -35,12 +35,15 @@ using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
class Sender : public FailoverManager::Command
{
public:
Sender(const std::string& queue, uint count, uint reportFreq);
void execute(AsyncSession& session, bool isRetry);
- uint getSent();
+ uint getSent();
void setVerbosity ( int v ) { verbosity = v; }
void setPersistence ( int p ) { persistence = p; }
@@ -51,7 +54,7 @@ class Sender : public FailoverManager::Command
uint sent;
const uint reportFrequency;
Message message;
-
+
int verbosity;
int persistence;
};
@@ -93,7 +96,11 @@ uint Sender::getSent()
return sent;
}
-int main(int argc, char ** argv)
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
{
ConnectionSettings settings;
@@ -118,23 +125,23 @@ int main(int argc, char ** argv)
connection.execute ( sender );
if ( verbosity > 0 )
{
- std::cout << "Sender finished. Sent "
- << sender.getSent()
- << " messages."
+ std::cout << "Sender finished. Sent "
+ << sender.getSent()
+ << " messages."
<< endl;
}
connection.close();
- return 0;
- }
- catch(const std::exception& error)
+ return 0;
+ }
+ catch(const std::exception& error)
{
- cerr << "Sender (host: "
- << settings.host
- << " port: "
+ cerr << "Sender (host: "
+ << settings.host
+ << " port: "
<< settings.port
<< " ) "
- << " Failed: "
- << error.what()
+ << " Failed: "
+ << error.what()
<< std::endl;
}
return 1;
diff --git a/qpid/cpp/src/tests/resuming_receiver.cpp b/qpid/cpp/src/tests/resuming_receiver.cpp
index ef559a009d..807bd83bee 100644
--- a/qpid/cpp/src/tests/resuming_receiver.cpp
+++ b/qpid/cpp/src/tests/resuming_receiver.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -35,8 +35,11 @@ using namespace qpid::framing;
using namespace std;
-class Listener : public MessageListener,
- public FailoverManager::Command,
+namespace qpid {
+namespace tests {
+
+class Listener : public MessageListener,
+ public FailoverManager::Command,
public FailoverManager::ReconnectionStrategy
{
public:
@@ -57,32 +60,32 @@ class Listener : public MessageListener,
};
-Listener::Listener(int freq, int verbosity)
- : count(0),
- received_twice(0),
- lastSn(0),
- gaps(false),
+Listener::Listener(int freq, int verbosity)
+ : count(0),
+ received_twice(0),
+ lastSn(0),
+ gaps(false),
reportFrequency(freq),
verbosity(verbosity),
done(false)
{}
-void Listener::received(Message & message)
+void Listener::received(Message & message)
{
- if (message.getData() == "That's all, folks!")
+ if (message.getData() == "That's all, folks!")
{
done = true;
if(verbosity > 0 )
{
- std::cout << "Shutting down listener for "
+ std::cout << "Shutting down listener for "
<< message.getDestination() << std::endl;
- std::cout << "Listener received "
- << count
- << " messages ("
- << received_twice
- << " received_twice)"
+ std::cout << "Listener received "
+ << count
+ << " messages ("
+ << received_twice
+ << " received_twice)"
<< endl;
}
subscription.cancel();
@@ -99,8 +102,8 @@ void Listener::received(Message & message)
++count;
if ( ! ( count % reportFrequency ) ) {
if ( verbosity > 0 )
- std::cout << "Listener has received "
- << count
+ std::cout << "Listener has received "
+ << count
<< " messages.\n";
}
} else {
@@ -133,6 +136,10 @@ void Listener::editUrlList(std::vector<Url>& urls)
if (urls.size() > 1) std::rotate(urls.begin(), urls.begin() + 1, urls.end());
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char ** argv)
{
ConnectionSettings settings;
diff --git a/qpid/cpp/src/tests/sender.cpp b/qpid/cpp/src/tests/sender.cpp
index 311de2e5f8..4e845c42b4 100644
--- a/qpid/cpp/src/tests/sender.cpp
+++ b/qpid/cpp/src/tests/sender.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -37,22 +37,27 @@ using namespace qpid::framing;
using namespace std;
-struct Args : public qpid::TestOptions
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
{
string destination;
string key;
uint sendEos;
bool durable;
+ uint ttl;
string lvqMatchValue;
string lvqMatchFile;
- Args() : key("test-queue"), sendEos(0), durable(false)
+ Args() : key("test-queue"), sendEos(0), durable(false), ttl(0)
{
addOptions()
("exchange", qpid::optValue(destination, "EXCHANGE"), "Exchange to send messages to")
("routing-key", qpid::optValue(key, "KEY"), "Routing key to add to messages")
("send-eos", qpid::optValue(sendEos, "N"), "Send N EOS messages to mark end of input")
("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.")
+ ("ttl", qpid::optValue(ttl, "msecs"), "Time-to-live for messages, in milliseconds")
("lvq-match-value", qpid::optValue(lvqMatchValue, "KEY"), "The value to set for the LVQ match key property")
("lvq-match-file", qpid::optValue(lvqMatchFile, "FILE"), "A file containing values to set for the LVQ match key property");
}
@@ -63,26 +68,29 @@ const string EOS("eos");
class Sender : public FailoverManager::Command
{
public:
- Sender(const std::string& destination, const std::string& key, uint sendEos, bool durable,
+ Sender(const std::string& destination, const std::string& key, uint sendEos, bool durable, uint ttl,
const std::string& lvqMatchValue, const std::string& lvqMatchFile);
void execute(AsyncSession& session, bool isRetry);
private:
const std::string destination;
MessageReplayTracker sender;
- Message message;
+ Message message;
const uint sendEos;
uint sent;
std::ifstream lvqMatchValues;
};
-Sender::Sender(const std::string& dest, const std::string& key, uint eos, bool durable,
- const std::string& lvqMatchValue, const std::string& lvqMatchFile) :
+Sender::Sender(const std::string& dest, const std::string& key, uint eos, bool durable, uint ttl, const std::string& lvqMatchValue, const std::string& lvqMatchFile) :
destination(dest), sender(10), message("", key), sendEos(eos), sent(0) , lvqMatchValues(lvqMatchFile.c_str())
{
if (durable){
message.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
}
+ if (ttl) {
+ message.getDeliveryProperties().setTtl(ttl);
+ }
+
if (!lvqMatchValue.empty()) {
message.getHeaders().setString(QueueOptions::strLVQMatchProperty, lvqMatchValue);
}
@@ -108,16 +116,20 @@ void Sender::execute(AsyncSession& session, bool isRetry)
}
}
-int main(int argc, char ** argv)
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
{
Args opts;
try {
opts.parse(argc, argv);
FailoverManager connection(opts.con);
- Sender sender(opts.destination, opts.key, opts.sendEos, opts.durable, opts.lvqMatchValue, opts.lvqMatchFile);
+ Sender sender(opts.destination, opts.key, opts.sendEos, opts.durable, opts.ttl, opts.lvqMatchValue, opts.lvqMatchFile);
connection.execute(sender);
connection.close();
- return 0;
+ return 0;
} catch(const std::exception& error) {
std::cout << "Failed: " << error.what() << std::endl;
}
diff --git a/qpid/cpp/src/tests/shlibtest.cpp b/qpid/cpp/src/tests/shlibtest.cpp
index e485cc9397..5655eb7e64 100644
--- a/qpid/cpp/src/tests/shlibtest.cpp
+++ b/qpid/cpp/src/tests/shlibtest.cpp
@@ -18,6 +18,9 @@
*
*/
+namespace qpid {
+namespace tests {
+
int* loaderData = 0;
extern "C"
#ifdef WIN32
@@ -28,5 +31,4 @@ void callMe(int *i) { loaderData=i; }
struct OnUnload { ~OnUnload() { *loaderData=42; } };
OnUnload unloader; // For destructor.
-
-
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/test_store.cpp b/qpid/cpp/src/tests/test_store.cpp
index 90503818ed..64a96bf71a 100644
--- a/qpid/cpp/src/tests/test_store.cpp
+++ b/qpid/cpp/src/tests/test_store.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,7 +22,7 @@
/**@file
* Plug-in message store for tests.
- *
+ *
* Add functionality as required, build up a comprehensive set of
* features to support persistent behavior tests.
*
@@ -46,6 +46,9 @@ using namespace std;
using namespace boost;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
struct TestStoreOptions : public Options {
string name;
@@ -66,7 +69,7 @@ struct Completer : public Runnable {
delete this;
}
};
-
+
class TestStore : public NullMessageStore {
public:
TestStore(const string& name_, Broker& broker_) : name(name_), broker(broker_) {}
@@ -83,7 +86,7 @@ class TestStore : public NullMessageStore {
// Check the message for special instructions.
size_t i = string::npos;
- size_t j = string::npos;
+ size_t j = string::npos;
if (strncmp(data.c_str(), TEST_STORE_DO.c_str(), strlen(TEST_STORE_DO.c_str())) == 0
&& (i = data.find(name+"[")) != string::npos
&& (j = data.find("]", i)) != string::npos)
@@ -144,3 +147,5 @@ struct TestStorePlugin : public Plugin {
};
static TestStorePlugin pluginInstance;
+
+}} // namespace qpid::tests
diff --git a/qpid/cpp/src/tests/test_tools.h b/qpid/cpp/src/tests/test_tools.h
index 54837d3e5b..832c04af04 100644
--- a/qpid/cpp/src/tests/test_tools.h
+++ b/qpid/cpp/src/tests/test_tools.h
@@ -34,7 +34,7 @@ template <class T> std::ostream& seqPrint(std::ostream& o, const T& seq) {
return o;
}
-// Compare sequences
+// Compare sequences
template <class T, class U>
bool seqEqual(const T& a, const U& b) {
typename T::const_iterator i = a.begin();
@@ -60,6 +60,9 @@ template <class T>
bool operator == (const boost::assign_detail::generic_list<T>& b, const vector<T>& a) { return seqEqual(a, b); }
}
+namespace qpid {
+namespace tests {
+
/** NB: order of parameters is regex first, in line with
* CHECK(expected, actual) convention.
*/
@@ -98,6 +101,7 @@ inline std::string getLibPath(const char* envName, const char* defaultPath = 0)
return defaultPath;
}
+}} // namespace qpid::tests
#endif /*!TEST_TOOLS_H*/
diff --git a/qpid/cpp/src/tests/topic_listener.cpp b/qpid/cpp/src/tests/topic_listener.cpp
index 44070cd4c9..aa8c19df99 100644
--- a/qpid/cpp/src/tests/topic_listener.cpp
+++ b/qpid/cpp/src/tests/topic_listener.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,7 @@
* This file provides one half of a test and example of a pub-sub
* style of interaction. See topic_publisher.cpp for the other half,
* in which the logic for publishing is defined.
- *
+ *
* This file contains the listener logic. A listener will subscribe to
* a logical 'topic'. It will count the number of messages it receives
* and the time elapsed between the first one and the last one. It
@@ -50,11 +50,14 @@ using namespace qpid::sys;
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
/**
* A message listener implementation in which the runtime logic is
* defined.
*/
-class Listener : public MessageListener{
+class Listener : public MessageListener{
Session session;
SubscriptionManager& mgr;
const string responseQueue;
@@ -62,7 +65,7 @@ class Listener : public MessageListener{
bool init;
int count;
AbsTime start;
-
+
void shutdown();
void report();
public:
@@ -91,6 +94,52 @@ struct Args : public qpid::TestOptions {
}
};
+Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
+ session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
+
+void Listener::received(Message& message){
+ if(!init){
+ start = now();
+ count = 0;
+ init = true;
+ cout << "Batch started." << endl;
+ }
+ string type = message.getHeaders().getAsString("TYPE");
+
+ if(string("TERMINATION_REQUEST") == type){
+ shutdown();
+ }else if(string("REPORT_REQUEST") == type){
+ subscription.accept(subscription.getUnaccepted()); // Accept everything upto this point
+ cout <<"Batch ended, sending report." << endl;
+ //send a report:
+ report();
+ init = false;
+ }else if (++count % 1000 == 0){
+ cout <<"Received " << count << " messages." << endl;
+ }
+}
+
+void Listener::shutdown(){
+ mgr.stop();
+}
+
+void Listener::report(){
+ AbsTime finish = now();
+ Duration time(start, finish);
+ stringstream reportstr;
+ reportstr << "Received " << count << " messages in "
+ << time/TIME_MSEC << " ms.";
+ Message msg(reportstr.str(), responseQueue);
+ msg.getHeaders().setString("TYPE", "REPORT");
+ session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
/**
* The main routine creates a Listener instance and sets it up to
@@ -142,7 +191,7 @@ int main(int argc, char** argv){
if (args.transactional) {
session.txSelect();
}
-
+
cout << "topic_listener: listening..." << endl;
mgr.run();
if (args.durable) {
@@ -158,47 +207,3 @@ int main(int argc, char** argv){
}
return 1;
}
-
-Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
- session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
-
-void Listener::received(Message& message){
- if(!init){
- start = now();
- count = 0;
- init = true;
- cout << "Batch started." << endl;
- }
- string type = message.getHeaders().getAsString("TYPE");
-
- if(string("TERMINATION_REQUEST") == type){
- shutdown();
- }else if(string("REPORT_REQUEST") == type){
- subscription.accept(subscription.getUnaccepted()); // Accept everything upto this point
- cout <<"Batch ended, sending report." << endl;
- //send a report:
- report();
- init = false;
- }else if (++count % 1000 == 0){
- cout <<"Received " << count << " messages." << endl;
- }
-}
-
-void Listener::shutdown(){
- mgr.stop();
-}
-
-void Listener::report(){
- AbsTime finish = now();
- Duration time(start, finish);
- stringstream reportstr;
- reportstr << "Received " << count << " messages in "
- << time/TIME_MSEC << " ms.";
- Message msg(reportstr.str(), responseQueue);
- msg.getHeaders().setString("TYPE", "REPORT");
- session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
- if(transactional){
- sync(session).txCommit();
- }
-}
-
diff --git a/qpid/cpp/src/tests/topic_publisher.cpp b/qpid/cpp/src/tests/topic_publisher.cpp
index 40055bbfa0..3381132b1a 100644
--- a/qpid/cpp/src/tests/topic_publisher.cpp
+++ b/qpid/cpp/src/tests/topic_publisher.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,7 @@
* This file provides one half of a test and example of a pub-sub
* style of interaction. See topic_listener.cpp for the other half, in
* which the logic for subscribers is defined.
- *
+ *
* This file contains the publisher logic. The publisher will send a
* number of messages to the exchange with the appropriate routing key
* for the logical 'topic'. Once it has done this it will then send a
@@ -49,19 +49,22 @@ using namespace qpid::client;
using namespace qpid::sys;
using namespace std;
+namespace qpid {
+namespace tests {
+
/**
* The publishing logic is defined in this class. It implements
* message listener and can therfore be used to receive messages sent
* back by the subscribers.
*/
-class Publisher {
+class Publisher {
AsyncSession session;
SubscriptionManager mgr;
LocalQueue queue;
const string controlTopic;
const bool transactional;
const bool durable;
-
+
string generateData(int size);
public:
@@ -99,6 +102,64 @@ struct Args : public TestOptions {
}
};
+Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
+ session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
+{
+ mgr.subscribe(queue, "response");
+}
+
+int64_t Publisher::publish(int msgs, int listeners, int size){
+ Message msg(generateData(size), controlTopic);
+ if (durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+ AbsTime start = now();
+
+ for(int i = 0; i < msgs; i++){
+ session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
+ }
+ //send report request
+ Message reportRequest("", controlTopic);
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+ //wait for a response from each listener (TODO, could log these)
+ for (int i = 0; i < listeners; i++) {
+ Message report = queue.pop();
+ }
+
+ if(transactional){
+ sync(session).txCommit();
+ }
+
+ AbsTime finish = now();
+ return Duration(start, finish);
+}
+
+string Publisher::generateData(int size){
+ string data;
+ for(int i = 0; i < size; i++){
+ data += ('A' + (i / 26));
+ }
+ return data;
+}
+
+void Publisher::terminate(){
+ //send termination request
+ Message terminationRequest("", controlTopic);
+ terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
+ session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ session.txCommit();
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv) {
try{
Args args;
@@ -120,11 +181,11 @@ int main(int argc, char** argv) {
Message m = statusQ.get();
if( m.getData().find("topic_listener: ", 0) == 0 ) {
cout << "Listener " << (i+1) << " of " << args.subscribers
- << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
- << ")" << endl;
+ << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
+ << ")" << endl;
} else {
throw Exception(QPID_MSG("Unexpected message received on status queue: " << m.getData()));
- }
+ }
}
}
@@ -150,12 +211,12 @@ int main(int argc, char** argv) {
if(!min || msecs < min) min = msecs;
sum += msecs;
cout << "Completed " << (i+1) << " of " << batchSize
- << " in " << msecs << "ms" << endl;
+ << " in " << msecs << "ms" << endl;
}
publisher.terminate();
int64_t avg = sum / batchSize;
if(batchSize > 1){
- cout << batchSize << " batches completed. avg=" << avg <<
+ cout << batchSize << " batches completed. avg=" << avg <<
", max=" << max << ", min=" << min << endl;
}
session.close();
@@ -167,57 +228,3 @@ int main(int argc, char** argv) {
}
return 1;
}
-
-Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
- session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
-{
- mgr.subscribe(queue, "response");
-}
-
-int64_t Publisher::publish(int msgs, int listeners, int size){
- Message msg(generateData(size), controlTopic);
- if (durable) {
- msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
- }
- AbsTime start = now();
-
- for(int i = 0; i < msgs; i++){
- session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
- }
- //send report request
- Message reportRequest("", controlTopic);
- reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
- session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
- if(transactional){
- sync(session).txCommit();
- }
- //wait for a response from each listener (TODO, could log these)
- for (int i = 0; i < listeners; i++) {
- Message report = queue.pop();
- }
-
- if(transactional){
- sync(session).txCommit();
- }
-
- AbsTime finish = now();
- return Duration(start, finish);
-}
-
-string Publisher::generateData(int size){
- string data;
- for(int i = 0; i < size; i++){
- data += ('A' + (i / 26));
- }
- return data;
-}
-
-void Publisher::terminate(){
- //send termination request
- Message terminationRequest("", controlTopic);
- terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
- session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
- if(transactional){
- session.txCommit();
- }
-}
diff --git a/qpid/cpp/src/tests/txjob.cpp b/qpid/cpp/src/tests/txjob.cpp
index 94db96a666..a7a905c1b7 100644
--- a/qpid/cpp/src/tests/txjob.cpp
+++ b/qpid/cpp/src/tests/txjob.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,7 +33,10 @@
using namespace qpid::client;
using namespace qpid::sys;
-struct Args : public qpid::TestOptions
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
{
string workQueue;
string source;
@@ -43,10 +46,10 @@ struct Args : public qpid::TestOptions
bool quit;
bool declareQueues;
- Args() : workQueue("txshift-control"), source("txshift-1"), dest("txshift-2"), messages(0), jobs(0),
+ Args() : workQueue("txshift-control"), source("txshift-1"), dest("txshift-2"), messages(0), jobs(0),
quit(false), declareQueues(false)
{
- addOptions()
+ addOptions()
("messages", qpid::optValue(messages, "N"), "Number of messages to shift")
("jobs", qpid::optValue(jobs, "N"), "Number of shift jobs to request")
("source", qpid::optValue(source, "QUEUE NAME"), "source queue from which messages will be shifted")
@@ -57,6 +60,10 @@ struct Args : public qpid::TestOptions
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
//TODO: might be nice to make this capable of failover as well at some
//point; for now its just for the setup phase.
int main(int argc, char** argv)
diff --git a/qpid/cpp/src/tests/txshift.cpp b/qpid/cpp/src/tests/txshift.cpp
index 97135c9829..882d3716d8 100644
--- a/qpid/cpp/src/tests/txshift.cpp
+++ b/qpid/cpp/src/tests/txshift.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -34,14 +34,17 @@
using namespace qpid::client;
using namespace qpid::sys;
-struct Args : public qpid::TestOptions
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
{
string workQueue;
size_t workers;
Args() : workQueue("txshift-control"), workers(1)
{
- addOptions()
+ addOptions()
("workers", qpid::optValue(workers, "N"), "Number of separate worker sessions to start")
("work-queue", qpid::optValue(workQueue, "NAME"), "work queue from which to take instructions");
}
@@ -61,7 +64,7 @@ struct Transfer : MessageListener
Transfer(const std::string control_) : control(control_), expected(0), transfered(0) {}
- void subscribeToSource(SubscriptionManager manager)
+ void subscribeToSource(SubscriptionManager manager)
{
sourceSettings.autoAck = 0;//will accept once at the end of the batch
sourceSettings.flowControl = FlowControl::messageCredit(expected);
@@ -69,7 +72,7 @@ struct Transfer : MessageListener
QPID_LOG(info, "Subscribed to source: " << source << " expecting: " << expected);
}
- void subscribeToControl(SubscriptionManager manager)
+ void subscribeToControl(SubscriptionManager manager)
{
controlSettings.flowControl = FlowControl::messageCredit(1);
controlSubscription = manager.subscribe(*this, control, controlSettings);
@@ -94,7 +97,7 @@ struct Transfer : MessageListener
message.getDeliveryProperties().setRoutingKey(destination);
async(sourceSubscription.getSession()).messageTransfer(arg::content=message);
if (++transfered == expected) {
- QPID_LOG(info, "completed job: " << transfered << " messages shifted from " <<
+ QPID_LOG(info, "completed job: " << transfered << " messages shifted from " <<
source << " to " << destination);
sourceSubscription.accept(sourceSubscription.getUnaccepted());
sourceSubscription.getSession().txCommit();
@@ -111,7 +114,7 @@ struct Transfer : MessageListener
destination = message.getHeaders().getAsString("dest");
expected = message.getHeaders().getAsInt("count");
transfered = 0;
- QPID_LOG(info, "received transfer request: " << expected << " messages to be shifted from " <<
+ QPID_LOG(info, "received transfer request: " << expected << " messages to be shifted from " <<
source << " to " << destination);
subscribeToSource(controlSubscription.getSubscriptionManager());
} else if (message.getData() == "quit") {
@@ -133,7 +136,7 @@ struct Worker : FailoverManager::Command, Runnable
Worker(FailoverManager& c, const std::string& controlQueue) : connection(c), transfer(controlQueue) {}
- void run()
+ void run()
{
connection.execute(*this);
}
@@ -148,7 +151,7 @@ struct Worker : FailoverManager::Command, Runnable
runner.join();
}
- void execute(AsyncSession& session, bool isRetry)
+ void execute(AsyncSession& session, bool isRetry)
{
if (isRetry) QPID_LOG(info, "Retrying...");
session.txSelect();
@@ -159,6 +162,10 @@ struct Worker : FailoverManager::Command, Runnable
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
Args opts;
diff --git a/qpid/cpp/src/tests/txtest.cpp b/qpid/cpp/src/tests/txtest.cpp
index c1ee246e2c..d0ba2f1245 100644
--- a/qpid/cpp/src/tests/txtest.cpp
+++ b/qpid/cpp/src/tests/txtest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,7 +33,7 @@
#include "qpid/client/SubscriptionManager.h"
#include "qpid/framing/Array.h"
#include "qpid/framing/Buffer.h"
-#include "qpid/sys/uuid.h"
+#include "qpid/framing/Uuid.h"
#include "qpid/sys/Thread.h"
using namespace qpid;
@@ -41,6 +41,9 @@ using namespace qpid::client;
using namespace qpid::sys;
using std::string;
+namespace qpid {
+namespace tests {
+
typedef std::vector<std::string> StringSet;
struct Args : public qpid::TestOptions {
@@ -55,12 +58,12 @@ struct Args : public qpid::TestOptions {
bool dtx;
bool quiet;
- Args() : init(true), transfer(true), check(true),
- size(256), durable(true), queues(2),
+ Args() : init(true), transfer(true), check(true),
+ size(256), durable(true), queues(2),
base("tx-test"), msgsPerTx(1), txCount(1), totalMsgCount(10),
dtx(false), quiet(false)
{
- addOptions()
+ addOptions()
("init", optValue(init, "yes|no"), "Declare queues and populate one with the initial set of messages.")
("transfer", optValue(transfer, "yes|no"), "'Move' messages from one queue to another using transactions to ensure no message loss.")
@@ -83,7 +86,7 @@ std::string generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -103,18 +106,18 @@ void generateSet(const std::string& base, uint count, StringSet& collection)
Args opts;
-struct Client
+struct Client
{
Connection connection;
AsyncSession session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
}
- ~Client()
+ ~Client()
{
try{
session.close();
@@ -130,25 +133,23 @@ struct Transfer : public Client, public Runnable
std::string src;
std::string dest;
Thread thread;
- uuid_t uuid;
- char uuidStr[37]; // Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + trailing \0
framing::Xid xid;
Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid(0x4c414e47, "", from) {}
- void run()
+ void run()
{
try {
-
+
if (opts.dtx) session.dtxSelect();
else session.txSelect();
SubscriptionManager subs(session);
-
+
LocalQueue lq;
SubscriptionSettings settings(FlowControl::messageWindow(opts.msgsPerTx));
settings.autoAck = 0; // Disabled
Subscription sub = subs.subscribe(lq, src, settings);
-
+
for (uint t = 0; t < opts.txCount; t++) {
Message in;
Message out("", dest);
@@ -184,13 +185,12 @@ struct Transfer : public Client, public Runnable
}
void setNewXid(framing::Xid& xid) {
- ::uuid_generate(uuid);
- ::uuid_unparse(uuid, uuidStr);
- xid.setGlobalId(uuidStr);
+ framing::Uuid uuid(true);
+ xid.setGlobalId(uuid.str());
}
};
-struct Controller : public Client
+struct Controller : public Client
{
StringSet ids;
StringSet queues;
@@ -201,7 +201,7 @@ struct Controller : public Client
generateSet("msg", opts.totalMsgCount, ids);
}
- void init()
+ void init()
{
//declare queues
for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
@@ -239,7 +239,7 @@ struct Controller : public Client
}
}
- int check()
+ int check()
{
SubscriptionManager subs(session);
@@ -294,10 +294,10 @@ struct Controller : public Client
//check that drained == ids
StringSet missing;
- set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
+ set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
StringSet extra;
- set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
+ set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
if (missing.empty() && extra.empty()) {
std::cout << "All expected messages were retrieved." << std::endl;
@@ -306,26 +306,30 @@ struct Controller : public Client
if (!missing.empty()) {
std::cout << "The following ids were missing:" << std::endl;
for (StringSet::iterator i = missing.begin(); i != missing.end(); i++) {
- std::cout << " '" << *i << "'" << std::endl;
- }
+ std::cout << " '" << *i << "'" << std::endl;
+ }
}
if (!extra.empty()) {
std::cout << "The following extra ids were encountered:" << std::endl;
for (StringSet::iterator i = extra.begin(); i != extra.end(); i++) {
- std::cout << " '" << *i << "'" << std::endl;
- }
+ std::cout << " '" << *i << "'" << std::endl;
+ }
}
return 1;
}
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
opts.parse(argc, argv);
Controller controller;
- if (opts.init) controller.init();
+ if (opts.init) controller.init();
if (opts.transfer) controller.transfer();
if (opts.check) return controller.check();
return 0;
diff --git a/qpid/cpp/src/windows/QpiddBroker.cpp b/qpid/cpp/src/windows/QpiddBroker.cpp
index 5c6eef48f8..5bf9477e6a 100644
--- a/qpid/cpp/src/windows/QpiddBroker.cpp
+++ b/qpid/cpp/src/windows/QpiddBroker.cpp
@@ -133,6 +133,14 @@ void ShutdownHandler::run() {
}
}
+// Console control handler to properly handle ctl-c.
+BOOL CtrlHandler(DWORD ctl)
+{
+ ShutdownEvent shutter; // no pid specified == shut me down
+ shutter.signal();
+ return ((ctl == CTRL_C_EVENT || ctl == CTRL_CLOSE_EVENT) ? TRUE : FALSE);
+}
+
}
struct ProcessControlOptions : public qpid::Options {
@@ -245,6 +253,7 @@ int QpiddBroker::execute (QpiddOptions *options) {
ShutdownHandler waitShut(brokerPtr);
qpid::sys::Thread waitThr(waitShut); // Wait for shutdown event
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
brokerPtr->run();
waitShut.signal(); // In case we shut down some other way
waitThr.join();
diff --git a/qpid/java/broker/bin/qpid-passwd b/qpid/java/broker/bin/qpid-passwd
index 63b30b5e71..b84580da60 100755
--- a/qpid/java/broker/bin/qpid-passwd
+++ b/qpid/java/broker/bin/qpid-passwd
@@ -1,35 +1,35 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-if [ -z "$QPID_HOME" ]; then
- export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
- export PATH=${PATH}:${QPID_HOME}/bin
-fi
-
-# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
-
-# Set other variables used by the qpid-run script before calling
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_MEM=-Xmx1024m \
- QPID_CLASSPATH=$QPID_LIBS
-
-. qpid-run org.apache.qpid.tools.security.Passwd "$@"
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ -z "$QPID_HOME" ]; then
+ export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
+ export PATH=${PATH}:${QPID_HOME}/bin
+fi
+
+# Set classpath to include Qpid jar with all required jars in manifest
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
+
+# Set other variables used by the qpid-run script before calling
+export JAVA=java \
+ JAVA_VM=-server \
+ JAVA_MEM=-Xmx1024m \
+ QPID_CLASSPATH=$QPID_LIBS
+
+. qpid-run org.apache.qpid.tools.security.Passwd "$@"
diff --git a/qpid/java/broker/bin/qpid-server b/qpid/java/broker/bin/qpid-server
index e5a9e998e2..738fc6e084 100755
--- a/qpid/java/broker/bin/qpid-server
+++ b/qpid/java/broker/bin/qpid-server
@@ -26,14 +26,19 @@ fi
# Set classpath to include Qpid jar with all required jars in manifest
QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar
+# Default Log4j to append to its log file
+if [ -z "$QPID_LOG_APPEND" ]; then
+ export QPID_LOG_APPEND="true"
+fi
+
# Set other variables used by the qpid-run script before calling
export JAVA=java \
JAVA_VM=-server \
JAVA_MEM=-Xmx1024m \
JAVA_GC="-XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError" \
QPID_CLASSPATH=$QPID_LIBS \
- QPID_RUN_LOG=2
+ QPID_RUN_LOG=2
-QPID_OPTS="$QPID_OPTS -Damqj.read_write_pool_size=32"
+QPID_OPTS="$QPID_OPTS -Damqj.read_write_pool_size=32 -DQPID_LOG_APPEND=$QPID_LOG_APPEND"
. qpid-run org.apache.qpid.server.Main "$@"
diff --git a/qpid/java/broker/etc/config-systests-derby.xml b/qpid/java/broker/etc/config-systests-derby.xml
deleted file mode 100644
index e9cfa04ab5..0000000000
--- a/qpid/java/broker/etc/config-systests-derby.xml
+++ /dev/null
@@ -1,141 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<broker>
- <prefix>${QPID_HOME}</prefix>
- <work>${QPID_WORK}</work>
- <conf>${prefix}/etc</conf>
- <connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
- <ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
- <keystorePath>/path/to/keystore.ks</keystorePath>
- <keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
- <qpidnio>false</qpidnio>
- <protectio>
- <enabled>false</enabled>
- </protectio>
- <transport>nio</transport>
- <port>5672</port>
- <sslport>8672</sslport>
- <socketReceiveBuffer>32768</socketReceiveBuffer>
- <socketSendBuffer>32768</socketSendBuffer>
- </connector>
- <management>
- <enabled>false</enabled>
- <jmxport>8999</jmxport>
- <ssl>
- <enabled>false</enabled>
- <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
- <keyStorePath>${prefix}/../test-profiles/test_resources/ssl/keystore.jks</keyStorePath>
- <keyStorePassword>password</keyStorePassword>
- </ssl>
- </management>
- <advanced>
- <filterchain enableExecutorPool="true"/>
- <enablePooledAllocator>false</enablePooledAllocator>
- <enableDirectBuffers>false</enableDirectBuffers>
- <framesize>65535</framesize>
- <compressBufferOnQueue>false</compressBufferOnQueue>
- <enableJMSXUserID>false</enableJMSXUserID>
- </advanced>
-
- <security>
- <principal-databases>
- <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
- <principal-database>
- <name>passwordfile</name>
- <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
- <attributes>
- <attribute>
- <name>passwordFile</name>
- <value>${conf}/passwd</value>
- </attribute>
- </attributes>
- </principal-database>
- </principal-databases>
-
- <access>
- <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
- </access>
-
- <msg-auth>false</msg-auth>
-
- <jmx>
- <access>${conf}/jmxremote.access</access>
- <principal-database>passwordfile</principal-database>
- </jmx>
- </security>
-
- <virtualhosts>
- <directory>${conf}/virtualhosts</directory>
-
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <store>
- <class>org.apache.qpid.server.store.DerbyMessageStore</class>
- <environment-path>${work}/derbyDB/localhost-store</environment-path>
- </store>
-
- <housekeeping>
- <expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
- </housekeeping>
-
- </localhost>
- </virtualhost>
-
- <virtualhost>
- <name>development</name>
- <development>
- <store>
- <class>org.apache.qpid.server.store.DerbyMessageStore</class>
- <environment-path>${work}/derbyDB/development-store</environment-path>
- </store>
- </development>
- </virtualhost>
-
- <virtualhost>
- <name>test</name>
- <test>
- <store>
- <class>org.apache.qpid.server.store.DerbyMessageStore</class>
- <environment-path>${work}/derbyDB/test-store</environment-path>
- </store>
- </test>
- </virtualhost>
-
- </virtualhosts>
- <heartbeat>
- <delay>0</delay>
- <timeoutFactor>2.0</timeoutFactor>
- </heartbeat>
- <queue>
- <auto_register>true</auto_register>
- </queue>
-
- <virtualhosts>${conf}/virtualhosts-systests.xml</virtualhosts>
-</broker>
-
-
diff --git a/qpid/java/broker/etc/config-systests.xml b/qpid/java/broker/etc/config-systests.xml
deleted file mode 100644
index 42e8c9dbba..0000000000
--- a/qpid/java/broker/etc/config-systests.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<broker>
- <prefix>${QPID_HOME}</prefix>
- <work>${QPID_WORK}</work>
- <conf>${prefix}/etc</conf>
- <connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
- <ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
- <keystorePath>/path/to/keystore.ks</keystorePath>
- <keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
- <qpidnio>false</qpidnio>
- <protectio>
- <enabled>false</enabled>
- <readBufferLimitSize>262144</readBufferLimitSize>
- <writeBufferLimitSize>262144</writeBufferLimitSize>
- </protectio>
- <transport>nio</transport>
- <port>5672</port>
- <sslport>8672</sslport>
- <socketReceiveBuffer>32768</socketReceiveBuffer>
- <socketSendBuffer>32768</socketSendBuffer>
- </connector>
- <management>
- <enabled>false</enabled>
- <jmxport>8999</jmxport>
- <ssl>
- <enabled>false</enabled>
- <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
- <keyStorePath>${prefix}/../test-profiles/test_resources/ssl/keystore.jks</keyStorePath>
- <keyStorePassword>password</keyStorePassword>
- </ssl>
- </management>
- <advanced>
- <filterchain enableExecutorPool="true"/>
- <enablePooledAllocator>false</enablePooledAllocator>
- <enableDirectBuffers>false</enableDirectBuffers>
- <framesize>65535</framesize>
- <compressBufferOnQueue>false</compressBufferOnQueue>
- <enableJMSXUserID>false</enableJMSXUserID>
- <locale>en_US</locale>
- </advanced>
-
- <security>
- <principal-databases>
- <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
- <principal-database>
- <name>passwordfile</name>
- <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
- <attributes>
- <attribute>
- <name>passwordFile</name>
- <value>${conf}/passwd</value>
- </attribute>
- </attributes>
- </principal-database>
- </principal-databases>
-
- <access>
- <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
- </access>
-
- <msg-auth>false</msg-auth>
-
- <jmx>
- <access>${conf}/jmxremote.access</access>
- <principal-database>passwordfile</principal-database>
- </jmx>
- </security>
-
- <virtualhosts>
- <directory>${conf}/virtualhosts</directory>
-
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
-
- <housekeeping>
- <expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
- </housekeeping>
-
- </localhost>
- </virtualhost>
-
- <virtualhost>
- <name>development</name>
- <development>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </development>
- </virtualhost>
-
- <virtualhost>
- <name>test</name>
- <test>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </test>
- </virtualhost>
-
- </virtualhosts>
- <heartbeat>
- <delay>0</delay>
- <timeoutFactor>2.0</timeoutFactor>
- </heartbeat>
- <queue>
- <auto_register>true</auto_register>
- </queue>
-
- <status-updates>ON</status-updates>
-
- <virtualhosts>${conf}/virtualhosts-systests.xml</virtualhosts>
-</broker>
-
-
diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml
index 928b773606..8fb3a8cf5a 100644
--- a/qpid/java/broker/etc/config.xml
+++ b/qpid/java/broker/etc/config.xml
@@ -24,17 +24,20 @@
<work>${QPID_WORK}</work>
<conf>${prefix}/etc</conf>
<connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
+ <!-- To enable SSL edit the keystorePath and keystorePassword
+ and set enabled to true.
+ To disasble Non-SSL port set sslOnly to true -->
<ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
+ <enabled>false</enabled>
+ <sslOnly>false</sslOnly>
<keystorePath>/path/to/keystore.ks</keystorePath>
<keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
+ </ssl>
<qpidnio>false</qpidnio>
<protectio>
<enabled>false</enabled>
+ <readBufferLimitSize>262144</readBufferLimitSize>
+ <writeBufferLimitSize>262144</writeBufferLimitSize>
</protectio>
<transport>nio</transport>
<port>5672</port>
@@ -59,6 +62,7 @@
<framesize>65535</framesize>
<compressBufferOnQueue>false</compressBufferOnQueue>
<enableJMSXUserID>false</enableJMSXUserID>
+ <locale>en_US</locale>
</advanced>
<security>
@@ -89,40 +93,143 @@
</security>
<virtualhosts>
- <directory>${conf}/virtualhosts</directory>
+ <default>test</default>
<virtualhost>
<name>localhost</name>
<localhost>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
<housekeeping>
<expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
</housekeeping>
+ <exchanges>
+ <exchange>
+ <type>direct</type>
+ <name>test.direct</name>
+ <durable>true</durable>
+ </exchange>
+ <exchange>
+ <type>topic</type>
+ <name>test.topic</name>
+ </exchange>
+ </exchanges>
+ <queues>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ <maximumMessageCount>50</maximumMessageCount>
+ <!-- 50 messages -->
+
+ <queue>
+ <name>queue</name>
+ </queue>
+ <queue>
+ <name>ping</name>
+ </queue>
+ <queue>
+ <name>test-queue</name>
+ <test-queue>
+ <exchange>test.direct</exchange>
+ <durable>true</durable>
+ </test-queue>
+ </queue>
+ <queue>
+ <name>test-ping</name>
+ <test-ping>
+ <exchange>test.direct</exchange>
+ </test-ping>
+ </queue>
+
+ </queues>
</localhost>
</virtualhost>
+
<virtualhost>
<name>development</name>
<development>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
+
+ <queues>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>50</maximumMessageCount>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </ping>
+ </queue>
+ </queues>
</development>
</virtualhost>
-
<virtualhost>
<name>test</name>
<test>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
+
+ <queues>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>50</maximumMessageCount>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </ping>
+ </queue>
+ </queues>
</test>
</virtualhost>
-
</virtualhosts>
<heartbeat>
<delay>0</delay>
@@ -132,7 +239,8 @@
<auto_register>true</auto_register>
</queue>
- <virtualhosts>${conf}/virtualhosts.xml</virtualhosts>
+ <status-updates>ON</status-updates>
+
</broker>
diff --git a/qpid/java/broker/etc/log4j.xml b/qpid/java/broker/etc/log4j.xml
index a395d0fd56..8ca43ededd 100644
--- a/qpid/java/broker/etc/log4j.xml
+++ b/qpid/java/broker/etc/log4j.xml
@@ -50,7 +50,7 @@
<appender class="org.apache.log4j.FileAppender" name="FileAppender">
<param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
- <param name="Append" value="false"/>
+ <param name="Append" value="${QPID_LOG_APPEND}"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
diff --git a/qpid/java/broker/etc/virtualhosts-systests.xml b/qpid/java/broker/etc/virtualhosts-systests.xml
deleted file mode 100644
index 4f23f55579..0000000000
--- a/qpid/java/broker/etc/virtualhosts-systests.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<virtualhosts>
- <default>test</default>
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <exchanges>
- <exchange>
- <type>direct</type>
- <name>test.direct</name>
- <durable>true</durable>
- </exchange>
- <exchange>
- <type>topic</type>
- <name>test.topic</name>
- </exchange>
- </exchanges>
- <queues>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- <maximumMessageCount>50</maximumMessageCount> <!-- 50 messages -->
-
- <queue>
- <name>queue</name>
- </queue>
- <queue>
- <name>ping</name>
- </queue>
- <queue>
- <name>test-queue</name>
- <test-queue>
- <exchange>test.direct</exchange>
- <durable>true</durable>
- </test-queue>
- </queue>
- <queue>
- <name>test-ping</name>
- <test-ping>
- <exchange>test.direct</exchange>
- </test-ping>
- </queue>
-
- </queues>
- </localhost>
- </virtualhost>
-
-
- <virtualhost>
- <name>development</name>
- <development>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>50</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </development>
- </virtualhost>
- <virtualhost>
- <name>test</name>
- <test>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>50</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </test>
- </virtualhost>
-</virtualhosts>
diff --git a/qpid/java/broker/etc/virtualhosts.xml b/qpid/java/broker/etc/virtualhosts.xml
deleted file mode 100644
index f62ec3f5d7..0000000000
--- a/qpid/java/broker/etc/virtualhosts.xml
+++ /dev/null
@@ -1,123 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<virtualhosts>
- <default>test</default>
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <exchanges>
- <exchange>
- <type>direct</type>
- <name>test.direct</name>
- <durable>true</durable>
- </exchange>
- <exchange>
- <type>topic</type>
- <name>test.topic</name>
- </exchange>
- </exchanges>
- <queues>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
-
- <queue>
- <name>queue</name>
- </queue>
- <queue>
- <name>ping</name>
- </queue>
- <queue>
- <name>test-queue</name>
- <test-queue>
- <exchange>test.direct</exchange>
- <durable>true</durable>
- </test-queue>
- </queue>
- <queue>
- <name>test-ping</name>
- <test-ping>
- <exchange>test.direct</exchange>
- </test-ping>
- </queue>
-
- </queues>
- </localhost>
- </virtualhost>
-
-
- <virtualhost>
- <name>development</name>
- <development>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>5000</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </development>
- </virtualhost>
- <virtualhost>
- <name>test</name>
- <test>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>5000</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </test>
- </virtualhost>
-</virtualhosts>
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 2afd3c1dc3..5cfa8066e5 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
@@ -317,8 +317,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
try
{
queue.delete();
- _messageStore.removeQueue(queue);
-
+ if (queue.isDurable())
+ {
+ _messageStore.removeQueue(queue);
+ }
}
catch (AMQException ex)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index 7ea7738189..ed9d8acc08 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -147,32 +147,27 @@ public class ServerConfiguration implements SignalHandler
Object thing = i.next();
if (thing instanceof String)
{
+ //Open the Virtualhost.xml file and copy values in to main config
XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing);
- List hosts = vhostConfiguration.getList("virtualhost.name");
- for (int j = 0; j < hosts.size(); j++)
- {
- String name = (String) hosts.get(j);
- // Add the keys of the virtual host to the main config then bail out
-
- Configuration myConf = vhostConfiguration.subset("virtualhost." + name);
- Iterator k = myConf.getKeys();
- while (k.hasNext())
- {
- String key = (String) k.next();
- conf.setProperty("virtualhosts.virtualhost."+name+"."+key, myConf.getProperty(key));
- }
- VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost."+name));
- _virtualHosts.put(vhostConfig.getName(), vhostConfig);
- }
- // Grab things other than the virtualhosts themselves
Iterator keys = vhostConfiguration.getKeys();
while (keys.hasNext())
{
String key = (String) keys.next();
- conf.setProperty("virtualhosts."+key, vhostConfiguration.getProperty(key));
+ conf.setProperty("virtualhosts." + key, vhostConfiguration.getProperty(key));
}
}
}
+
+ List hosts = conf.getList("virtualhosts.virtualhost.name");
+ for (int j = 0; j < hosts.size(); j++)
+ {
+ String name = (String) hosts.get(j);
+ // Add the keys of the virtual host to the main config then bail out
+
+ VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost." + name));
+ _virtualHosts.put(vhostConfig.getName(), vhostConfig);
+ }
+
}
private void substituteEnvironmentVariables()
@@ -202,7 +197,7 @@ public class ServerConfiguration implements SignalHandler
}
/**
- * Check the configuration file to see if status updates are enabled.
+ * Check the configuration file to see if status updates are enabled.
* @return true if status updates are enabled
*/
public boolean getStatusUpdatesEnabled()
@@ -466,7 +461,7 @@ public class ServerConfiguration implements SignalHandler
{
return getConfig().getBoolean("management.enabled", true);
}
-
+
public void setManagementEnabled(boolean enabled)
{
getConfig().setProperty("management.enabled", enabled);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java
index 0dffde50fa..bfb122985b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java
@@ -39,4 +39,11 @@ public class StartupRootMessageLogger extends RootMessageLoggerImpl
return true;
}
+ @Override
+ public boolean isMessageEnabled(LogActor actor)
+ {
+ return true;
+ }
+
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
index 42b3b05ac5..aea9ab43ea 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
@@ -379,6 +379,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
try
{
_cs.stop();
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET));
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_1003("RMI ConnectorServer", _cs.getAddress().getPort()));
}
catch (IOException e)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
index 5f52805414..569dd8bdbd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
@@ -109,10 +109,4 @@ public abstract class BasicACLPlugin implements ACLPlugin
// no-op
}
- public boolean supportsTag(String name)
- {
- // This plugin doesn't support any tags
- return false;
- }
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
index fa6b2285eb..9ab3592628 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
@@ -195,10 +195,22 @@ public class VirtualHost implements Accessable
// perform a createExchange twice with the same details in the
// MessageStore(RoutingTable) as some instances may not like that.
// Derby being one.
+ // todo this can be removed with the resolution fo QPID-2096
configFileRT.exchange.clear();
initialiseModel(hostConfig);
+ //todo REMOVE Work Around for QPID-2096
+ // This means that all durable exchanges declared in the configuration
+ // will not be stored in the MessageStore.
+ // They will still be created/registered/available on startup for as
+ // long as they are contained in the configuration. However, when they
+ // are removed from the configuration they will no longer exist.
+ // This differs from durable queues as they will be writen to to the
+ // store. After QPID-2096 has been resolved exchanges will mirror that
+ // functionality.
+ configFileRT.exchange.clear();
+
if (store != null)
{
_messageStore = store;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
index 8cb0837b39..ebfa80d139 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -54,7 +54,7 @@ public class ServerConfigurationTest extends TestCase
_config = new XMLConfiguration();
}
-
+
@Override
public void tearDown() throws Exception
{
@@ -727,7 +727,7 @@ public class ServerConfigurationTest extends TestCase
assertEquals(true, config.getQpidNIO()); // From the second file, not
// present in the first
}
-
+
public void testVariableInterpolation() throws Exception
{
File mainFile = File.createTempFile(getClass().getName(), null);
@@ -742,7 +742,7 @@ public class ServerConfigurationTest extends TestCase
out.close();
ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile());
- assertEquals("Did not get correct interpolated value",
+ assertEquals("Did not get correct interpolated value",
"foo", config.getManagementKeyStorePath());
}
@@ -783,7 +783,7 @@ public class ServerConfigurationTest extends TestCase
out.write("\t</virtualhosts>\n");
out.write("</broker>\n");
out.close();
-
+
// Load config
ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
ApplicationRegistry.initialise(reg, 1);
@@ -795,15 +795,15 @@ public class ServerConfigurationTest extends TestCase
TestIoSession iosession = new TestIoSession();
iosession.setAddress("127.0.0.1");
-
+
AMQProtocolSession session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
-
+
iosession.setAddress("127.1.2.3");
session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
}
-
+
public void testCombinedConfigurationFirewall() throws Exception
{
// Write out config
@@ -870,7 +870,7 @@ public class ServerConfigurationTest extends TestCase
TestIoSession iosession = new TestIoSession();
iosession.setAddress("127.0.0.1");
-
+
AMQProtocolSession session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
}
@@ -947,22 +947,22 @@ public class ServerConfigurationTest extends TestCase
fileBRandom.setLength(0);
fileBRandom.seek(0);
fileBRandom.close();
-
+
out = new FileWriter(fileB);
out.write("<firewall>\n");
out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>");
out.write("</firewall>\n");
out.close();
-
+
reg.getConfiguration().reparseConfigFile();
-
+
assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
-
+
fileBRandom = new RandomAccessFile(fileB, "rw");
fileBRandom.setLength(0);
fileBRandom.seek(0);
fileBRandom.close();
-
+
out = new FileWriter(fileB);
out.write("<firewall>\n");
out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
@@ -970,17 +970,17 @@ public class ServerConfigurationTest extends TestCase
out.close();
reg.getConfiguration().reparseConfigFile();
-
+
assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
}
public void testnewParserOutputVsOldParserOutput() throws ConfigurationException
{
String configDir = System.getProperty("QPID_HOME")+"/etc";
-
- XMLConfiguration oldConfig = new XMLConfiguration(configDir +"/sample-parsed-config.xml");
- Configuration newConfig = new ServerConfiguration(new File(configDir+"/persistent_config-config-test.xml")).getConfig();
-
+
+ XMLConfiguration oldConfig = new XMLConfiguration(configDir +"/config-systests-ServerConfigurationTest-Old.xml");
+ Configuration newConfig = new ServerConfiguration(new File(configDir+"/config-systests-ServerConfigurationTest-New.xml")).getConfig();
+
Iterator xmlKeys = oldConfig.getKeys();
while (xmlKeys.hasNext())
{
@@ -988,6 +988,21 @@ public class ServerConfigurationTest extends TestCase
assertEquals("Incorrect value for "+key, oldConfig.getProperty(key), newConfig.getProperty(key));
}
}
-
-
+
+
+ public void testNoVirtualhostXMLFile() throws Exception
+ {
+ int REGISTRY=1;
+
+ File configFile = new File(System.getProperty("QPID_HOME")+"/etc/config.xml");
+ assertTrue(configFile.exists());
+
+ ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile), REGISTRY);
+
+ VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance(REGISTRY).getVirtualHostRegistry();
+
+ assertEquals("Incorrect virtualhost count", 3 , virtualHostRegistry.getVirtualHosts().size());
+ }
+
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
index a964fa931c..0e754e2c87 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
@@ -47,17 +47,4 @@ public class ExchangeDenier extends AllowAll
{
return AuthzResult.DENIED;
}
-
- @Override
- public String getPluginName()
- {
- return getClass().getSimpleName();
- }
-
- @Override
- public boolean supportsTag(String name)
- {
- return name.equals("exchangeDenier");
- }
-
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
index 05ac3dca9e..6bae0166d1 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
@@ -39,9 +39,4 @@ public class AMQAuthenticationException extends AMQException
{
super(error, msg, cause);
}
- public boolean isHardError()
- {
- return true;
- }
-
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 118be75705..2e3e417c95 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -65,6 +65,7 @@ import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.AMQChannelClosedException;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverNoopSupport;
import org.apache.qpid.client.failover.FailoverProtectedOperation;
@@ -205,9 +206,9 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
*/
protected static final boolean DEFAULT_MANDATORY = Boolean.parseBoolean(System.getProperty("qpid.default_mandatory", "true"));
- protected static final boolean DECLARE_QUEUES =
+ protected final boolean DECLARE_QUEUES =
Boolean.parseBoolean(System.getProperty("qpid.declare_queues", "true"));
- protected static final boolean DECLARE_EXCHANGES =
+ protected final boolean DECLARE_EXCHANGES =
Boolean.parseBoolean(System.getProperty("qpid.declare_exchanges", "true"));
/** System property to enable strict AMQP compliance. */
@@ -629,6 +630,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
*/
public void close(long timeout) throws JMSException
{
+ close(timeout, true);
+ }
+
+ private void close(long timeout, boolean sendClose) throws JMSException
+ {
if (_logger.isInfoEnabled())
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -654,9 +660,12 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// If the connection is open or we are in the process
// of closing the connection then send a cance
// no point otherwise as the connection will be gone
- if (!_connection.isClosed() || _connection.isClosing())
+ if (!_connection.isClosed() || _connection.isClosing())
{
- sendClose(timeout);
+ if (sendClose)
+ {
+ sendClose(timeout);
+ }
}
}
catch (AMQException e)
@@ -712,25 +721,22 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (!_closed.getAndSet(true))
{
- synchronized (getFailoverMutex())
+ synchronized (_messageDeliveryLock)
{
- synchronized (_messageDeliveryLock)
+ // An AMQException has an error code and message already and will be passed in when closure occurs as a
+ // result of a channel close request
+ AMQException amqe;
+ if (e instanceof AMQException)
{
- // An AMQException has an error code and message already and will be passed in when closure occurs as a
- // result of a channel close request
- AMQException amqe;
- if (e instanceof AMQException)
- {
- amqe = (AMQException) e;
- }
- else
- {
- amqe = new AMQException("Closing session forcibly", e);
- }
-
- _connection.deregisterSession(_channelId);
- closeProducersAndConsumers(amqe);
+ amqe = (AMQException) e;
+ }
+ else
+ {
+ amqe = new AMQException("Closing session forcibly", e);
}
+
+ _connection.deregisterSession(_channelId);
+ closeProducersAndConsumers(amqe);
}
}
}
@@ -1737,6 +1743,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
+ if (e instanceof AMQChannelClosedException)
+ {
+ close(-1, false);
+ }
+
JMSException ex = new JMSException("Error registering consumer: " + e);
ex.setLinkedException(e);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index fa4e08f62b..d7196c0abb 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -33,6 +33,7 @@ import org.apache.qpid.client.message.*;
import org.apache.qpid.client.message.AMQMessageDelegateFactory;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
+import org.apache.qpid.client.state.AMQState;
import org.apache.qpid.common.AMQPFilterTypes;
import org.apache.qpid.framing.*;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
@@ -116,12 +117,23 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendClose(long timeout) throws AMQException, FailoverException
{
- getProtocolHandler().closeSession(this);
- getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
- new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
- ChannelCloseOkBody.class, timeout);
- // When control resumes at this point, a reply will have been received that
- // indicates the broker has closed the channel successfully.
+ // we also need to check the state manager for 08/09 as the
+ // _connection variable may not be updated in time by the error receiving
+ // thread.
+ // We can't close the session if we are alreadying in the process of
+ // closing/closed the connection.
+
+ if (!(getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED)
+ || getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSING)))
+ {
+
+ getProtocolHandler().closeSession(this);
+ getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
+ new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
+ ChannelCloseOkBody.class, timeout);
+ // When control resumes at this point, a reply will have been received that
+ // indicates the broker has closed the channel successfully.
+ }
}
public void sendCommit() throws AMQException, FailoverException
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
index 2b6745ebe4..2cf19bf391 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
@@ -32,7 +32,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ChannelCloseBody;
import org.apache.qpid.framing.ChannelCloseOkBody;
import org.apache.qpid.protocol.AMQConstant;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +47,7 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
}
public void methodReceived(AMQProtocolSession session, ChannelCloseBody method, int channelId)
- throws AMQException
+ throws AMQException
{
_logger.debug("ChannelClose method received");
@@ -59,52 +58,62 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
_logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
}
-
-
ChannelCloseOkBody body = session.getMethodRegistry().createChannelCloseOkBody();
AMQFrame frame = body.generateFrame(channelId);
session.writeFrame(frame);
-
- if (errorCode != AMQConstant.REPLY_SUCCESS)
+ try
{
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
- }
-
- if (errorCode == AMQConstant.NO_CONSUMERS)
- {
- throw new AMQNoConsumersException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.NO_ROUTE)
- {
- throw new AMQNoRouteException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
{
- _logger.debug("Broker responded with Invalid Argument.");
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
+ }
+
+ if (errorCode == AMQConstant.NO_CONSUMERS)
+ {
+ throw new AMQNoConsumersException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ throw new AMQNoRouteException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ {
+ _logger.debug("Broker responded with Invalid Argument.");
+
+ throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
+ {
+ _logger.debug("Broker responded with Invalid Routing Key.");
+
+ throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
+ }
+ else
+ {
+
+ throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
+ }
- throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
- }
- else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
- {
- _logger.debug("Broker responded with Invalid Routing Key.");
-
- throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
- }
- else
- {
- throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
}
-
}
- // fixme why is this only done when the close is expected...
- // should the above forced closes not also cause a close?
- // ----------
- // Closing the session only when it is expected allows the errors to be processed
- // Calling this here will prevent failover. So we should do this for all exceptions
- // that should never cause failover. Such as authentication errors.
-
- session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ finally
+ {
+ // fixme why is this only done when the close is expected...
+ // should the above forced closes not also cause a close?
+ // ----------
+ // Closing the session only when it is expected allows the errors to be processed
+ // Calling this here will prevent failover. So we should do this for all exceptions
+ // that should never cause failover. Such as authentication errors.
+ // ----
+ // 2009-09-07 - ritchiem
+ // calling channelClosed will only close this session and will not
+ // prevent failover. If we don't close the session here then we will
+ // have problems during the session close as it will attempt to
+ // close the session that the broker has closed,
+
+ session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ }
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
index e639a33450..e40cafd72f 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
@@ -40,7 +40,6 @@ public class ConnectionOpenOkMethodHandler implements StateAwareMethodListener<C
}
public void methodReceived(AMQProtocolSession session, ConnectionOpenOkBody body, int channelId)
- throws AMQException
{
session.getStateManager().changeState(AMQState.CONNECTION_OPEN);
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
index e4e58c317d..287b5957a1 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
@@ -45,7 +45,6 @@ public class ConnectionTuneMethodHandler implements StateAwareMethodListener<Con
{ }
public void methodReceived(AMQProtocolSession session, ConnectionTuneBody frame, int channelId)
- throws AMQException
{
_logger.debug("ConnectionTune frame received");
final MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
index f2aca58deb..8782e00a12 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
@@ -52,7 +52,7 @@ public class AMQIoTransportProtocolSession extends AMQProtocolSession
}
@Override
- public void closeProtocolSession(boolean waitLast) throws AMQException
+ public void closeProtocolSession(boolean waitLast)
{
_ioSender.close();
_protocolHandler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index 2389c9e2da..6f62070fd0 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -259,7 +259,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
/**
* Called when we want to create a new IoTransport session
- * @param brokerDetail
+ * @param brokerDetail
*/
public void createIoTransportSession(BrokerDetails brokerDetail)
{
@@ -271,7 +271,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
brokerDetail.useSSL());
_protocolSession.init();
}
-
+
/**
* Called when the network connection is closed. This can happen, either because the client explicitly requested
* that the connection be closed, in which case nothing is done, or because the connection died. In the case
@@ -433,12 +433,11 @@ public class AMQProtocolHandler extends IoHandlerAdapter
* @param e the exception to propagate
*
* @see #propagateExceptionToFrameListeners
- * @see #propagateExceptionToStateWaiters
*/
public void propagateExceptionToAllWaiters(Exception e)
{
+ getStateManager().error(e);
propagateExceptionToFrameListeners(e);
- propagateExceptionToStateWaiters(e);
}
/**
@@ -469,22 +468,6 @@ public class AMQProtocolHandler extends IoHandlerAdapter
}
}
- /**
- * This caters for the case where we only need to propogate an exception to the the state manager to interupt any
- * thing waiting for a state change.
- *
- * Currently (2008-07-15) the state manager is only used during 0-8/0-9 Connection establishement.
- *
- * Normally the state manager would not need to be notified without notifiying the frame listeners so in normal
- * cases {@link #propagateExceptionToAllWaiters} would be the correct choice.
- *
- * @param e the exception to propagate
- */
- public void propagateExceptionToStateWaiters(Exception e)
- {
- getStateManager().error(e);
- }
-
public void notifyFailoverStarting()
{
// Set the last exception in the sync block to ensure the ordering with add.
@@ -601,7 +584,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
_protocolLogger.debug(String.format("SEND: [%s] %s", this, message));
}
-
+
final long sentMessages = _messagesOut++;
final boolean debug = _logger.isDebugEnabled();
@@ -667,7 +650,8 @@ public class AMQProtocolHandler extends IoHandlerAdapter
throw _lastFailoverException;
}
- if(_stateManager.getCurrentState() == AMQState.CONNECTION_CLOSED)
+ if(_stateManager.getCurrentState() == AMQState.CONNECTION_CLOSED ||
+ _stateManager.getCurrentState() == AMQState.CONNECTION_CLOSING)
{
Exception e = _stateManager.getLastException();
if (e != null)
@@ -733,25 +717,31 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void closeConnection(long timeout) throws AMQException
{
- getStateManager().changeState(AMQState.CONNECTION_CLOSING);
-
ConnectionCloseBody body = _protocolSession.getMethodRegistry().createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), // replyCode
new AMQShortString("JMS client is closing the connection."), 0, 0);
final AMQFrame frame = body.generateFrame(0);
- try
- {
- syncWrite(frame, ConnectionCloseOkBody.class, timeout);
- _protocolSession.closeProtocolSession();
- }
- catch (AMQTimeoutException e)
+ //If the connection is already closed then don't do a syncWrite
+ if (getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED))
{
_protocolSession.closeProtocolSession(false);
}
- catch (FailoverException e)
+ else
{
- _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ try
+ {
+ syncWrite(frame, ConnectionCloseOkBody.class, timeout);
+ _protocolSession.closeProtocolSession();
+ }
+ catch (AMQTimeoutException e)
+ {
+ _protocolSession.closeProtocolSession(false);
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ }
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
index 5e12a5e6f8..0e872170aa 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
@@ -410,12 +410,12 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
return (AMQConnection) _minaProtocolSession.getAttribute(AMQ_CONNECTION);
}
- public void closeProtocolSession() throws AMQException
+ public void closeProtocolSession()
{
closeProtocolSession(true);
}
- public void closeProtocolSession(boolean waitLast) throws AMQException
+ public void closeProtocolSession(boolean waitLast)
{
_logger.debug("Waiting for last write to join.");
if (waitLast && (_lastWriteFuture != null))
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
index f8645139f2..70d4697f2c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.io.IOException;
/**
* The state manager is responsible for managing the state of the protocol session. <p/>
@@ -86,7 +87,7 @@ public class AMQStateManager implements AMQMethodListener
return _currentState;
}
- public void changeState(AMQState newState) throws AMQException
+ public void changeState(AMQState newState)
{
_logger.debug("State changing to " + newState + " from old state " + _currentState);
@@ -136,6 +137,22 @@ public class AMQStateManager implements AMQMethodListener
*/
public void error(Exception error)
{
+ if (error instanceof AMQException)
+ {
+ // AMQException should be being notified before closing the
+ // ProtocolSession. Which will change the State to CLOSED.
+ // if we have a hard error.
+ if (((AMQException)error).isHardError())
+ {
+ changeState(AMQState.CONNECTION_CLOSING);
+ }
+ }
+ else
+ {
+ // Be on the safe side here and mark the connection closed
+ changeState(AMQState.CONNECTION_CLOSED);
+ }
+
if (_waiters.size() == 0)
{
_logger.error("No Waiters for error saving as last error:" + error.getMessage());
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java b/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
index ce79080e97..da44822ec3 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
@@ -85,7 +85,7 @@ public class MockAMQConnection extends AMQConnection
}
@Override
- public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException
+ public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException
{
_connected = true;
_protocolHandler.getStateManager().changeState(AMQState.CONNECTION_OPEN);
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
index 10ec220d9e..fc7f8148f0 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
@@ -200,15 +200,8 @@ public class AMQProtocolHandlerTest extends TestCase
_handler.getStateManager().error(trigger);
_logger.info("Setting state to be CONNECTION_CLOSED.");
- try
- {
- _handler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
- }
- catch (AMQException e)
- {
- _logger.error("Unable to change the state to closed.", e);
- fail("Unable to change the state to closed due to :"+e.getMessage());
- }
+
+ _handler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
_logger.info("Firing exception");
_handler.propagateExceptionToFrameListeners(trigger);
diff --git a/qpid/java/doc/broker-priority-queue-subscription.dia b/qpid/java/doc/broker-priority-queue-subscription.dia
new file mode 100644
index 0000000000..2289899435
--- /dev/null
+++ b/qpid/java/doc/broker-priority-queue-subscription.dia
Binary files differ
diff --git a/qpid/java/doc/broker-queue-subscription.dia b/qpid/java/doc/broker-queue-subscription.dia
new file mode 100644
index 0000000000..d146ad136d
--- /dev/null
+++ b/qpid/java/doc/broker-queue-subscription.dia
Binary files differ
diff --git a/qpid/java/broker/etc/persistent_config-config-test.xml b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml
index 258f54397d..33cc90b895 100644
--- a/qpid/java/broker/etc/persistent_config-config-test.xml
+++ b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml
@@ -87,7 +87,7 @@
<auto_register>true</auto_register>
</queue>
- <virtualhosts>${conf}/virtualhosts-config-test.xml</virtualhosts>
+ <virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml</virtualhosts>
</broker>
diff --git a/qpid/java/broker/etc/sample-parsed-config.xml b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml
index 37dfae4d2e..67e0702c41 100644
--- a/qpid/java/broker/etc/sample-parsed-config.xml
+++ b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml
@@ -41,7 +41,7 @@
<principal-database>passwordfile</principal-database>
</jmx>
</security>
-<virtualhosts>${conf}/virtualhosts-config-test.xml
+<virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml
<default>dev-only</default>
<virtualhost>
<name>dev-only</name>
diff --git a/qpid/java/broker/etc/acl.config.xml b/qpid/java/systests/etc/config-systests-acl-settings.xml
index a2b723fc63..c5374a5c5e 100644
--- a/qpid/java/broker/etc/acl.config.xml
+++ b/qpid/java/systests/etc/config-systests-acl-settings.xml
@@ -20,76 +20,12 @@
-
-->
<broker>
- <prefix>${QPID_HOME}</prefix>
- <work>${QPID_WORK}</work>
- <conf>${prefix}/etc</conf>
- <connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
- <ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
- <keystorePath>/path/to/keystore.ks</keystorePath>
- <keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
- <qpidnio>false</qpidnio>
- <!-- I've had the 0.0 and 0.1 Reader threads continually throwing IOException when client closes-->
- <protectio>false</protectio>
- <transport>nio</transport>
- <port>5672</port>
- <sslport>8672</sslport>
- <socketReceiveBuffer>32768</socketReceiveBuffer>
- <socketSendBuffer>32768</socketSendBuffer>
- </connector>
- <management>
- <enabled>false</enabled>
- <jmxport>8999</jmxport>
- <security-enabled>false</security-enabled>
- </management>
- <advanced>
- <filterchain enableExecutorPool="true"/>
- <enablePooledAllocator>false</enablePooledAllocator>
- <enableDirectBuffers>false</enableDirectBuffers>
- <framesize>65535</framesize>
- <compressBufferOnQueue>false</compressBufferOnQueue>
- <enableJMSXUserID>false</enableJMSXUserID>
- </advanced>
-
- <security>
- <principal-databases>
- <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
- <principal-database>
- <name>passwordfile</name>
- <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
- <attributes>
- <attribute>
- <name>passwordFile</name>
- <value>${conf}/passwd</value>
- </attribute>
- </attributes>
- </principal-database>
- </principal-databases>
-
- <access>
- <class>org.apache.qpid.server.security.access.plugins.DenyAll</class>
- </access>
-
- <jmx>
- <access>${conf}/jmxremote.access</access>
- <principal-database>passwordfile</principal-database>
- </jmx>
- </security>
<virtualhosts>
- <directory>${conf}/virtualhosts</directory>
<virtualhost>
<name>test</name>
<test>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
-
<queues>
<exchange>amq.direct</exchange>
<!-- 4Mb -->
@@ -197,34 +133,7 @@
</security>
</test>
</virtualhost>
-
-
- <virtualhost>
- <name>development</name>
- <development>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </development>
- </virtualhost>
-
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </localhost>
- </virtualhost>
-
</virtualhosts>
-
- <heartbeat>
- <delay>0</delay>
- <timeoutFactor>2.0</timeoutFactor>
- </heartbeat>
-
- <virtualhosts>${conf}/virtualhosts.xml</virtualhosts>
</broker>
diff --git a/qpid/java/systests/etc/config-systests-acl.xml b/qpid/java/systests/etc/config-systests-acl.xml
new file mode 100644
index 0000000000..34104dbe6b
--- /dev/null
+++ b/qpid/java/systests/etc/config-systests-acl.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-acl-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/qpid/java/systests/etc/config-systests-derby-settings.xml b/qpid/java/systests/etc/config-systests-derby-settings.xml
new file mode 100644
index 0000000000..9c25b5682e
--- /dev/null
+++ b/qpid/java/systests/etc/config-systests-derby-settings.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <virtualhosts>
+ <directory>${conf}/virtualhosts</directory>
+
+ <virtualhost>
+ <name>localhost</name>
+ <localhost>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/localhost-store</environment-path>
+ </store>
+
+ <housekeeping>
+ <expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
+ </housekeeping>
+
+ </localhost>
+ </virtualhost>
+
+ <virtualhost>
+ <name>development</name>
+ <development>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/development-store</environment-path>
+ </store>
+ </development>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/test-store</environment-path>
+ </store>
+ </test>
+ </virtualhost>
+
+ </virtualhosts>
+</broker>
+
+
diff --git a/qpid/java/systests/etc/config-systests-derby.xml b/qpid/java/systests/etc/config-systests-derby.xml
new file mode 100644
index 0000000000..18ba0c4ad9
--- /dev/null
+++ b/qpid/java/systests/etc/config-systests-derby.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-derby-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/qpid/java/systests/etc/config-systests-settings.xml b/qpid/java/systests/etc/config-systests-settings.xml
new file mode 100644
index 0000000000..4e9c863fda
--- /dev/null
+++ b/qpid/java/systests/etc/config-systests-settings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <management>
+ <enabled>false</enabled>
+ <ssl>
+ <enabled>false</enabled>
+ </ssl>
+ </management>
+</broker>
diff --git a/qpid/java/systests/etc/config-systests.xml b/qpid/java/systests/etc/config-systests.xml
new file mode 100644
index 0000000000..290c082a4f
--- /dev/null
+++ b/qpid/java/systests/etc/config-systests.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/qpid/java/broker/etc/virtualhosts-config-test.xml b/qpid/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml
index 168aa074da..168aa074da 100644
--- a/qpid/java/broker/etc/virtualhosts-config-test.xml
+++ b/qpid/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
index 7a2266902b..2e107ada34 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
@@ -20,24 +20,21 @@
*/
package org.apache.qpid.management.jmx;
-import org.apache.qpid.commands.objects.AllObjects;
-import org.apache.qpid.management.common.JMXConnnectionFactory;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
import org.apache.qpid.management.common.mbeans.ManagedConnection;
import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.server.logging.AbstractTestLogging;
import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.test.utils.JMXTestUtils;
import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
import javax.management.JMException;
-import javax.management.MBeanException;
-import javax.management.MBeanServerConnection;
-import javax.management.MBeanServerInvocationHandler;
-import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
import java.io.IOException;
import java.util.List;
-import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test class to test if any change in the broker JMX code is affesting the management console
@@ -46,33 +43,21 @@ import java.util.Set;
*/
public class ManagementActorLoggingTest extends AbstractTestLogging
{
- MBeanServerConnection _mbsc;
- JMXConnector _jmxc;
+ private JMXTestUtils _jmxUtils;
private static final String USER = "admin";
@Override
public void setUp() throws Exception
{
- setConfigurationProperty("management.enabled", "true");
+ _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils.setUp();
super.setUp();
-
- if (isExternalBroker())
- {
- _jmxc = JMXConnnectionFactory.getJMXConnection(
- 5000, "127.0.0.1",
- getManagementPort(getPort()), USER, USER);
-
- _mbsc = _jmxc.getMBeanServerConnection();
- }
}
@Override
public void tearDown() throws Exception
{
- if (isExternalBroker())
- {
- _jmxc.close();
- }
+ _jmxUtils.close();
super.tearDown();
}
@@ -103,34 +88,31 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testJMXManagementConsoleConnection() throws IOException
{
- if (isExternalBroker())
- {
- List<String> results = _monitor.findMatches("MNG-1007");
+ List<String> results = _monitor.findMatches("MNG-1007");
- assertEquals("Unexpected Management Connection count", 1, results.size());
+ assertEquals("Unexpected Management Connection count", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- validateMessageID("MNG-1007", log);
+ validateMessageID("MNG-1007", log);
- assertTrue("User not in log message:" + log, log.endsWith(USER));
- // Extract the id from the log string
- // MESSAGE [mng:1(rmi://169.24.29.116)] MNG-1007 : Open : User admin
- int connectionID = Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + "");
+ assertTrue("User not in log message:" + log, log.endsWith(USER));
+ // Extract the id from the log string
+ // MESSAGE [mng:1(rmi://169.24.29.116)] MNG-1007 : Open : User admin
+ int connectionID = Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + "");
- results = _monitor.findMatches("MNG-1008");
+ results = _monitor.findMatches("MNG-1008");
- assertEquals("Unexpected Management Connection close count", 0, results.size());
+ assertEquals("Unexpected Management Connection close count", 0, results.size());
- _jmxc.close();
+ _jmxUtils.close();
- results = _monitor.findMatches("MNG-1008");
+ results = _monitor.findMatches("MNG-1008");
- assertEquals("Unexpected Management Connection count", 1, results.size());
+ assertEquals("Unexpected Management Connection count", 1, results.size());
- assertEquals("Close does not have same id as open,", connectionID,
- Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + ""));
- }
+ assertEquals("Close does not have same id as open,", connectionID,
+ Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + ""));
}
/**
@@ -155,38 +137,40 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testConnectionCloseViaManagement() throws IOException, Exception
{
- if (isExternalBroker())
+ //Create a connection to the broker
+ Connection connection = getConnection();
+
+ // Monitor the connection for an exception being thrown
+ // this should be a DisconnectionException but it is not this tests
+ // job to valiate that. Only use the exception as a synchronisation
+ // to check the log file for the Close message
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+ connection.setExceptionListener(new ExceptionListener()
{
+ public void onException(JMSException e)
+ {
+ //Failover being attempted.
+ exceptionReceived.countDown();
+ }
+ });
- //Create a connection to the broker
- Connection connection = getConnection();
-
- // Get all active AMQP connections
- AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.Connection,*";
-
- Set<ObjectName> objectNames = allObject.returnObjects();
-
- assertEquals("More than one test connection returned", 1, objectNames.size());
+ //Remove the connection close from any 0-10 connections
+ _monitor.reset();
- ObjectName connectionName = objectNames.iterator().next();
+ // Get a managedConnection
+ ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*");
- ManagedConnection mangedConnection = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, connectionName,
- ManagedConnection.class, false);
+ //Close the connection
+ mangedConnection.closeConnection();
- //Remove the connection close from any 0-10 connections
- _monitor.reset();
+ //Wait for the connection to close
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
- //Close the connection
- mangedConnection.closeConnection();
+ //Validate results
+ List<String> results = _monitor.findMatches("CON-1002");
- //Validate results
- List<String> results = _monitor.findMatches("CON-1002");
-
-
- assertEquals("Unexpected Connection Close count", 1, results.size());
- }
+ assertEquals("Unexpected Connection Close count", 1, results.size());
}
/**
@@ -212,114 +196,100 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous exchange declares
- _monitor.reset();
-
- createExchange("direct");
+ _monitor.reset();
- // Validate
+ _jmxUtils.createExchange("test", "direct", null, false);
- //1 - ID is correct
- List<String> results = _monitor.findMatches("EXH-1001");
+ // Validate
- assertEquals("More than one exchange creation found", 1, results.size());
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
- String log = getLog(results.get(0));
+ assertEquals("More than one exchange creation found", 1, results.size());
- // Validate correct exchange name
- assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+ String log = getLog(results.get(0));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
- }
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous exchange declares
- _monitor.reset();
+ //Remove any previous exchange declares
+ _monitor.reset();
- createExchange("topic");
+ _jmxUtils.createExchange("test", "topic", null, false);
- // Validate
+ // Validate
- //1 - ID is correct
- List<String> results = _monitor.findMatches("EXH-1001");
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
- assertEquals("More than one exchange creation found", 1, results.size());
+ assertEquals("More than one exchange creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct exchange name
- assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
}
public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous exchange declares
- _monitor.reset();
+ //Remove any previous exchange declares
+ _monitor.reset();
- createExchange("fanout");
+ _jmxUtils.createExchange("test", "fanout", null, false);
- // Validate
+ // Validate
- //1 - ID is correct
- List<String> results = _monitor.findMatches("EXH-1001");
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
- assertEquals("More than one exchange creation found", 1, results.size());
+ assertEquals("More than one exchange creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct exchange name
- assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
}
public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous exchange declares
- _monitor.reset();
+ //Remove any previous exchange declares
+ _monitor.reset();
- createExchange("headers");
+ _jmxUtils.createExchange("test", "headers", null, false);
- // Validate
+ // Validate
- //1 - ID is correct
- List<String> results = _monitor.findMatches("EXH-1001");
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
- assertEquals("More than one exchange creation found", 1, results.size());
+ assertEquals("More than one exchange creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct exchange name
- assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
}
/**
@@ -343,29 +313,26 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createQueue();
+ _jmxUtils.createQueue("test", getName(), null, false);
- // Validate
+ // Validate
- List<String> results = _monitor.findMatches("QUE-1001");
+ List<String> results = _monitor.findMatches("QUE-1001");
- assertEquals("More than one queue creation found", 1, results.size());
+ assertEquals("More than one queue creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct queue name
- String subject = fromSubject(log);
- assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ // Validate correct queue name
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
/**
@@ -389,34 +356,29 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testQueueDeleteViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createQueue();
+ _jmxUtils.createQueue("test", getName(), null, false);
- ManagedBroker managedBroker = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getVirtualHostManagerObjectName(),
- ManagedBroker.class, false);
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
- managedBroker.deleteQueue(getName());
+ managedBroker.deleteQueue(getName());
- List<String> results = _monitor.findMatches("QUE-1002");
+ List<String> results = _monitor.findMatches("QUE-1002");
- assertEquals("More than one queue deletion found", 1, results.size());
+ assertEquals("More than one queue deletion found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct binding
- String subject = fromSubject(log);
- assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
}
/**
@@ -440,98 +402,83 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createQueue();
+ _jmxUtils.createQueue("test", getName(), null, false);
- ManagedExchange managedExchange = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getExchange("amq.direct"),
- ManagedExchange.class, false);
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct");
- managedExchange.createNewBinding(getName(), getName());
+ managedExchange.createNewBinding(getName(), getName());
- List<String> results = _monitor.findMatches("BND-1001");
+ List<String> results = _monitor.findMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("More than one bind creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct binding
- String subject = fromSubject(log);
- assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
- assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createQueue();
+ _jmxUtils.createQueue("test", getName(), null, false);
- ManagedExchange managedExchange = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getExchange("amq.topic"),
- ManagedExchange.class, false);
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic");
- managedExchange.createNewBinding(getName(), getName());
+ managedExchange.createNewBinding(getName(), getName());
- List<String> results = _monitor.findMatches("BND-1001");
+ List<String> results = _monitor.findMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("More than one bind creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct binding
- String subject = fromSubject(log);
- assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
- assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createQueue();
+ _jmxUtils.createQueue("test", getName(), null, false);
- ManagedExchange managedExchange = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getExchange("amq.fanout"),
- ManagedExchange.class, false);
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout");
- managedExchange.createNewBinding(getName(), getName());
+ managedExchange.createNewBinding(getName(), getName());
- List<String> results = _monitor.findMatches("BND-1001");
+ List<String> results = _monitor.findMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("More than one bind creation found", 1, results.size());
- String log = getLog(results.get(0));
+ String log = getLog(results.get(0));
- // Validate correct binding
- String subject = fromSubject(log);
- assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
- assertEquals("Incorrect routing key in create", "*", AbstractTestLogSubject.getSlice("rk", subject));
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", "*", AbstractTestLogSubject.getSlice("rk", subject));
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
/**
@@ -556,114 +503,28 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
*/
public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException
{
- if (isExternalBroker())
- {
-
- //Remove any previous queue declares
- _monitor.reset();
+ //Remove any previous queue declares
+ _monitor.reset();
- createExchange("direct");
+ _jmxUtils.createExchange("test", "direct", null, false);
- ManagedBroker managedBroker = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getVirtualHostManagerObjectName(),
- ManagedBroker.class, false);
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
- managedBroker.unregisterExchange(getName());
+ managedBroker.unregisterExchange(getName());
- List<String> results = _monitor.findMatches("EXH-1002");
+ List<String> results = _monitor.findMatches("EXH-1002");
- assertEquals("More than one exchange deletion found", 1, results.size());
-
- String log = getLog(results.get(0));
-
- // Validate correct binding
- String subject = fromSubject(log);
- assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject));
-
- // Validate it was a management actor.
- String actor = fromActor(log);
- assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
- }
- }
-
- /**
- * Create a non-durable test exchange with the current test name
- *
- * @throws JMException - is thrown if a exchange with this testName already exists
- * @throws IOException - if there is a problem with the JMX Connection
- * @throws javax.management.MBeanException
- * - if there is another problem creating the exchange
- */
- private void createExchange(String type)
- throws JMException, IOException, MBeanException
- {
- ManagedBroker managedBroker = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getVirtualHostManagerObjectName(),
- ManagedBroker.class, false);
-
- managedBroker.createNewExchange(getName(), type, false);
- }
-
- /**
- * Create a non-durable queue (with no owner) that is named after the
- * creating test.
- *
- * @throws JMException - is thrown if a queue with this testName already exists
- * @throws IOException - if there is a problem with the JMX Connection
- */
- private void createQueue()
- throws JMException, IOException
- {
- ManagedBroker managedBroker = MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getVirtualHostManagerObjectName(),
- ManagedBroker.class, false);
-
- managedBroker.createNewQueue(getName(), null, false);
- }
-
- /**
- * Retrive the ObjectName for the test Virtualhost.
- *
- * This is then use to create aproxy to the ManagedBroker MBean.
- *
- * @return the ObjectName for the 'test' VirtualHost.
- */
- private ObjectName getVirtualHostManagerObjectName()
- {
- // Get the name of the test manager
- AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=test,*";
-
- Set<ObjectName> objectNames = allObject.returnObjects();
-
- assertEquals("Incorrect number test vhosts returned", 1, objectNames.size());
-
- // We have verified we have only one value in objectNames so return it
- return objectNames.iterator().next();
- }
-
- /**
- * Retrive the ObjectName for the given Exchange on the test Virtualhost.
- *
- * This is then use to create aproxy to the ManagedExchange MBean.
- *
- * @param exchange The exchange to retireve e.g. 'direct'
- *
- * @return the ObjectName for the given exchange on the test VirtualHost.
- */
- private ObjectName getExchange(String exchange)
- {
- // Get the name of the test manager
- AllObjects allObject = new AllObjects(_mbsc);
- allObject.querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=test,name=" + exchange + ",*";
+ assertEquals("More than one exchange deletion found", 1, results.size());
- Set<ObjectName> objectNames = allObject.returnObjects();
+ String log = getLog(results.get(0));
- assertEquals("Incorrect number of exchange with name '" + exchange +
- "' returned", 1, objectNames.size());
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject));
- // We have verified we have only one value in objectNames so return it
- return objectNames.iterator().next();
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java
index c4803e121e..0a88ef391c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java
@@ -40,6 +40,8 @@ public class ServerConfigurationFileTest extends QpidTestCase
{
fail("Unable to test without config file:" + _configFile);
}
+
+ saveTestConfiguration();
_serverConfig = new ServerConfiguration(_configFile);
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
index 620b2a5161..683abee4da 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
@@ -94,7 +94,7 @@ public class AlertingTest extends AbstractTestLogging
{
_connection = getConnection();
_session = _connection.createSession(true, Session.SESSION_TRANSACTED);
- _destination = _session.createQueue("testQueue");
+ _destination = _session.createQueue(getTestQueueName());
// Consumer is only used to actually create the destination
_session.createConsumer(_destination).close();
@@ -116,14 +116,12 @@ public class AlertingTest extends AbstractTestLogging
// Add the current contents of the log file to test output
message.append(_monitor.readFile());
- // Write the server config file to test output
- message.append("Server configuration file in use:\n");
- message.append(FileUtils.readFileAsString(_configFile));
+ // Write the test config file to test output
+ message.append("Server configuration overrides in use:\n");
+ message.append(FileUtils.readFileAsString(getTestConfigFile()));
- // Write the virtualhost config file to test output
- message.append("\nVirtualhost configuration file in use:\n");
- message.append(FileUtils.readFileAsString(ServerConfiguration.
- flatConfig(_configFile).getString("virtualhosts")));
+ message.append("\nVirtualhost maxMessageCount:\n");
+ message.append((new ServerConfiguration(_configFile)).getConfig().getString("virtualhosts.virtualhost." + VIRTUALHOST + ".queues.maximumMessageCount"));
fail(message.toString());
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java
index 254ec9693d..cc3993249c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java
@@ -28,6 +28,7 @@ import javax.jms.Connection;
import javax.jms.Queue;
import javax.jms.Session;
import java.util.List;
+import java.io.File;
/**
* The MessageStore test suite validates that the follow log messages as
@@ -56,9 +57,9 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
//We call super.setUp but this will not start the broker as that is
//part of the test case.
- // Load current configuration file to get the list of defined vhosts
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ // Load the default configuration file to get the list of defined vhosts
+ ServerConfiguration configuration = new ServerConfiguration(new File(_configFile.getParent() + "/config.xml"));
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
// Make them all persistent i.e. Use DerbyMessageStore and
// test that it logs correctly.
@@ -97,8 +98,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1002");
@@ -117,7 +118,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -160,8 +161,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1004");
@@ -186,7 +187,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -227,8 +228,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1006");
@@ -253,7 +254,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -293,8 +294,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1004 : Recovery Start :");
@@ -316,7 +317,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -358,8 +359,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1006 : Recovery Complete :");
@@ -381,7 +382,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -500,8 +501,8 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1004 : Recovery Start : " + queueName);
@@ -542,7 +543,7 @@ public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
index 11c003a2a7..8b7c881a32 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
@@ -24,6 +24,7 @@ import junit.framework.AssertionFailedError;
import org.apache.qpid.util.LogMonitor;
import java.util.List;
+import java.io.File;
/**
* Management Console Test Suite
@@ -308,9 +309,8 @@ public class ManagementLoggingTest extends AbstractTestLogging
// We expect the RMIConnector Server port to be 100 higher than
// the RMI Server Port
- int mPort = getPort() + (DEFAULT_MANAGEMENT_PORT - DEFAULT_PORT) + 100;
- assertTrue("SSL Keystore entry expected(" + mPort + ").:" + getMessageString(log),
- getMessageString(log).endsWith(getConfigurationStringProperty("management.ssl.keyStorePath")));
+ assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
+ getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName()));
}
catch (AssertionFailedError afe)
{
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
index a1cbeca6de..2298ba4da0 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
@@ -89,8 +89,8 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
assertEquals("MST-1001 is not the first MST message", "MST-1001", getMessageID(fromMessage(log)));
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1001");
@@ -109,7 +109,7 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
@@ -156,8 +156,8 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
assertTrue("MST messages not logged", results.size() > 0);
// Load VirtualHost list from file.
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("MST-1003");
@@ -176,7 +176,7 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
// the virtualhost name, found above. AND
// the index that the virtualhost is within the configuration.
// we can retrive that from the vhosts list previously extracted.
- String fullStoreName = configuration.getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
index 033c0533f8..5dd56fb0f9 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
@@ -29,6 +29,7 @@ import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.Topic;
+import javax.jms.Message;
import java.io.IOException;
import java.util.List;
@@ -327,51 +328,59 @@ public class SubscriptionLoggingTest extends AbstractTestLogging
int PREFETCH = 15;
//Create new session with small prefetch
- _session = ((AMQConnection) _connection).createSession(true, Session.AUTO_ACKNOWLEDGE, PREFETCH);
+ _session = ((AMQConnection) _connection).createSession(true, Session.SESSION_TRANSACTED, PREFETCH);
MessageConsumer consumer = _session.createConsumer(_queue);
_connection.start();
+ //Start the dispatcher & Unflow the channel.
+ consumer.receiveNoWait();
+
//Fill the prefetch and two extra so that our receive bellow allows the
- // subscription to become active then return to a suspended state.
- sendMessage(_session, _queue, 17);
+ // subscription to become active
+ // Previously we set this to 17 so that it would return to a suspended
+ // state. However, testing has shown that the state change can occur
+ // sufficiently quickly that logging does not occur consistently enough
+ // for testing.
+ int SEND_COUNT = 16;
+ sendMessage(_session, _queue, SEND_COUNT);
_session.commit();
// Retreive the first message, and start the flow of messages
- assertNotNull("First message not retreived", consumer.receive(1000));
+ Message msg = consumer.receive(1000);
+ assertNotNull("First message not retreived", msg);
_session.commit();
-
- //Validate
- List<String> results = _monitor.findMatches("SUB-1003");
-
- int i = 0;
- while (results.size() != 3 && i < 10)
+ // Drain the queue to ensure there is time for the ACTIVE log message
+ // Check that we can received all the messages
+ int receivedCount = 0;
+ while (msg != null)
{
- try
- {
- Thread.sleep(1500);
- }
- catch (InterruptedException e)
- {
-
- }
- results = _monitor.findMatches("SUB-1003");
- i++;
+ receivedCount++;
+ msg = consumer.receive(1000);
+ _session.commit();
}
+ //Validate we received all the messages
+ assertEquals("Not all sent messages received.", SEND_COUNT, receivedCount);
+
+ // Fill the queue again to suspend the consumer
+ sendMessage(_session, _queue, SEND_COUNT);
+ _session.commit();
+
+ //Validate
+ List<String> results = _monitor.findMatches("SUB-1003");
+
try
{
// Validation expects three messages.
- // The first will be logged by the QueueActor as part of the processQueue thread
-// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State : SUSPENDED
- // The second will be by the connnection as it acknowledges and activates the subscription
-// INFO - MESSAGE [con:6(guest@anonymous(26562441)/test)/ch:3] [sub:6(qu(example.queue))] SUB-1003 : State : ACTIVE
- // The final one can be the subscription suspending as part of the SubFlushRunner or the processQueue thread
- // As a result validating the actor is more complicated and doesn't add anything. The goal of this test is
- // to ensure the State is correct not that a particular Actor performs the logging.
-// INFO - MESSAGE [sub:6(vh(test)/qu(example.queue))] [sub:6(qu(example.queue))] SUB-1003 : State : SUSPENDED
-// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State : SUSPENDED
+ // The Actor can be any one of the following depending on the exactly what is going on on the broker.
+ // Ideally we would test that we can get all of them but setting up
+ // the timing to do this in a consistent way is not benefitial.
+ // Ensuring the State is as expected is sufficient.
+// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State :
+// INFO - MESSAGE [con:6(guest@anonymous(26562441)/test)/ch:3] [sub:6(qu(example.queue))] SUB-1003 : State :
+// INFO - MESSAGE [sub:6(vh(test)/qu(example.queue))] [sub:6(qu(example.queue))] SUB-1003 : State :
assertEquals("Result set not expected size:", 3, results.size());
@@ -380,19 +389,10 @@ public class SubscriptionLoggingTest extends AbstractTestLogging
String log = getLog(results.get(0));
validateSubscriptionState(log, expectedState);
- // Validate that the logActor is the the queue
- String actor = fromActor(log);
- assertTrue("Actor string does not contain expected queue("
- + _queue.getQueueName() + ") name." + actor,
- actor.contains("qu(" + _queue.getQueueName() + ")"));
-
// After being suspended the subscription should become active.
expectedState = "ACTIVE";
log = getLog(results.get(1));
validateSubscriptionState(log, expectedState);
- // Validate we have a connection Actor
- actor = fromActor(log);
- assertTrue("The actor is not a connection actor:" + actor, actor.startsWith("con:"));
// Validate that it was re-suspended
expectedState = "SUSPENDED";
@@ -411,6 +411,9 @@ public class SubscriptionLoggingTest extends AbstractTestLogging
}
_connection.close();
+ //Ensure the queue is drained before the test ends
+ drainQueue(_queue);
+
}
/**
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
index 7bf644508e..f4a0c8b27d 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
@@ -64,8 +64,8 @@ public class VirtualHostLoggingTest extends AbstractTestLogging
try
{
// Validation
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("VHT-1001");
@@ -117,8 +117,8 @@ public class VirtualHostLoggingTest extends AbstractTestLogging
{
// Validation
- Configuration configuration = ServerConfiguration.flatConfig(_configFile);
- List<String> vhosts = configuration.getList("virtualhosts.virtualhost.name");
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
//Validate each vhost logs a creation
results = _monitor.findMatches("VHT-1002");
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
new file mode 100644
index 0000000000..078b8f43ce
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
@@ -0,0 +1,299 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.management.JMException;
+import javax.management.MBeanException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
+
+/**
+ * This Test validates the Queue Model on the broker.
+ * Currently it has some basic queue creation / deletion tests.
+ * However, it should be expanded to include other tests that relate to the
+ * model. i.e.
+ *
+ * The Create and Delete tests should ensure that the requisite logging is
+ * performed.
+ *
+ * Additions to this suite would be to complete testing of creations, validating
+ * fields such as owner/exclusive, autodelete and priority are correctly set.
+ *
+ * Currently this test uses the JMX interface to validate that the queue has
+ * been declared as expected so these tests cannot run against a CPP broker.
+ *
+ *
+ * Tests should ensure that they clean up after themselves.
+ * e,g. Durable queue creation test should perform a queue delete.
+ */
+public class ModelTest extends QpidTestCase
+{
+
+ private static final String USER = "admin";
+ private JMXTestUtils _jmxUtils;
+ private static final String VIRTUALHOST_NAME = "test";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ // Create a JMX Helper
+ _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils.setUp();
+ super.setUp();
+
+ // Open the JMX Connection
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ // Close the JMX Connection
+ _jmxUtils.close();
+ super.tearDown();
+ }
+
+ /**
+ * Test that a transient queue can be created via AMQP.
+ *
+ * @throws Exception On unexpected error
+ */
+ public void testQueueCreationTransientViaAMQP() throws Exception
+ {
+ Connection connection = getConnection();
+
+ String queueName = getTestQueueName();
+ boolean durable = false;
+ boolean autoDelete = false;
+ boolean exclusive = false;
+
+ createViaAMQPandValidateViaJMX(connection, queueName, durable,
+ autoDelete, exclusive);
+ }
+
+ /**
+ * Test that a durable queue can be created via AMQP.
+ *
+ * @throws Exception On unexpected error
+ */
+
+ public void testQueueCreationDurableViaAMQP() throws Exception
+ {
+ Connection connection = getConnection();
+
+ String queueName = getTestQueueName();
+ boolean durable = true;
+ boolean autoDelete = false;
+ boolean exclusive = false;
+
+ createViaAMQPandValidateViaJMX(connection, queueName, durable,
+ autoDelete, exclusive);
+
+ // Clean up
+ ManagedBroker managedBroker =
+ _jmxUtils.getManagedBroker(VIRTUALHOST_NAME);
+ managedBroker.deleteQueue(queueName);
+ }
+
+ /**
+ * Test that a transient queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testCreationTransientViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+ String owner = null;
+ boolean durable = false;
+
+ createViaJMXandValidateViaJMX(name, owner, durable, durable);
+ }
+
+ /**
+ * Test that a durable queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testCreationDurableViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+ String owner = null;
+ boolean durable = true;
+
+ createViaJMXandValidateViaJMX(name, owner, durable, durable);
+
+ // Clean up
+ ManagedBroker managedBroker =
+ _jmxUtils.getManagedBroker(VIRTUALHOST_NAME);
+ managedBroker.deleteQueue(name);
+ }
+
+ /**
+ * Test that a transient queue can be deleted via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testDeletionTransientViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.
+ getManagedBroker(VIRTUALHOST_NAME);
+
+ try
+ {
+ managedBroker.deleteQueue(name);
+ }
+ catch (UndeclaredThrowableException e)
+ {
+ fail(((MBeanException) ((InvocationTargetException)
+ e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage());
+ }
+ }
+
+ /**
+ * Test that a durable queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testDeletionDurableViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, true);
+
+ ManagedBroker managedBroker = _jmxUtils.
+ getManagedBroker(VIRTUALHOST_NAME);
+
+ try
+ {
+ managedBroker.deleteQueue(name);
+ }
+ catch (UndeclaredThrowableException e)
+ {
+ fail(((MBeanException) ((InvocationTargetException)
+ e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage());
+ }
+ }
+
+ /*
+ * Helper Methods
+ */
+
+ /**
+ * Using the provided JMS Connection create a queue using the AMQP extension
+ * with the given properties and then validate it was created correctly via
+ * the JMX Connection
+ *
+ * @param connection Qpid JMS Connection
+ * @param queueName String the desired QueueName
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ * @param exclusive boolean if the queue is exclusive
+ *
+ * @throws AMQException if there is a problem with the createQueue call
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ * @throws JMSException if there is a problem creating the JMS Session
+ */
+ private void createViaAMQPandValidateViaJMX(Connection connection,
+ String queueName,
+ boolean durable,
+ boolean autoDelete,
+ boolean exclusive)
+ throws AMQException, JMException, IOException, JMSException
+ {
+ AMQSession session = (AMQSession) connection.createSession(false,
+ Session.AUTO_ACKNOWLEDGE);
+
+ session.createQueue(new AMQShortString(queueName),
+ autoDelete, durable, exclusive);
+
+ validateQueueViaJMX(queueName, exclusive ? ((AMQConnection) connection).
+ getUsername() : null, durable, autoDelete);
+ }
+
+ /**
+ * Use the JMX Helper to create a queue with the given properties and then
+ * validate it was created correctly via the JMX Connection
+ *
+ * @param queueName String the desired QueueName
+ * @param owner String the owner value that should be set
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ *
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ */
+ private void createViaJMXandValidateViaJMX(String queueName, String owner,
+ boolean durable, boolean autoDelete)
+ throws JMException, IOException
+ {
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, queueName, owner, durable);
+
+ validateQueueViaJMX(queueName, owner, durable, autoDelete);
+ }
+
+ /**
+ * Validate that a queue with the given properties exists on the broker
+ *
+ * @param queueName String the desired QueueName
+ * @param owner String the owner value that should be set
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ *
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ */
+ private void validateQueueViaJMX(String queueName, String owner, boolean durable, boolean autoDelete)
+ throws JMException, IOException
+ {
+ ManagedQueue managedQueue = _jmxUtils.
+ getManagedObject(ManagedQueue.class,
+ _jmxUtils.getQueueObjectName(VIRTUALHOST_NAME,
+ queueName));
+
+ assertEquals(queueName, managedQueue.getName());
+ assertEquals(String.valueOf(owner), managedQueue.getOwner());
+ assertEquals(durable, managedQueue.isDurable());
+ assertEquals(autoDelete, managedQueue.isAutoDelete());
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
index b5c0a87b0f..a755bbfaa7 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
@@ -21,67 +21,57 @@
package org.apache.qpid.server.security.acl;
-import junit.framework.TestCase;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.client.*;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import org.apache.qpid.AMQException;
-import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.url.URLSyntaxException;
-import javax.jms.*;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
import java.io.File;
public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
- private String BROKER = "vm://:"+ApplicationRegistry.DEFAULT_INSTANCE;//"tcp://localhost:5672";
-
public void setUp() throws Exception
{
- //Shutdown the QTC broker
- stopBroker();
-
- // Initialise ACLs.
- final String QpidExampleHome = System.getProperty("QPID_EXAMPLE_HOME");
- final File defaultaclConfigFile = new File(QpidExampleHome, "etc/acl.config.xml");
+ final String QPID_HOME = System.getProperty("QPID_HOME");
- if (!defaultaclConfigFile.exists())
- {
- System.err.println("Configuration file not found:" + defaultaclConfigFile);
- fail("Configuration file not found:" + defaultaclConfigFile);
- }
-
- if (System.getProperty("QPID_HOME") == null)
+ if (QPID_HOME == null)
{
fail("QPID_HOME not set");
}
- ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(defaultaclConfigFile);
- ApplicationRegistry.initialise(config, ApplicationRegistry.DEFAULT_INSTANCE);
- TransportConnection.createVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
- }
+ // Initialise ACLs.
+ _configFile = new File(QPID_HOME, "etc/config-systests-acl.xml");
- public void tearDown()
- {
- TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
- ApplicationRegistry.remove(ApplicationRegistry.DEFAULT_INSTANCE);
+ super.setUp();
}
- public String createConnectionString(String username, String password, String broker)
+ public String createConnectionString(String username, String password)
{
- return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + broker + "?retries='0''";
+ return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + getBroker() + "?retries='0''";
}
public void testAccessAuthorized() throws AMQException, URLSyntaxException
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
@@ -94,28 +84,32 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
catch (Exception e)
{
- fail("Connection was not created due to:" + e.getMessage());
+ fail("Connection was not created due to:" + e);
}
}
- public void testAccessNoRights() throws URLSyntaxException, JMSException
+ public void testAccessNoRights() throws Exception
{
try
{
- Connection conn = createConnection("guest", "guest");
+ Connection conn = getConnection("guest", "guest");
//Attempt to do do things to test connection.
Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
conn.start();
sesh.rollback();
- conn.close();
fail("Connection was created.");
}
- catch (AMQException amqe)
+ catch (JMSException jmse)
{
- Throwable cause = amqe.getCause();
- assertEquals("Exception was wrong type", AMQAuthenticationException.class, cause.getClass());
+ Throwable linkedException = jmse.getLinkedException();
+ assertNotNull("Cause was null", linkedException);
+
+ assertEquals("Linked Exception was wrong type", AMQConnectionFailureException.class, linkedException.getClass());
+
+ Throwable cause = linkedException.getCause();
+ assertEquals("Cause was wrong type", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
}
}
@@ -124,7 +118,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -140,11 +134,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testClientConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
+ public void testClientConsumeFromNamedQueueInvalid() throws NamingException
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
//Prevent Failover
((AMQConnection) conn).setConnectionListener(this);
@@ -171,7 +165,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -189,11 +183,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testClientCreateNamedQueue() throws JMSException, URLSyntaxException, AMQException
+ public void testClientCreateNamedQueue() throws NamingException, JMSException, AMQException
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -207,6 +201,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
catch (AMQAuthenticationException amqe)
{
+ amqe.printStackTrace();
assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) amqe).getErrorCode().getCode());
}
}
@@ -215,7 +210,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -242,7 +237,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -268,11 +263,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException
{
try
{
- Connection conn = createConnection("client", "guest");
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -317,7 +312,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
try
{
- Connection conn = createConnection("server", "guest");
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -333,11 +328,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException
{
try
- {
- Connection conn = createConnection("client", "guest");
+ {
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -358,11 +353,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException
{
try
{
- Connection conn = createConnection("server","guest");
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -382,30 +377,22 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- private Connection createConnection(String username, String password) throws AMQException
+ @Override
+ public Connection getConnection(String username, String password) throws NamingException, JMSException
{
- AMQConnection connection = null;
- try
- {
- connection = new AMQConnection(createConnectionString(username, password, BROKER));
- }
- catch (URLSyntaxException e)
- {
- // This should never happen as we generate the URLs.
- fail(e.getMessage());
- }
+ AMQConnection connection = (AMQConnection) super.getConnection(username, password);
//Prevent Failover
connection.setConnectionListener(this);
- return (Connection)connection;
+ return (Connection) connection;
}
public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException
{
try
{
- Connection conn = createConnection("server", "guest");
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -422,11 +409,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException
+ public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException
{
try
{
- Connection conn = createConnection("server", "guest");
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -444,18 +431,18 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerCreateTemporaryQueueInvalid() throws JMSException, URLSyntaxException, AMQException
+ public void testServerCreateTemporaryQueueInvalid() throws NamingException
{
try
{
- Connection conn = createConnection("server", "guest");
+ Connection conn = getConnection("server", "guest");
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
session.createTemporaryQueue();
-
+
fail("Test failed as creation succeded.");
//conn will be automatically closed
}
@@ -469,19 +456,19 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerCreateAutoDeleteQueueInvalid() throws JMSException, URLSyntaxException, AMQException
+ public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException
{
Connection connection = null;
try
{
- connection = createConnection("server", "guest");
+ connection = getConnection("server", "guest");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
((AMQSession) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
- true, false, false);
+ true, false, false);
fail("Test failed as creation succeded.");
//connection will be automatically closed
@@ -489,7 +476,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
catch (AMQAuthenticationException amqe)
{
assertEquals("Incorrect error code thrown", 403, amqe.getErrorCode().getCode());
- }
+ }
}
/**
@@ -500,10 +487,10 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
* @throws URLSyntaxException
* @throws JMSException
*/
- public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException
{
//Set up the Server
- Connection serverConnection = createConnection("server", "guest");
+ Connection serverConnection = getConnection("server", "guest");
((AMQConnection) serverConnection).setConnectionListener(this);
@@ -516,7 +503,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
serverConnection.start();
//Set up the consumer
- Connection clientConnection = createConnection("client", "guest");
+ Connection clientConnection = getConnection("client", "guest");
//Send a test mesage
Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -557,8 +544,6 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
//Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
serverSession.commit();
-
-
//Ensure Response is received.
Message clientResponseMsg = clientResponse.receive(2000);
assertNotNull("Client did not receive response message,", clientResponseMsg);
@@ -582,11 +567,11 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
- public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException
{
try
{
- Connection conn = createConnection("server", "guest");
+ Connection conn = getConnection("server", "guest");
((AMQConnection) conn).setConnectionListener(this);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
index 5a5e23baa5..d76d3858b3 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
@@ -1,31 +1,300 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.test.client.message;
+import java.util.concurrent.CountDownLatch;
+
import javax.jms.Connection;
+import javax.jms.DeliveryMode;
import javax.jms.Destination;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import junit.framework.Assert;
-import org.apache.log4j.Logger;
+import org.apache.log4j.BasicConfigurator;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.BasicMessageProducer;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-public class SelectorTest extends QpidTestCase
+public class SelectorTest extends QpidTestCase implements MessageListener
{
- private static final Logger _logger = Logger.getLogger(SelectorTest.class);
+ private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
+
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private int count;
+ public String _connectionString = "vm://:1";
+ private static final String INVALID_SELECTOR = "Cost LIKE 5";
+ CountDownLatch _responseLatch = new CountDownLatch(1);
+
+ private static final String BAD_MATHS_SELECTOR = " 1 % 5";
+
+ private static final long RECIEVE_TIMEOUT = 1000;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ BasicConfigurator.configure();
+ init((AMQConnection) getConnection("guest", "guest"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ if (_session != null)
+ {
+ try
+ {
+ _session.close();
+ }
+ catch (JMSException e)
+ {
+ fail("Error cleaning up:" + e.getMessage());
+ }
+ }
+ if (_connection != null)
+ {
+ try
+ {
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ fail("Error cleaning up:" + e.getMessage());
+ }
+ }
+ }
+
+ private void init(AMQConnection connection) throws JMSException
+ {
+ init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws JMSException
+ {
+ _connection = connection;
+ _destination = destination;
+ connection.start();
+
+ String selector = null;
+ selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
+ // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
+
+ _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ // _session.createConsumer(destination).setMessageListener(this);
+ _session.createConsumer(destination, selector).setMessageListener(this);
+ }
+
+ public void test() throws Exception
+ {
+ try
+ {
+ init((AMQConnection) getConnection("guest", "guest", randomize("Client")));
+
+ Message msg = _session.createTextMessage("Message");
+ msg.setJMSPriority(1);
+ msg.setIntProperty("Cost", 2);
+ msg.setStringProperty("property-with-hyphen", "wibble");
+ msg.setJMSType("Special");
+
+ _logger.info("Sending Message:" + msg);
+
+ ((BasicMessageProducer) _session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
+ _logger.info("Message sent, waiting for response...");
+
+ _responseLatch.await();
+
+ if (count > 0)
+ {
+ _logger.info("Got message");
+ }
+
+ if (count == 0)
+ {
+ fail("Did not get message!");
+ // throw new RuntimeException("Did not get message!");
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ else
+ {
+ System.out.println("SUCCESS!!");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ }
+ catch (URLSyntaxException e)
+ {
+ _logger.debug("URL:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ fail("Wrong exception");
+ }
+ catch (AMQException e)
+ {
+ _logger.debug("AMQ:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ fail("Wrong exception");
+ }
+
+ finally
+ {
+ if (_session != null)
+ {
+ _session.close();
+ }
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ }
+
+ public void testUnparsableSelectors() throws Exception
+ {
+ Connection connection = getConnection("guest", "guest", randomize("Client"));
+ _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ boolean caught = false;
+ //Try Creating a Browser
+ try
+ {
+ _session.createBrowser(_session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Consumer
+ try
+ {
+ _session.createConsumer(_session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Receiever
+ try
+ {
+ _session.createReceiver(_session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ try
+ {
+ _session.createReceiver(_session.createQueue("Ping"), BAD_MATHS_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ }
+
+ public void testRuntimeSelectorError() throws JMSException
+ {
+ MessageConsumer consumer = _session.createConsumer(_destination , "testproperty % 5 = 1");
+ MessageProducer producer = _session.createProducer(_destination);
+ Message sentMsg = _session.createTextMessage();
+
+ sentMsg.setIntProperty("testproperty", 1); // 1 % 5
+ producer.send(sentMsg);
+ Message recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNotNull(recvd);
+
+ sentMsg.setStringProperty("testproperty", "hello"); // "hello" % 5 makes no sense
+ producer.send(sentMsg);
+ try
+ {
+ recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNull(recvd);
+ }
+ catch (Exception e)
+ {
+
+ }
+ assertTrue("Connection should be closed", _connection.isClosed());
+ }
+
public void testSelectorWithJMSMessageID() throws Exception
{
Connection conn = getConnection();
conn.start();
Session session = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
-
- Destination dest = session.createQueue("SelectorQueue");
- MessageProducer prod = session.createProducer(dest);
- MessageConsumer consumer = session.createConsumer(dest,"JMSMessageID IS NOT NULL");
+ MessageProducer prod = session.createProducer(_destination);
+ MessageConsumer consumer = session.createConsumer(_destination,"JMSMessageID IS NOT NULL");
for (int i=0; i<2; i++)
{
@@ -54,7 +323,7 @@ public class SelectorTest extends QpidTestCase
Message msg3 = consumer.receive(1000);
Assert.assertNull("Msg3 should be null", msg3);
session.commit();
- consumer = session.createConsumer(dest,"JMSMessageID IS NULL");
+ consumer = session.createConsumer(_destination,"JMSMessageID IS NULL");
Message msg4 = consumer.receive(1000);
Message msg5 = consumer.receive(1000);
@@ -62,4 +331,49 @@ public class SelectorTest extends QpidTestCase
Assert.assertNotNull("Msg4 should not be null", msg4);
Assert.assertNotNull("Msg5 should not be null", msg5);
}
+
+ public void onMessage(Message message)
+ {
+ count++;
+ _logger.info("Got Message:" + message);
+ _responseLatch.countDown();
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ SelectorTest test = new SelectorTest();
+ test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
+
+ try
+ {
+ while (true)
+ {
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.setUp();
+ }
+ test.test();
+
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.tearDown();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(SelectorTest.class);
+ }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java
index b13170efc9..a123fb290c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java
@@ -57,26 +57,13 @@ public class SyncWaitDelayTest extends QpidTestCase
public void setUp() throws Exception
{
- super.setUp();
- stopBroker();
- if (!_configFile.exists())
- {
- fail("Unable to test without config file:" + _configFile);
- }
- XMLConfiguration configuration = new XMLConfiguration(_configFile);
- configuration.setProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.class", "org.apache.qpid.server.store.SlowMessageStore");
- configuration.setProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.delays.commitTran.post", POST_COMMIT_DELAY);
- configuration.setProperty("management.enabled", "false");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.class", "org.apache.qpid.server.store.SlowMessageStore");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.delays.commitTran.post", String.valueOf(POST_COMMIT_DELAY));
+ setConfigurationProperty("management.enabled", "false");
- File tmpFile = File.createTempFile("configFile", "test");
- tmpFile.deleteOnExit();
- configuration.save(tmpFile);
-
- _configFile = tmpFile;
-
- startBroker(1);
+ super.setUp();
//Set the syncWrite timeout to be just larger than the delay on the commitTran.
setSystemProperty("amqj.default_syncwrite_timeout", String.valueOf(SYNC_WRITE_TIMEOUT));
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
deleted file mode 100644
index c42e4c7582..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.basic;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.BasicMessageProducer;
-import org.apache.qpid.client.state.StateWaiter;
-import org.apache.qpid.url.URLSyntaxException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jms.Connection;
-import javax.jms.DeliveryMode;
-import javax.jms.InvalidSelectorException;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import java.util.concurrent.CountDownLatch;
-
-public class SelectorTest extends QpidTestCase implements MessageListener
-{
- private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
-
- private AMQConnection _connection;
- private AMQDestination _destination;
- private AMQSession _session;
- private int count;
- public String _connectionString = "vm://:1";
- private static final String INVALID_SELECTOR = "Cost LIKE 5";
- CountDownLatch _responseLatch = new CountDownLatch(1);
-
- protected void setUp() throws Exception
- {
- super.setUp();
- init((AMQConnection) getConnection("guest", "guest"));
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
- private void init(AMQConnection connection) throws JMSException
- {
- init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true));
- }
-
- private void init(AMQConnection connection, AMQDestination destination) throws JMSException
- {
- _connection = connection;
- _destination = destination;
- connection.start();
-
- String selector = null;
- selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
- // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
-
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- // _session.createConsumer(destination).setMessageListener(this);
- _session.createConsumer(destination, selector).setMessageListener(this);
- }
-
- public void test() throws Exception
- {
- try
- {
-
- init((AMQConnection) getConnection("guest", "guest", randomize("Client")));
-
- Message msg = _session.createTextMessage("Message");
- msg.setJMSPriority(1);
- msg.setIntProperty("Cost", 2);
- msg.setStringProperty("property-with-hyphen", "wibble");
- msg.setJMSType("Special");
-
- _logger.info("Sending Message:" + msg);
-
- ((BasicMessageProducer) _session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
- _logger.info("Message sent, waiting for response...");
-
- _responseLatch.await();
-
- if (count > 0)
- {
- _logger.info("Got message");
- }
-
- if (count == 0)
- {
- fail("Did not get message!");
- // throw new RuntimeException("Did not get message!");
- }
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- System.out.println("SUCCESS!!");
- }
- }
- catch (InterruptedException e)
- {
- _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- _logger.debug("URL:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
- catch (AMQException e)
- {
- _logger.debug("AMQ:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
-
- finally
- {
- if (_session != null)
- {
- _session.close();
- }
- if (_connection != null)
- {
- _connection.close();
- }
- }
- }
-
-
- public void testInvalidSelectors() throws Exception
- {
- Connection connection = null;
-
- try
- {
- connection = getConnection("guest", "guest", randomize("Client"));
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- }
- catch (JMSException e)
- {
- fail(e.getMessage());
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- fail("Error:" + e.getMessage());
- }
-
- //Try Creating a Browser
- try
- {
- _session.createBrowser(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Consumer
- try
- {
- _session.createConsumer(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Receiever
- try
- {
- _session.createReceiver(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- finally
- {
- if (_session != null)
- {
- try
- {
- _session.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- if (_connection != null)
- {
- try
- {
- _connection.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- }
- }
-
- public void onMessage(Message message)
- {
- count++;
- _logger.info("Got Message:" + message);
- _responseLatch.countDown();
- }
-
- private static String randomize(String in)
- {
- return in + System.currentTimeMillis();
- }
-
- public static void main(String[] argv) throws Exception
- {
- SelectorTest test = new SelectorTest();
- test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
-
- try
- {
- while (true)
- {
- if (test._connectionString.contains("vm://:1"))
- {
- test.setUp();
- }
- test.test();
-
- if (test._connectionString.contains("vm://:1"))
- {
- test.tearDown();
- }
- }
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(SelectorTest.class);
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
new file mode 100644
index 0000000000..c9810e7304
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+/**
+ * QPID-155
+ *
+ * Test to validate that setting the respective qpid.declare_queues,
+ * qpid.declare_exchanges system properties functions as expected.
+ *
+ */
+public class DynamicQueueExchangeCreateTest extends QpidTestCase
+{
+
+ public void testQueueDeclare() throws Exception
+ {
+ setSystemProperty("qpid.declare_queues", "false");
+
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Queue queue = session.createQueue(getTestQueueName());
+
+ try
+ {
+ session.createConsumer(queue);
+ fail("JMSException should be thrown as the queue does not exist");
+ }
+ catch (JMSException e)
+ {
+ assertTrue("Exception should be that the queue does not exist :" +
+ e.getMessage(),
+ e.getMessage().contains("does not exist"));
+
+ }
+ }
+
+ public void testExchangeDeclare() throws Exception
+ {
+ setSystemProperty("qpid.declare_exchanges", "false");
+
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ String EXCHANGE_TYPE = "test.direct";
+ Queue queue = session.createQueue("direct://" + EXCHANGE_TYPE + "/queue/queue");
+
+ try
+ {
+ session.createConsumer(queue);
+ fail("JMSException should be thrown as the exchange does not exist");
+ }
+ catch (JMSException e)
+ {
+ assertTrue("Exception should be that the exchange does not exist :" +
+ e.getMessage(),
+ e.getMessage().contains("Exchange " + EXCHANGE_TYPE + " does not exist"));
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java
new file mode 100644
index 0000000000..3fb6cd3526
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.close;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.framing.ExchangeDeclareOkBody;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Session;
+
+/** QPID-1809
+ *
+ * Race condition on error handling and close logic.
+ *
+ * See most often with SimpleACLTest as this test is the expects the server to
+ * shut the connection/channels. This sort of testing is not performed by many,
+ * if any, of the other system tests.
+ *
+ * The problem is that we have two threads
+ *
+ * MainThread Exception(Mina)Thread
+ * | |
+ * Performs |
+ * ACtion |
+ * | Receives Server
+ * | Close
+ * Blocks for |
+ * Response |
+ * | Starts To Notify
+ * | client
+ * | |
+ * | <----- Notify Main Thread
+ * Notification |
+ * wakes client |
+ * | |
+ * Client then |
+ * processes Error. |
+ * | |
+ * Potentially Attempting Close Channel/Connection
+ * Connection Close
+ *
+ * The two threads both attempt to close the connection but the main thread does
+ * so assuming that the connection is open and valid.
+ *
+ * The Exception thread must modify the connection so that no furter syncWait
+ * commands are performed.
+ *
+ * This test sends an ExchangeDeclare that is Asynchronous and will fail and
+ * so cause a ChannelClose error but we perform a syncWait so that we can be
+ * sure to test that the BlockingWaiter is correctly awoken.
+ *
+ */
+public class JavaServerCloseRaceConditionTest extends QpidTestCase
+{
+ private static final String EXCHANGE_NAME = "NewExchangeNametoFailLookup";
+
+ public void test() throws Exception
+ {
+
+ AMQConnection connection = (AMQConnection) getConnection();
+
+ AMQSession session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Set no wait true so that we block the connection
+ // Also set a different exchange class string so the attempt to declare
+ // the exchange causes an exchange.
+ ExchangeDeclareBody body = session.getMethodRegistry().createExchangeDeclareBody(session.getTicket(), new AMQShortString(EXCHANGE_NAME), null,
+ true, false, false, false, true, null);
+
+ AMQFrame exchangeDeclare = body.generateFrame(session.getChannelId());
+
+ try
+ {
+ // block our thread so that can times out
+ connection.getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class);
+ }
+ catch (Exception e)
+ {
+ assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME));
+ }
+
+ try
+ {
+ // Depending on if the notification thread has closed the connection
+ // or not we may get an exception here when we attempt to close the
+ // connection. If we do get one then it should be the same as above
+ // an AMQAuthenticationException.
+ connection.close();
+ }
+ catch (Exception e)
+ {
+ assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME));
+ }
+
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
index 9c755fcb41..b603455644 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
@@ -479,7 +479,7 @@ public class CommitRollbackTest extends QpidTestCase
_publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
_pubSession.commit();
- assertNotNull(_consumer.receive(100));
+ assertNotNull(_consumer.receive(1000));
_publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
new file mode 100644
index 0000000000..3f8cdb9c25
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.utils;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.commands.objects.AllObjects;
+import org.apache.qpid.management.common.JMXConnnectionFactory;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ *
+ */
+public class JMXTestUtils
+{
+ QpidTestCase _test;
+ MBeanServerConnection _mbsc;
+ JMXConnector _jmxc;
+
+ private String USER;
+ private String PASSWORD;
+
+ public JMXTestUtils(QpidTestCase test, String user, String password)
+ {
+ _test = test;
+ USER = user;
+ PASSWORD = password;
+ }
+
+ public void setUp() throws IOException, ConfigurationException, Exception
+ {
+ _test.setConfigurationProperty("management.enabled", "true");
+ }
+
+ public void open() throws Exception
+ {
+ _jmxc = JMXConnnectionFactory.getJMXConnection(
+ 5000, "127.0.0.1",
+ _test.getManagementPort(_test.getPort()), USER, PASSWORD);
+
+ _mbsc = _jmxc.getMBeanServerConnection();
+ }
+
+ public void close() throws IOException
+ {
+ _jmxc.close();
+ }
+
+ /**
+ * Create a non-durable test exchange with the current test name
+ *
+ * @throws javax.management.JMException - is thrown if a exchange with this testName already exists
+ * @throws java.io.IOException - if there is a problem with the JMX Connection
+ * @throws javax.management.MBeanException
+ * - if there is another problem creating the exchange
+ */
+ public void createExchange(String virtualHostName, String name, String type, boolean durable)
+ throws JMException, IOException, MBeanException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+
+ managedBroker.createNewExchange(name, type, durable);
+ }
+
+ /**
+ * Create a non-durable queue (with no owner) that is named after the
+ * creating test.
+ *
+ * @throws JMException - is thrown if a queue with this testName already exists
+ * @throws IOException - if there is a problem with the JMX Connection
+ */
+ public void createQueue(String virtualHostName, String name, String owner, boolean durable)
+ throws JMException, IOException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+
+ managedBroker.createNewQueue(name, owner, durable);
+ }
+
+ /**
+ * Retrive the ObjectName for the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedBroker MBean.
+ *
+ * @return the ObjectName for the 'test' VirtualHost.
+ */
+ public ObjectName getVirtualHostManagerObjectName(String vhostName)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + vhostName + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertEquals("Incorrect number test vhosts returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ /**
+ * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedExchange MBean.
+ *
+ * @param queue The exchange to retireve e.g. 'direct'
+ *
+ * @return the ObjectName for the given exchange on the test VirtualHost.
+ */
+ public ObjectName getQueueObjectName(String virtualHostName, String queue)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=" + virtualHostName + ",name=" + queue + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertEquals("Incorrect number of exchange with name '" + queue +
+ "' returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ /**
+ * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedExchange MBean.
+ *
+ * @param virtualHostName
+ * @param exchange The exchange to retireve e.g. 'direct'
+ *
+ * @return the ObjectName for the given exchange on the test VirtualHost.
+ */
+ public ObjectName getExchangeObjectName(String virtualHostName, String exchange)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=" + virtualHostName + ",name=" + exchange + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertEquals("Incorrect number of exchange with name '" + exchange +
+ "' returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ public <T> T getManagedObject(Class<T> managedClass, String queryString)
+ {
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = queryString;
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertEquals("More than one " + managedClass + " returned", 1, objectNames.size());
+
+ ObjectName objectName = objectNames.iterator().next();
+
+ return getManagedObject(managedClass, objectName);
+ }
+
+ public <T> T getManagedObject(Class<T> managedClass, ObjectName objectName)
+ {
+ return MBeanServerInvocationHandler.
+ newProxyInstance(_mbsc, objectName, managedClass, false);
+ }
+
+ public ManagedBroker getManagedBroker(String virtualHost)
+ {
+ return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost).toString());
+ }
+
+ public ManagedExchange getManagedExchange(String exchangeName)
+ {
+ return MBeanServerInvocationHandler.
+ newProxyInstance(_mbsc, getExchangeObjectName("test", exchangeName),
+ ManagedExchange.class, false);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
index db096710dc..bed5d3242a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -21,6 +21,7 @@ import junit.framework.TestCase;
import junit.framework.TestResult;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQConnectionFactory;
import org.apache.qpid.client.transport.TransportConnection;
@@ -30,6 +31,7 @@ import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import org.apache.qpid.server.store.DerbyMessageStore;
+import org.apache.qpid.url.URLSyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -73,6 +75,7 @@ public class QpidTestCase extends TestCase
protected long RECEIVE_TIMEOUT = 1000l;
private Map<String, String> _setProperties = new HashMap<String, String>();
+ private XMLConfiguration _testConfiguration = new XMLConfiguration();
/**
* Some tests are excluded when the property test.excludes is set to true.
@@ -183,8 +186,7 @@ public class QpidTestCase extends TestCase
public static final String QUEUE = "queue";
public static final String TOPIC = "topic";
/** Map to hold test defined environment properties */
- private Map<String,String> _env;
-
+ private Map<String, String> _env;
public QpidTestCase(String name)
{
@@ -335,7 +337,7 @@ public class QpidTestCase extends TestCase
latch.countDown();
}
- if (latch != null && line.contains(stopped))
+ if (!seenReady && line.contains(stopped))
{
stopLine = line;
}
@@ -368,7 +370,9 @@ public class QpidTestCase extends TestCase
/**
* Return the management portin use by the broker on this main port
+ *
* @param mainPort the broker's main port.
+ *
* @return the management port that corresponds to the broker on the given port
*/
protected int getManagementPort(int mainPort)
@@ -415,9 +419,14 @@ public class QpidTestCase extends TestCase
{
port = getPort(port);
+ // Save any configuratio changes that have been made
+ saveTestConfiguration();
+
Process process = null;
if (_broker.equals(VM))
{
+ setConfigurationProperty("management.jmxport", String.valueOf(getManagementPort(port)));
+ saveTestConfiguration();
// create an in_VM broker
ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(_configFile), port);
TransportConnection.createVMBroker(port);
@@ -438,15 +447,35 @@ public class QpidTestCase extends TestCase
env.put("PATH", env.get("PATH").concat(File.pathSeparator + qpidHome + "/bin"));
//Add the test name to the broker run.
- env.put("QPID_PNAME", "-DPNAME=\"" + _testName + "\"");
+ // DON'T change PNAME, qpid.stop needs this value.
+ env.put("QPID_PNAME", "-DPNAME=QPBRKR -DTNAME=\"" + _testName + "\"");
env.put("QPID_WORK", System.getProperty("QPID_WORK"));
// Add all the environment settings the test requested
if (!_env.isEmpty())
{
- for(Map.Entry<String,String> entry : _env.entrySet())
+ for (Map.Entry<String, String> entry : _env.entrySet())
+ {
+ env.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ String QPID_OPTS = " ";
+ // Add all the specified system properties to QPID_OPTS
+ if (!_setProperties.isEmpty())
+ {
+ for (String key : _setProperties.keySet())
+ {
+ QPID_OPTS += "-D" + key + "=" + System.getProperty(key) + " ";
+ }
+
+ if (env.containsKey("QPID_OPTS"))
{
- env.put(entry.getKey() ,entry.getValue());
+ env.put("QPID_OPTS", env.get("QPID_OPTS") + QPID_OPTS);
+ }
+ else
+ {
+ env.put("QPID_OPTS", QPID_OPTS);
}
}
@@ -484,6 +513,27 @@ public class QpidTestCase extends TestCase
_brokers.put(port, process);
}
+ public String getTestConfigFile()
+ {
+ String path = _output == null ? System.getProperty("java.io.tmpdir") : _output;
+ return path + "/" + getTestQueueName() + ".xml";
+ }
+
+ protected void saveTestConfiguration() throws ConfigurationException
+ {
+ String testConfig = getTestConfigFile();
+ //Specifiy the test configuration
+ setSystemProperty("test.config", testConfig);
+
+ // This is a work
+ if (_testConfiguration.isEmpty())
+ {
+ _testConfiguration.addProperty("test", getTestQueueName());
+ }
+
+ _testConfiguration.save(getTestConfigFile());
+ }
+
public void cleanBroker()
{
if (_brokerClean != null)
@@ -565,18 +615,12 @@ public class QpidTestCase extends TestCase
storeClass = bdb;
}
- // First we munge the config file and, if we're in a VM, set up an additional logfile
- XMLConfiguration configuration = new XMLConfiguration(_configFile);
- configuration.setProperty("virtualhosts.virtualhost." + virtualhost +
+
+ _testConfiguration.setProperty("virtualhosts.virtualhost." + virtualhost +
".store.class", storeClass.getName());
- configuration.setProperty("virtualhosts.virtualhost." + virtualhost +
+ _testConfiguration.setProperty("virtualhosts.virtualhost." + virtualhost +
".store." + DerbyMessageStore.ENVIRONMENT_PATH_PROPERTY,
- "${work}/" + virtualhost);
-
- File tmpFile = File.createTempFile("configFile", "test");
- tmpFile.deleteOnExit();
- configuration.save(tmpFile);
- _configFile = tmpFile;
+ "${QPID_WORK}/" + virtualhost);
}
/**
@@ -591,6 +635,10 @@ public class QpidTestCase extends TestCase
*/
protected String getConfigurationStringProperty(String property) throws ConfigurationException
{
+ // Call save Configuration to be sure we have saved the test specific
+ // file. As the optional status
+ saveTestConfiguration();
+
ServerConfiguration configuration = new ServerConfiguration(_configFile);
return configuration.getConfig().getString(property);
}
@@ -613,48 +661,9 @@ public class QpidTestCase extends TestCase
protected void setConfigurationProperty(String property, String value)
throws ConfigurationException, IOException
{
- XMLConfiguration configuration = new XMLConfiguration(_configFile);
-
- // If we are modifying a virtualhost value then we need to do so in
- // the virtualhost.xml file as these values overwrite the values in
- // the main config.xml file
- if (property.startsWith("virtualhosts"))
- {
- // So locate the virtualhost.xml file and use the ServerConfiguration
- // flatConfig method to get the interpolated value.
- String vhostConfigFile = ServerConfiguration.
- flatConfig(_configFile).getString("virtualhosts");
-
- // Load the vhostConfigFile
- XMLConfiguration vhostConfiguration = new XMLConfiguration(vhostConfigFile);
-
- // Set the value specified in to the vhostConfig.
- // Remembering that property will be 'virtualhosts.virtulhost....'
- // so we need to take off the 'virtualhosts.' from the start.
- vhostConfiguration.setProperty(property.substring(property.indexOf(".") + 1), value);
-
- // Write out the new virtualhost config file
- File tmpFile = File.createTempFile("virtualhost-configFile", ".xml");
- tmpFile.deleteOnExit();
- vhostConfiguration.save(tmpFile);
-
- // Change the property and value to be the new virtualhosts file
- // so that then update the value in the main config file.
- property = "virtualhosts";
- value = tmpFile.getAbsolutePath();
- }
-
- configuration.setProperty(property, value);
-
- // Write the new server config file
- File tmpFile = File.createTempFile("configFile", ".xml");
- tmpFile.deleteOnExit();
- configuration.save(tmpFile);
-
- _logger.info("Qpid Test Case now using configuration File:"
- + tmpFile.getAbsolutePath());
-
- _configFile = tmpFile;
+ //Write the value in to this configuration file which will override the
+ // defaults.
+ _testConfiguration.setProperty(property, value);
}
/**
@@ -695,14 +704,13 @@ public class QpidTestCase extends TestCase
* Add an environtmen variable for the external broker environment
*
* @param property the property to set
- * @param value the value to set it to
+ * @param value the value to set it to
*/
protected void setBrokerEnvironment(String property, String value)
{
- _env.put(property,value);
+ _env.put(property, value);
}
-
/**
* Check whether the broker is an 0.8
*
@@ -720,7 +728,7 @@ public class QpidTestCase extends TestCase
protected boolean isJavaBroker()
{
- return _brokerLanguage.equals("java");
+ return _brokerLanguage.equals("java") || _broker.equals("vm");
}
protected boolean isCppBroker()
@@ -831,7 +839,7 @@ public class QpidTestCase extends TestCase
*
* @throws Exception if there is an error getting the connection
*/
- public Connection getConnection(String username, String password) throws Exception
+ public Connection getConnection(String username, String password) throws JMSException, NamingException
{
_logger.info("get Connection");
Connection con = getConnectionFactory().createConnection(username, password);
@@ -840,7 +848,7 @@ public class QpidTestCase extends TestCase
return con;
}
- public Connection getConnection(String username, String password, String id) throws Exception
+ public Connection getConnection(String username, String password, String id) throws JMSException, URLSyntaxException, AMQException, NamingException
{
_logger.info("get Connection");
Connection con;
@@ -860,6 +868,7 @@ public class QpidTestCase extends TestCase
/**
* Return a uniqueName for this test.
* In this case it returns a queue Named by the TestCase and TestName
+ *
* @return String name for a queue
*/
protected String getTestQueueName()
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java
index b721e27726..2b9fe8e039 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java
@@ -158,18 +158,6 @@ public class LogMonitorTest extends TestCase
validateLogDoesNotContainsMessage(_monitor, notLogged);
}
- public void testWaitForMessage_Found() throws IOException
- {
- String message = getName() + ": Test Message";
-
- long TIME_OUT = 2000;
-
- logMessageWithDelay(message, TIME_OUT / 2);
-
- assertTrue("Message was not logged ",
- _monitor.waitForMessage(message, TIME_OUT));
- }
-
public void testWaitForMessage_Timeout() throws IOException
{
String message = getName() + ": Test Message";
diff --git a/qpid/java/test-profiles/010Excludes b/qpid/java/test-profiles/010Excludes
index e238934124..f03d62667d 100644
--- a/qpid/java/test-profiles/010Excludes
+++ b/qpid/java/test-profiles/010Excludes
@@ -83,3 +83,12 @@ org.apache.qpid.server.logging.*
// CPP Broker does not have a JMX interface to test
org.apache.qpid.management.jmx.*
+// JMX is used in this test for validation
+org.apache.qpid.server.queue.ModelTest#*
+
+
+// 0-10 is not supported by the MethodRegistry
+org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#*
+
+// QPID-2084 : this test needs more work for 0-10
+org.apache.qpid.test.unit.client.DynamicQueueExchangeCreateTest#*
diff --git a/qpid/java/test-profiles/08Excludes b/qpid/java/test-profiles/08Excludes
index 0866694854..b277c6d929 100644
--- a/qpid/java/test-profiles/08Excludes
+++ b/qpid/java/test-profiles/08Excludes
@@ -15,3 +15,8 @@ org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
org.apache.qpid.client.SessionCreateTest#*
org.apache.qpid.test.client.RollbackOrderTest#*
+
+// QPID-2097 exclude it from the InVM test runs until InVM JMX Interface is reliable
+org.apache.qpid.management.jmx.ManagementActorLoggingTest#*
+org.apache.qpid.server.queue.ModelTest#*
+
diff --git a/qpid/java/test-profiles/Excludes b/qpid/java/test-profiles/Excludes
index 7ef2a15e51..a72d3bc86c 100644
--- a/qpid/java/test-profiles/Excludes
+++ b/qpid/java/test-profiles/Excludes
@@ -13,5 +13,9 @@ org.apache.qpid.server.logging.BrokerLoggingTest#testBrokerShutdownListeningTCPS
org.apache.qpid.server.logging.BrokerLoggingTest#testBrokerShutdownStopped
org.apache.qpid.server.logging.VirtualHostLoggingTest#testVirtualhostClosure
org.apache.qpid.server.logging.MemoryMessageStoreLoggingTest#testMessageStoreClose
-org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#testMessageStoreClose
+// QPID-XXX : Test fails to start external broker due to Derby Exception.
+org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#*
+
+// QPID-2081 :The configuration changes are now highlighting the close race condition
+org.apache.qpid.server.security.acl.SimpleACLTest#*
diff --git a/qpid/java/test-profiles/cpp.testprofile b/qpid/java/test-profiles/cpp.testprofile
index 1d5416fe19..b3b979c786 100644
--- a/qpid/java/test-profiles/cpp.testprofile
+++ b/qpid/java/test-profiles/cpp.testprofile
@@ -8,6 +8,7 @@ broker.executable=${broker.dir}/qpidd
broker.module.ssl=${module.dir}/ssl.so
broker.module.cluster=${module.dir}/cluster.so
broker.module.store=${store.module.dir}/msgstore.so
+broker.stopped=Exception constructed
broker.modules=
broker.args=
diff --git a/qpid/java/test-profiles/default.testprofile b/qpid/java/test-profiles/default.testprofile
index 49d4a25b82..86a5b2efb3 100644
--- a/qpid/java/test-profiles/default.testprofile
+++ b/qpid/java/test-profiles/default.testprofile
@@ -18,9 +18,10 @@ log4j.debug=false
test.port=15672
test.mport=18999
+#Note : Management will start open second port on: mport + 100 : 19099
test.port.ssl=15671
-test.port.alt=15772
-test.port.alt.ssl=15771
+test.port.alt=25672
+test.port.alt.ssl=25671
test.exclude=true
profile.excludes=08TransientExcludes
diff --git a/qpid/python/Makefile b/qpid/python/Makefile
index 380115db41..31547c8f57 100644
--- a/qpid/python/Makefile
+++ b/qpid/python/Makefile
@@ -46,6 +46,12 @@ $(BUILD)/%.py: %.py
build: $(TARGETS)
+.PHONY: doc
+
+doc:
+ @mkdir -p $(BUILD)
+ epydoc qpid.messaging -o $(BUILD)/doc --no-private --no-sourcecode --include-log
+
install: build
install -d $(PYTHON_LIB)
diff --git a/qpid/python/qpid/concurrency.py b/qpid/python/qpid/concurrency.py
new file mode 100644
index 0000000000..00cdb6b953
--- /dev/null
+++ b/qpid/python/qpid/concurrency.py
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import inspect, time
+
+def synchronized(meth):
+ args, vargs, kwargs, defs = inspect.getargspec(meth)
+ scope = {}
+ scope["meth"] = meth
+ exec """
+def %s%s:
+ %s
+ %s._lock.acquire()
+ try:
+ return meth%s
+ finally:
+ %s._lock.release()
+""" % (meth.__name__, inspect.formatargspec(args, vargs, kwargs, defs),
+ repr(inspect.getdoc(meth)), args[0],
+ inspect.formatargspec(args, vargs, kwargs, defs,
+ formatvalue=lambda x: ""),
+ args[0]) in scope
+ return scope[meth.__name__]
+
+class Waiter(object):
+
+ def __init__(self, condition):
+ self.condition = condition
+
+ def wait(self, predicate, timeout=None):
+ passed = 0
+ start = time.time()
+ while not predicate():
+ if timeout is None:
+ # using the timed wait prevents keyboard interrupts from being
+ # blocked while waiting
+ self.condition.wait(3)
+ elif passed < timeout:
+ self.condition.wait(timeout - passed)
+ else:
+ return False
+ passed = time.time() - start
+ return True
+
+ def notify(self):
+ self.condition.notify()
+
+ def notifyAll(self):
+ self.condition.notifyAll()
diff --git a/qpid/python/qpid/datatypes.py b/qpid/python/qpid/datatypes.py
index f832ddae34..61643715e4 100644
--- a/qpid/python/qpid/datatypes.py
+++ b/qpid/python/qpid/datatypes.py
@@ -234,6 +234,24 @@ class RangedSet:
def add(self, lower, upper = None):
self.add_range(Range(lower, upper))
+ def empty(self):
+ for r in self.ranges:
+ if r.lower <= r.upper:
+ return False
+ return True
+
+ def max(self):
+ if self.ranges:
+ return self.ranges[-1].upper
+ else:
+ return None
+
+ def min(self):
+ if self.ranges:
+ return self.ranges[0].lower
+ else:
+ return None
+
def __iter__(self):
return iter(self.ranges)
diff --git a/qpid/python/qpid/delegates.py b/qpid/python/qpid/delegates.py
index c74cc5a945..14111a88df 100644
--- a/qpid/python/qpid/delegates.py
+++ b/qpid/python/qpid/delegates.py
@@ -139,12 +139,18 @@ class Server(Delegate):
class Client(Delegate):
+ ppid = 0
+ try:
+ ppid = os.getppid()
+ except:
+ pass
+
PROPERTIES = {"product": "qpid python client",
"version": "development",
"platform": os.name,
"qpid.client_process": os.path.basename(sys.argv[0]),
"qpid.client_pid": os.getpid(),
- "qpid.client_ppid": os.getppid()}
+ "qpid.client_ppid": ppid}
def __init__(self, connection, username="guest", password="guest",
mechanism="PLAIN", heartbeat=None):
diff --git a/qpid/python/qpid/driver.py b/qpid/python/qpid/driver.py
new file mode 100644
index 0000000000..2e07c82a0d
--- /dev/null
+++ b/qpid/python/qpid/driver.py
@@ -0,0 +1,444 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import compat, connection, socket, sys, time
+from concurrency import synchronized
+from datatypes import RangedSet, Message as Message010
+from exceptions import Timeout
+from logging import getLogger
+from messaging import get_codec, ConnectError, Message, Pattern, UNLIMITED
+from ops import delivery_mode
+from session import Client, INCOMPLETE, SessionDetached
+from threading import Condition, Thread
+from util import connect
+
+log = getLogger("qpid.messaging")
+
+def parse_addr(address):
+ parts = address.split("/", 1)
+ if len(parts) == 1:
+ return parts[0], None
+ else:
+ return parts[0], parts[i1]
+
+def reply_to2addr(reply_to):
+ if reply_to.routing_key is None:
+ return reply_to.exchange
+ elif reply_to.exchange in (None, ""):
+ return reply_to.routing_key
+ else:
+ return "%s/%s" % (reply_to.exchange, reply_to.routing_key)
+
+class Attachment:
+
+ def __init__(self, target):
+ self.target = target
+
+DURABLE_DEFAULT=True
+
+FILTER_DEFAULTS = {
+ "topic": Pattern("*")
+ }
+
+def delegate(handler, session):
+ class Delegate(Client):
+
+ def message_transfer(self, cmd):
+ return handler._message_transfer(session, cmd)
+ return Delegate
+
+class Driver:
+
+ def __init__(self, connection):
+ self.connection = connection
+ self._lock = self.connection._lock
+ self._wakeup_cond = Condition()
+ self._socket = None
+ self._conn = None
+ self._connected = False
+ self._attachments = {}
+ self._modcount = self.connection._modcount
+ self.thread = Thread(target=self.run)
+ self.thread.setDaemon(True)
+ # XXX: need to figure out how to join on this thread
+
+ def wakeup(self):
+ self._wakeup_cond.acquire()
+ try:
+ self._wakeup_cond.notifyAll()
+ finally:
+ self._wakeup_cond.release()
+
+ def start(self):
+ self.thread.start()
+
+ def run(self):
+ while True:
+ self._wakeup_cond.acquire()
+ try:
+ if self.connection._modcount <= self._modcount:
+ self._wakeup_cond.wait(10)
+ finally:
+ self._wakeup_cond.release()
+ self.dispatch(self.connection._modcount)
+
+ @synchronized
+ def dispatch(self, modcount):
+ try:
+ if self._conn is None and self.connection._connected:
+ self.connect()
+ elif self._conn is not None and not self.connection._connected:
+ self.disconnect()
+
+ if self._conn is not None:
+ for ssn in self.connection.sessions.values():
+ self.attach(ssn)
+ self.process(ssn)
+
+ exi = None
+ except:
+ exi = sys.exc_info()
+
+ if exi:
+ msg = compat.format_exc()
+ recoverable = ["aborted", "Connection refused", "SessionDetached", "Connection reset by peer",
+ "Bad file descriptor", "start timed out", "Broken pipe"]
+ for r in recoverable:
+ if self.connection.reconnect and r in msg:
+ print "waiting to retry"
+ self.reset()
+ time.sleep(3)
+ print "retrying..."
+ return
+ else:
+ self.connection.error = (msg,)
+
+ self._modcount = modcount
+ self.connection._waiter.notifyAll()
+
+ def connect(self):
+ if self._conn is not None:
+ return
+ try:
+ self._socket = connect(self.connection.host, self.connection.port)
+ except socket.error, e:
+ raise ConnectError(e)
+ self._conn = connection.Connection(self._socket)
+ try:
+ self._conn.start(timeout=10)
+ self._connected = True
+ except connection.VersionError, e:
+ raise ConnectError(e)
+ except Timeout:
+ print "start timed out"
+ raise ConnectError("start timed out")
+
+ def disconnect(self):
+ self._conn.close()
+ self.reset()
+
+ def reset(self):
+ self._conn = None
+ self._connected = False
+ self._attachments.clear()
+ for ssn in self.connection.sessions.values():
+ for m in ssn.acked + ssn.unacked + ssn.incoming:
+ m._transfer_id = None
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+
+ def connected(self):
+ return self._conn is not None
+
+ def attach(self, ssn):
+ _ssn = self._attachments.get(ssn)
+ if _ssn is None:
+ _ssn = self._conn.session(ssn.name, delegate=delegate(self, ssn))
+ _ssn.auto_sync = False
+ _ssn.invoke_lock = self._lock
+ _ssn.lock = self._lock
+ _ssn.condition = self.connection._condition
+ if ssn.transactional:
+ # XXX: adding an attribute to qpid.session.Session
+ _ssn.acked = []
+ _ssn.tx_select()
+ self._attachments[ssn] = _ssn
+
+ for snd in ssn.senders:
+ self.link_out(snd)
+ for rcv in ssn.receivers:
+ self.link_in(rcv)
+
+ if ssn.closing:
+ _ssn.close()
+ del self._attachments[ssn]
+ ssn.closed = True
+
+ def _exchange_query(self, ssn, address):
+ # XXX: auto sync hack is to avoid deadlock on future
+ result = ssn.exchange_query(name=address, sync=True)
+ ssn.sync()
+ return result.get()
+
+ def link_out(self, snd):
+ _ssn = self._attachments[snd.session]
+ _snd = self._attachments.get(snd)
+ if _snd is None:
+ _snd = Attachment(snd)
+ node, _snd._subject = parse_addr(snd.target)
+ result = self._exchange_query(_ssn, node)
+ if result.not_found:
+ # XXX: should check 'create' option
+ _ssn.queue_declare(queue=node, durable=DURABLE_DEFAULT, sync=True)
+ _ssn.sync()
+ _snd._exchange = ""
+ _snd._routing_key = node
+ else:
+ _snd._exchange = node
+ _snd._routing_key = _snd._subject
+ self._attachments[snd] = _snd
+
+ if snd.closed:
+ del self._attachments[snd]
+ return None
+ else:
+ return _snd
+
+ def link_in(self, rcv):
+ _ssn = self._attachments[rcv.session]
+ _rcv = self._attachments.get(rcv)
+ if _rcv is None:
+ _rcv = Attachment(rcv)
+ result = self._exchange_query(_ssn, rcv.source)
+ if result.not_found:
+ _rcv._queue = rcv.source
+ # XXX: should check 'create' option
+ _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT)
+ else:
+ _rcv._queue = "%s.%s" % (rcv.session.name, rcv.destination)
+ _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True)
+ if rcv.filter is None:
+ f = FILTER_DEFAULTS[result.type]
+ else:
+ f = rcv.filter
+ f._bind(_ssn, rcv.source, _rcv._queue)
+ _ssn.message_subscribe(queue=_rcv._queue, destination=rcv.destination)
+ _ssn.message_set_flow_mode(rcv.destination, _ssn.flow_mode.credit, sync=True)
+ self._attachments[rcv] = _rcv
+ # XXX: need to kill syncs
+ _ssn.sync()
+
+ if rcv.closing:
+ _ssn.message_cancel(rcv.destination, sync=True)
+ # XXX: need to kill syncs
+ _ssn.sync()
+ del self._attachments[rcv]
+ rcv.closed = True
+ return None
+ else:
+ return _rcv
+
+ def process(self, ssn):
+ if ssn.closing: return
+
+ _ssn = self._attachments[ssn]
+
+ while ssn.outgoing:
+ msg = ssn.outgoing[0]
+ snd = msg._sender
+ self.send(snd, msg)
+ ssn.outgoing.pop(0)
+
+ for rcv in ssn.receivers:
+ self.process_receiver(rcv)
+
+ if ssn.acked:
+ messages = ssn.acked[:]
+ ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
+ for range in ids:
+ _ssn.receiver._completed.add_range(range)
+ ch = _ssn.channel
+ if ch is None:
+ raise SessionDetached()
+ ch.session_completed(_ssn.receiver._completed)
+ _ssn.message_accept(ids, sync=True)
+ # XXX: really need to make this async so that we don't give up the lock
+ _ssn.sync()
+
+ # XXX: we're ignoring acks that get lost when disconnected
+ for m in messages:
+ ssn.acked.remove(m)
+ if ssn.transactional:
+ _ssn.acked.append(m)
+
+ if ssn.committing:
+ _ssn.tx_commit(sync=True)
+ # XXX: need to kill syncs
+ _ssn.sync()
+ del _ssn.acked[:]
+ ssn.committing = False
+ ssn.committed = True
+ ssn.aborting = False
+ ssn.aborted = False
+
+ if ssn.aborting:
+ for rcv in ssn.receivers:
+ _ssn.message_stop(rcv.destination)
+ _ssn.sync()
+
+ messages = _ssn.acked + ssn.unacked + ssn.incoming
+ ids = RangedSet(*[m._transfer_id for m in messages])
+ for range in ids:
+ _ssn.receiver._completed.add_range(range)
+ _ssn.channel.session_completed(_ssn.receiver._completed)
+ _ssn.message_release(ids)
+ _ssn.tx_rollback(sync=True)
+ _ssn.sync()
+
+ del ssn.incoming[:]
+ del ssn.unacked[:]
+ del _ssn.acked[:]
+
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+ rcv.returned = rcv.received
+ # XXX: do we need to update granted here as well?
+
+ for rcv in ssn.receivers:
+ self.process_receiver(rcv)
+
+ ssn.aborting = False
+ ssn.aborted = True
+ ssn.committing = False
+ ssn.committed = False
+
+ def grant(self, rcv):
+ _ssn = self._attachments[rcv.session]
+ _rcv = self.link_in(rcv)
+
+ if rcv.granted is UNLIMITED:
+ if rcv.impending is UNLIMITED:
+ delta = 0
+ else:
+ delta = UNLIMITED
+ elif rcv.impending is UNLIMITED:
+ delta = -1
+ else:
+ delta = max(rcv.granted, rcv.received) - rcv.impending
+
+ if delta is UNLIMITED:
+ _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
+ _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, UNLIMITED.value)
+ rcv.impending = UNLIMITED
+ elif delta > 0:
+ _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
+ _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, delta)
+ rcv.impending += delta
+ elif delta < 0:
+ if rcv.drain:
+ _ssn.message_flush(rcv.destination, sync=True)
+ else:
+ _ssn.message_stop(rcv.destination, sync=True)
+ # XXX: need to kill syncs
+ _ssn.sync()
+ rcv.impending = rcv.received
+ self.grant(rcv)
+
+ def process_receiver(self, rcv):
+ if rcv.closed: return
+ self.grant(rcv)
+
+ def send(self, snd, msg):
+ _ssn = self._attachments[snd.session]
+ _snd = self.link_out(snd)
+
+ # XXX: what if subject is specified for a normal queue?
+ if _snd._routing_key is None:
+ rk = msg.subject
+ else:
+ rk = _snd._routing_key
+ # XXX: do we need to query to figure out how to create the reply-to interoperably?
+ if msg.reply_to:
+ rt = _ssn.reply_to(*parse_addr(msg.reply_to))
+ else:
+ rt = None
+ dp = _ssn.delivery_properties(routing_key=rk)
+ mp = _ssn.message_properties(message_id=msg.id,
+ user_id=msg.user_id,
+ reply_to=rt,
+ correlation_id=msg.correlation_id,
+ content_type=msg.content_type,
+ application_headers=msg.properties)
+ if msg.subject is not None:
+ if mp.application_headers is None:
+ mp.application_headers = {}
+ mp.application_headers["subject"] = msg.subject
+ if msg.to is not None:
+ if mp.application_headers is None:
+ mp.application_headers = {}
+ mp.application_headers["to"] = msg.to
+ if msg.durable:
+ dp.delivery_mode = delivery_mode.persistent
+ enc, dec = get_codec(msg.content_type)
+ body = enc(msg.content)
+ _ssn.message_transfer(destination=_snd._exchange,
+ message=Message010(dp, mp, body),
+ sync=True)
+ log.debug("SENT [%s] %s", snd.session, msg)
+ # XXX: really need to make this async so that we don't give up the lock
+ _ssn.sync()
+ # XXX: should we log the ack somehow too?
+ snd.acked += 1
+
+ @synchronized
+ def _message_transfer(self, ssn, cmd):
+ m = Message010(cmd.payload)
+ m.headers = cmd.headers
+ m.id = cmd.id
+ msg = self._decode(m)
+ rcv = ssn.receivers[int(cmd.destination)]
+ msg._receiver = rcv
+ if rcv.impending is not UNLIMITED:
+ assert rcv.received < rcv.impending
+ rcv.received += 1
+ log.debug("RECV [%s] %s", ssn, msg)
+ ssn.incoming.append(msg)
+ self.connection._waiter.notifyAll()
+ return INCOMPLETE
+
+ def _decode(self, message):
+ dp = message.get("delivery_properties")
+ mp = message.get("message_properties")
+ ap = mp.application_headers
+ enc, dec = get_codec(mp.content_type)
+ content = dec(message.body)
+ msg = Message(content)
+ msg.id = mp.message_id
+ if ap is not None:
+ msg.to = ap.get("to")
+ msg.subject = ap.get("subject")
+ msg.user_id = mp.user_id
+ 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
+ msg.properties = mp.application_headers
+ msg.content_type = mp.content_type
+ msg._transfer_id = message.id
+ return msg
diff --git a/qpid/python/qpid/messaging.py b/qpid/python/qpid/messaging.py
index 3c41a2c417..d755aa5054 100644
--- a/qpid/python/qpid/messaging.py
+++ b/qpid/python/qpid/messaging.py
@@ -6,9 +6,9 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,64 +30,18 @@ Areas that still need work:
- protocol negotiation/multiprotocol impl
"""
-import connection, time, socket, sys, compat
from codec010 import StringCodec
-from datatypes import timestamp, uuid4, RangedSet, Message as Message010, Serial
-from exceptions import Timeout
+from concurrency import synchronized, Waiter
+from datatypes import timestamp, uuid4, Serial
from logging import getLogger
-from ops import PRIMITIVE, delivery_mode
-from session import Client, INCOMPLETE, SessionDetached
+from ops import PRIMITIVE
from threading import Thread, RLock, Condition
-from util import connect
+from util import default
log = getLogger("qpid.messaging")
static = staticmethod
-def synchronized(meth):
- def sync_wrapper(self, *args, **kwargs):
- self.lock()
- try:
- return meth(self, *args, **kwargs)
- finally:
- self.unlock()
- return sync_wrapper
-
-class Lockable(object):
-
- def lock(self):
- self._lock.acquire()
-
- def unlock(self):
- self._lock.release()
-
- def wait(self, predicate, timeout=None):
- passed = 0
- start = time.time()
- while not predicate():
- if timeout is None:
- # using the timed wait prevents keyboard interrupts from being
- # blocked while waiting
- self._condition.wait(3)
- elif passed < timeout:
- self._condition.wait(timeout - passed)
- else:
- return False
- passed = time.time() - start
- return True
-
- def notify(self):
- self._condition.notify()
-
- def notifyAll(self):
- self._condition.notifyAll()
-
-def default(value, default):
- if value is None:
- return default
- else:
- return value
-
AMQP_PORT = 5672
AMQPS_PORT = 5671
@@ -103,12 +57,19 @@ class Constant:
UNLIMITED = Constant("UNLIMITED", 0xFFFFFFFFL)
class ConnectionError(Exception):
+ """
+ The base class for all connection related exceptions.
+ """
pass
class ConnectError(ConnectionError):
+ """
+ Exception raised when there is an error connecting to the remote
+ peer.
+ """
pass
-class Connection(Lockable):
+class Connection:
"""
A Connection manages a group of L{Sessions<Session>} and connects
@@ -153,27 +114,27 @@ class Connection(Lockable):
self._connected = False
self._lock = RLock()
self._condition = Condition(self._lock)
+ self._waiter = Waiter(self._condition)
self._modcount = Serial(0)
self.error = None
+ from driver import Driver
self._driver = Driver(self)
self._driver.start()
- def wakeup(self):
+ def _wait(self, predicate, timeout=None):
+ return self._waiter.wait(predicate, timeout=timeout)
+
+ def _wakeup(self):
self._modcount += 1
self._driver.wakeup()
- def catchup(self, exc=ConnectionError):
- mc = self._modcount
- self.wait(lambda: not self._driver._modcount < mc)
- self.check_error(exc)
-
- def check_error(self, exc=ConnectionError):
+ def _check_error(self, exc=ConnectionError):
if self.error:
raise exc(*self.error)
- def ewait(self, predicate, timeout=None, exc=ConnectionError):
- result = self.wait(lambda: self.error or predicate(), timeout)
- self.check_error(exc)
+ def _ewait(self, predicate, timeout=None, exc=ConnectionError):
+ result = self._wait(lambda: self.error or predicate(), timeout)
+ self._check_error(exc)
return result
@synchronized
@@ -200,7 +161,7 @@ class Connection(Lockable):
else:
ssn = Session(self, name, self.started, transactional=transactional)
self.sessions[name] = ssn
- self.wakeup()
+ self._wakeup()
return ssn
@synchronized
@@ -213,8 +174,8 @@ class Connection(Lockable):
Connect to the remote endpoint.
"""
self._connected = True
- self.wakeup()
- self.ewait(lambda: self._driver._connected, exc=ConnectError)
+ self._wakeup()
+ self._ewait(lambda: self._driver._connected, exc=ConnectError)
@synchronized
def disconnect(self):
@@ -222,8 +183,8 @@ class Connection(Lockable):
Disconnect from the remote endpoint.
"""
self._connected = False
- self.wakeup()
- self.ewait(lambda: not self._driver._connected)
+ self._wakeup()
+ self._ewait(lambda: not self._driver._connected)
@synchronized
def connected(self):
@@ -273,17 +234,6 @@ class Pattern:
ssn.exchange_bind(exchange=exchange, queue=queue,
binding_key=self.value.replace("*", "#"))
-FILTER_DEFAULTS = {
- "topic": Pattern("*")
- }
-
-def delegate(handler, session):
- class Delegate(Client):
-
- def message_transfer(self, cmd):
- handler._message_transfer(session, cmd)
- return Delegate
-
class SessionError(Exception):
pass
@@ -304,7 +254,7 @@ class NontransactionalSession(SessionError):
class TransactionAborted(SessionError):
pass
-class Session(Lockable):
+class Session:
"""
Sessions provide a linear context for sending and receiving
@@ -329,12 +279,14 @@ class Session(Lockable):
self.incoming = []
self.unacked = []
self.acked = []
+ # XXX: I hate this name.
+ self.ack_capacity = UNLIMITED
self.closing = False
self.closed = False
self._lock = connection._lock
- self._condition = connection._condition
+ self.running = True
self.thread = Thread(target = self.run)
self.thread.setDaemon(True)
self.thread.start()
@@ -342,17 +294,17 @@ class Session(Lockable):
def __repr__(self):
return "<Session %s>" % self.name
- def wakeup(self):
- self.connection.wakeup()
+ def _wait(self, predicate, timeout=None):
+ return self.connection._wait(predicate, timeout=timeout)
- def catchup(self, exc=SessionError):
- self.connection.catchup(exc)
+ def _wakeup(self):
+ self.connection._wakeup()
- def check_error(self, exc=SessionError):
- self.connection.check_error(exc)
+ def _check_error(self, exc=SessionError):
+ self.connection._check_error(exc)
- def ewait(self, predicate, timeout=None, exc=SessionError):
- return self.connection.ewait(predicate, timeout, exc)
+ def _ewait(self, predicate, timeout=None, exc=SessionError):
+ return self.connection._ewait(predicate, timeout, exc)
@synchronized
def sender(self, target):
@@ -367,7 +319,7 @@ class Session(Lockable):
"""
sender = Sender(self, len(self.senders), target)
self.senders.append(sender)
- self.wakeup()
+ self._wakeup()
# XXX: because of the lack of waiting here we can end up getting
# into the driver loop with messages sent for senders that haven't
# been linked yet, something similar can probably happen for
@@ -388,7 +340,7 @@ class Session(Lockable):
receiver = Receiver(self, len(self.receivers), source, filter,
self.started)
self.receivers.append(receiver)
- self.wakeup()
+ self._wakeup()
return receiver
@synchronized
@@ -416,8 +368,8 @@ class Session(Lockable):
@synchronized
def _get(self, predicate, timeout=None):
- if self.wait(lambda: ((self._peek(predicate) is not None) or self.closing),
- timeout):
+ if self._wait(lambda: ((self._peek(predicate) is not None) or self.closing),
+ timeout):
msg = self._pop(predicate)
if msg is not None:
msg._receiver.returned += 1
@@ -427,13 +379,15 @@ class Session(Lockable):
return None
@synchronized
- def acknowledge(self, message=None):
+ def acknowledge(self, message=None, sync=True):
"""
Acknowledge the given L{Message}. If message is None, then all
unacknowledged messages on the session are acknowledged.
@type message: Message
@param message: the message to acknowledge or None
+ @type sync: boolean
+ @param sync: if true then block until the message(s) are acknowledged
"""
if message is None:
messages = self.unacked[:]
@@ -441,12 +395,18 @@ class Session(Lockable):
messages = [message]
for m in messages:
+ if self.ack_capacity is not UNLIMITED:
+ if self.ack_capacity <= 0:
+ # XXX: this is currently a SendError, maybe it should be a SessionError?
+ raise InsufficientCapacity("ack_capacity = %s" % self.ack_capacity)
+ self._wakeup()
+ self._ewait(lambda: len(self.acked) < self.ack_capacity)
self.unacked.remove(m)
self.acked.append(m)
- self.wakeup()
- self.wait(lambda: self.connection.error or not [m for m in messages if m in self.acked])
- self.check_error()
+ self._wakeup()
+ if sync:
+ self._ewait(lambda: not [m for m in messages if m in self.acked])
@synchronized
def commit(self):
@@ -457,8 +417,8 @@ class Session(Lockable):
if not self.transactional:
raise NontransactionalSession()
self.committing = True
- self.wakeup()
- self.ewait(lambda: not self.committing)
+ self._wakeup()
+ self._ewait(lambda: not self.committing)
if self.aborted:
raise TransactionAborted()
assert self.committed
@@ -472,8 +432,8 @@ class Session(Lockable):
if not self.transactional:
raise NontransactionalSession()
self.aborting = True
- self.wakeup()
- self.ewait(lambda: not self.aborting)
+ self._wakeup()
+ self._ewait(lambda: not self.aborting)
assert self.aborted
@synchronized
@@ -493,7 +453,7 @@ class Session(Lockable):
for rcv in self.receivers:
rcv.stop()
# TODO: think about stopping individual receivers in listen mode
- self.wait(lambda: self._peek(self._pred) is None)
+ self._wait(lambda: self._peek(self._pred) is None)
self.started = False
def _pred(self, m):
@@ -501,6 +461,7 @@ class Session(Lockable):
@synchronized
def run(self):
+ self.running = True
try:
while True:
msg = self._get(self._pred)
@@ -509,10 +470,10 @@ class Session(Lockable):
else:
msg._receiver.listener(msg)
if self._peek(self._pred) is None:
- self.notifyAll()
+ self.connection._waiter.notifyAll()
finally:
- self.closed = True
- self.notifyAll()
+ self.running = False
+ self.connection._waiter.notifyAll()
@synchronized
def close(self):
@@ -523,33 +484,22 @@ class Session(Lockable):
link.close()
self.closing = True
- self.wakeup()
- self.catchup()
- self.wait(lambda: self.closed)
+ self._wakeup()
+ self._ewait(lambda: self.closed and not self.running)
while self.thread.isAlive():
self.thread.join(3)
self.thread = None
+ # XXX: should be able to express this condition through API calls
+ self._ewait(lambda: not self.outgoing and not self.acked)
self.connection._remove_session(self)
-def parse_addr(address):
- parts = address.split("/", 1)
- if len(parts) == 1:
- return parts[0], None
- else:
- return parts[0], parts[i1]
-
-def reply_to2addr(reply_to):
- if reply_to.routing_key is None:
- return reply_to.exchange
- elif reply_to.exchange in (None, ""):
- return reply_to.routing_key
- else:
- return "%s/%s" % (reply_to.exchange, reply_to.routing_key)
-
class SendError(SessionError):
pass
-class Sender(Lockable):
+class InsufficientCapacity(SendError):
+ pass
+
+class Sender:
"""
Sends outgoing messages.
@@ -559,32 +509,50 @@ class Sender(Lockable):
self.session = session
self.index = index
self.target = target
+ self.capacity = UNLIMITED
+ self.queued = Serial(0)
+ self.acked = Serial(0)
self.closed = False
self._lock = self.session._lock
- self._condition = self.session._condition
- def wakeup(self):
- self.session.wakeup()
+ def _wakeup(self):
+ self.session._wakeup()
- def catchup(self, exc=SendError):
- self.session.catchup(exc)
+ def _check_error(self, exc=SendError):
+ self.session._check_error(exc)
- def check_error(self, exc=SendError):
- self.session.check_error(exc)
+ def _ewait(self, predicate, timeout=None, exc=SendError):
+ return self.session._ewait(predicate, timeout, exc)
- def ewait(self, predicate, timeout=None, exc=SendError):
- return self.session.ewait(predicate, timeout, exc)
+ @synchronized
+ def pending(self):
+ """
+ Returns the number of messages awaiting acknowledgment.
+ @rtype: int
+ @return: the number of unacknowledged messages
+ """
+ return self.queued - self.acked
@synchronized
- def send(self, object):
+ def send(self, object, sync=True, timeout=None):
"""
Send a message. If the object passed in is of type L{unicode},
L{str}, L{list}, or L{dict}, it will automatically be wrapped in a
L{Message} and sent. If it is of type L{Message}, it will be sent
- directly.
+ directly. If the sender capacity is not L{UNLIMITED} then send
+ will block until there is available capacity to send the message.
+ If the timeout parameter is specified, then send will throw an
+ L{InsufficientCapacity} exception if capacity does not become
+ available within the specified time.
@type object: unicode, str, list, dict, Message
@param object: the message or content to send
+
+ @type sync: boolean
+ @param sync: if true then block until the message is sent
+
+ @type timeout: float
+ @param timeout: the time to wait for available capacity
"""
if not self.session.connection._connected or self.session.closing:
@@ -595,12 +563,23 @@ class Sender(Lockable):
else:
message = Message(object)
+ if self.capacity is not UNLIMITED:
+ if self.capacity <= 0:
+ raise InsufficientCapacity("capacity = %s" % self.capacity)
+ if not self._ewait(lambda: self.pending() < self.capacity, timeout=timeout):
+ raise InsufficientCapacity("capacity = %s" % self.capacity)
+
# XXX: what if we send the same message to multiple senders?
message._sender = self
self.session.outgoing.append(message)
+ self.queued += 1
+ mno = self.queued
+
+ self._wakeup()
- self.wakeup()
- self.ewait(lambda: message not in self.session.outgoing)
+ if sync:
+ self._ewait(lambda: self.acked >= mno)
+ assert message not in self.session.outgoing
@synchronized
def close(self):
@@ -622,7 +601,7 @@ class Empty(ReceiveError):
"""
pass
-class Receiver(Lockable):
+class Receiver:
"""
Receives incoming messages from a remote source. Messages may be
@@ -649,22 +628,25 @@ class Receiver(Lockable):
self.closed = False
self.listener = None
self._lock = self.session._lock
- self._condition = self.session._condition
- def wakeup(self):
- self.session.wakeup()
+ def _wakeup(self):
+ self.session._wakeup()
- def catchup(self, exc=ReceiveError):
- self.session.catchup()
+ def _check_error(self, exc=ReceiveError):
+ self.session._check_error(exc)
- def check_error(self, exc=ReceiveError):
- self.session.check_error(exc)
-
- def ewait(self, predicate, timeout=None, exc=ReceiveError):
- return self.session.ewait(predicate, timeout, exc)
+ def _ewait(self, predicate, timeout=None, exc=ReceiveError):
+ return self.session._ewait(predicate, timeout, exc)
@synchronized
def pending(self):
+ """
+ Returns the number of messages available to be fetched by the
+ application.
+
+ @rtype: int
+ @return: the number of available messages
+ """
return self.received - self.returned
def _capacity(self):
@@ -700,23 +682,23 @@ class Receiver(Lockable):
"""
if self._capacity() == 0:
self.granted = self.returned + 1
- self.wakeup()
- self.ewait(lambda: self.impending == self.granted)
+ self._wakeup()
+ self._ewait(lambda: self.impending >= self.granted)
msg = self.session._get(self._pred, timeout=timeout)
if msg is None:
self.drain = True
self.granted = self.received
- self.wakeup()
- self.ewait(lambda: self.impending == self.received)
+ self._wakeup()
+ self._ewait(lambda: self.impending == self.received)
self.drain = False
self._grant()
- self.wakeup()
+ self._wakeup()
msg = self.session._get(self._pred, timeout=0)
if msg is None:
raise Empty()
elif self._capacity() not in (0, UNLIMITED.value):
self.granted += 1
- self.wakeup()
+ self._wakeup()
return msg
def _grant(self):
@@ -736,7 +718,7 @@ class Receiver(Lockable):
"""
self.started = True
self._grant()
- self.wakeup()
+ self._wakeup()
@synchronized
def stop(self):
@@ -745,8 +727,8 @@ class Receiver(Lockable):
"""
self.started = False
self._grant()
- self.wakeup()
- self.ewait(lambda: self.impending == self.received)
+ self._wakeup()
+ self._ewait(lambda: self.impending == self.received)
@synchronized
def close(self):
@@ -754,9 +736,9 @@ class Receiver(Lockable):
Close the receiver.
"""
self.closing = True
- self.wakeup()
+ self._wakeup()
try:
- self.ewait(lambda: self.closed)
+ self._ewait(lambda: self.closed)
finally:
self.session.receivers.remove(self)
@@ -843,391 +825,7 @@ class Message:
def __repr__(self):
return "Message(%r)" % self.content
-class Attachment:
-
- def __init__(self, target):
- self.target = target
-
-DURABLE_DEFAULT=True
-
-class Driver(Lockable):
-
- def __init__(self, connection):
- self.connection = connection
- self._lock = self.connection._lock
- self._condition = self.connection._condition
- self._wakeup_cond = Condition()
- self._socket = None
- self._conn = None
- self._connected = False
- self._attachments = {}
- self._modcount = self.connection._modcount
- self.thread = Thread(target=self.run)
- self.thread.setDaemon(True)
- # XXX: need to figure out how to join on this thread
-
- def start(self):
- self.thread.start()
-
- def wakeup(self):
- self._wakeup_cond.acquire()
- try:
- self._wakeup_cond.notifyAll()
- finally:
- self._wakeup_cond.release()
-
- def start(self):
- self.thread.start()
-
- def run(self):
- while True:
- self._wakeup_cond.acquire()
- try:
- if self.connection._modcount <= self._modcount:
- self._wakeup_cond.wait(10)
- finally:
- self._wakeup_cond.release()
- self.dispatch(self.connection._modcount)
-
- @synchronized
- def dispatch(self, modcount):
- try:
- if self._conn is None and self.connection._connected:
- self.connect()
- elif self._conn is not None and not self.connection._connected:
- self.disconnect()
-
- if self._conn is not None:
- for ssn in self.connection.sessions.values():
- self.attach(ssn)
- self.process(ssn)
-
- exi = None
- except:
- exi = sys.exc_info()
-
- if exi:
- msg = compat.format_exc()
- recoverable = ["aborted", "Connection refused", "SessionDetached", "Connection reset by peer",
- "Bad file descriptor", "start timed out", "Broken pipe"]
- for r in recoverable:
- if self.connection.reconnect and r in msg:
- print "waiting to retry"
- self.reset()
- time.sleep(3)
- print "retrying..."
- return
- else:
- self.connection.error = (msg,)
-
- self._modcount = modcount
- self.notifyAll()
-
- def connect(self):
- if self._conn is not None:
- return
- try:
- self._socket = connect(self.connection.host, self.connection.port)
- except socket.error, e:
- raise ConnectError(e)
- self._conn = connection.Connection(self._socket)
- try:
- self._conn.start(timeout=10)
- self._connected = True
- except connection.VersionError, e:
- raise ConnectError(e)
- except Timeout:
- print "start timed out"
- raise ConnectError("start timed out")
-
- def disconnect(self):
- self._conn.close()
- self.reset()
-
- def reset(self):
- self._conn = None
- self._connected = False
- self._attachments.clear()
- for ssn in self.connection.sessions.values():
- for m in ssn.acked + ssn.unacked + ssn.incoming:
- m._transfer_id = None
- for rcv in ssn.receivers:
- rcv.impending = rcv.received
-
- def connected(self):
- return self._conn is not None
-
- def attach(self, ssn):
- _ssn = self._attachments.get(ssn)
- if _ssn is None:
- _ssn = self._conn.session(ssn.name, delegate=delegate(self, ssn))
- _ssn.auto_sync = False
- _ssn.invoke_lock = self._lock
- _ssn.lock = self._lock
- _ssn.condition = self._condition
- if ssn.transactional:
- # XXX: adding an attribute to qpid.session.Session
- _ssn.acked = []
- _ssn.tx_select()
- self._attachments[ssn] = _ssn
-
- for snd in ssn.senders:
- self.link_out(snd)
- for rcv in ssn.receivers:
- self.link_in(rcv)
-
- if ssn.closing:
- _ssn.close()
- del self._attachments[ssn]
-
- def _exchange_query(self, ssn, address):
- # XXX: auto sync hack is to avoid deadlock on future
- result = ssn.exchange_query(name=address, sync=True)
- ssn.sync()
- return result.get()
-
- def link_out(self, snd):
- _ssn = self._attachments[snd.session]
- _snd = self._attachments.get(snd)
- if _snd is None:
- _snd = Attachment(snd)
- node, _snd._subject = parse_addr(snd.target)
- result = self._exchange_query(_ssn, node)
- if result.not_found:
- # XXX: should check 'create' option
- _ssn.queue_declare(queue=node, durable=DURABLE_DEFAULT, sync=True)
- _ssn.sync()
- _snd._exchange = ""
- _snd._routing_key = node
- else:
- _snd._exchange = node
- _snd._routing_key = _snd._subject
- self._attachments[snd] = _snd
-
- if snd.closed:
- del self._attachments[snd]
- return None
- else:
- return _snd
-
- def link_in(self, rcv):
- _ssn = self._attachments[rcv.session]
- _rcv = self._attachments.get(rcv)
- if _rcv is None:
- _rcv = Attachment(rcv)
- result = self._exchange_query(_ssn, rcv.source)
- if result.not_found:
- _rcv._queue = rcv.source
- # XXX: should check 'create' option
- _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT)
- else:
- _rcv._queue = "%s.%s" % (rcv.session.name, rcv.destination)
- _ssn.queue_declare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True)
- if rcv.filter is None:
- f = FILTER_DEFAULTS[result.type]
- else:
- f = rcv.filter
- f._bind(_ssn, rcv.source, _rcv._queue)
- _ssn.message_subscribe(queue=_rcv._queue, destination=rcv.destination)
- _ssn.message_set_flow_mode(rcv.destination, _ssn.flow_mode.credit, sync=True)
- self._attachments[rcv] = _rcv
- # XXX: need to kill syncs
- _ssn.sync()
-
- if rcv.closing:
- _ssn.message_cancel(rcv.destination, sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- del self._attachments[rcv]
- rcv.closed = True
- return None
- else:
- return _rcv
-
- def process(self, ssn):
- if ssn.closing: return
-
- _ssn = self._attachments[ssn]
-
- while ssn.outgoing:
- msg = ssn.outgoing[0]
- snd = msg._sender
- self.send(snd, msg)
- ssn.outgoing.pop(0)
-
- for rcv in ssn.receivers:
- self.process_receiver(rcv)
-
- if ssn.acked:
- messages = ssn.acked[:]
- ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
- for range in ids:
- _ssn.receiver._completed.add_range(range)
- ch = _ssn.channel
- if ch is None:
- raise SessionDetached()
- ch.session_completed(_ssn.receiver._completed)
- _ssn.message_accept(ids, sync=True)
- # XXX: really need to make this async so that we don't give up the lock
- _ssn.sync()
-
- for m in messages:
- ssn.acked.remove(m)
- if ssn.transactional:
- _ssn.acked.append(m)
-
- if ssn.committing:
- _ssn.tx_commit(sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- del _ssn.acked[:]
- ssn.committing = False
- ssn.committed = True
- ssn.aborting = False
- ssn.aborted = False
-
- if ssn.aborting:
- for rcv in ssn.receivers:
- _ssn.message_stop(rcv.destination)
- _ssn.sync()
-
- messages = _ssn.acked + ssn.unacked + ssn.incoming
- ids = RangedSet(*[m._transfer_id for m in messages])
- for range in ids:
- _ssn.receiver._completed.add_range(range)
- _ssn.channel.session_completed(_ssn.receiver._completed)
- _ssn.message_release(ids)
- _ssn.tx_rollback(sync=True)
- _ssn.sync()
-
- del ssn.incoming[:]
- del ssn.unacked[:]
- del _ssn.acked[:]
-
- for rcv in ssn.receivers:
- rcv.impending = rcv.received
- rcv.returned = rcv.received
- # XXX: do we need to update granted here as well?
-
- for rcv in ssn.receivers:
- self.process_receiver(rcv)
-
- ssn.aborting = False
- ssn.aborted = True
- ssn.committing = False
- ssn.committed = False
-
- def grant(self, rcv):
- _ssn = self._attachments[rcv.session]
- _rcv = self.link_in(rcv)
-
- if rcv.granted is UNLIMITED:
- if rcv.impending is UNLIMITED:
- delta = 0
- else:
- delta = UNLIMITED
- elif rcv.impending is UNLIMITED:
- delta = -1
- else:
- delta = max(rcv.granted, rcv.received) - rcv.impending
-
- if delta is UNLIMITED:
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, UNLIMITED.value)
- rcv.impending = UNLIMITED
- elif delta > 0:
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.byte, UNLIMITED.value)
- _ssn.message_flow(rcv.destination, _ssn.credit_unit.message, delta)
- rcv.impending += delta
- elif delta < 0:
- if rcv.drain:
- _ssn.message_flush(rcv.destination, sync=True)
- else:
- _ssn.message_stop(rcv.destination, sync=True)
- # XXX: need to kill syncs
- _ssn.sync()
- rcv.impending = rcv.received
- self.grant(rcv)
-
- def process_receiver(self, rcv):
- if rcv.closed: return
- self.grant(rcv)
-
- def send(self, snd, msg):
- _ssn = self._attachments[snd.session]
- _snd = self.link_out(snd)
-
- # XXX: what if subject is specified for a normal queue?
- if _snd._routing_key is None:
- rk = msg.subject
- else:
- rk = _snd._routing_key
- # XXX: do we need to query to figure out how to create the reply-to interoperably?
- if msg.reply_to:
- rt = _ssn.reply_to(*parse_addr(msg.reply_to))
- else:
- rt = None
- dp = _ssn.delivery_properties(routing_key=rk)
- mp = _ssn.message_properties(message_id=msg.id,
- user_id=msg.user_id,
- reply_to=rt,
- correlation_id=msg.correlation_id,
- content_type=msg.content_type,
- application_headers=msg.properties)
- if msg.subject is not None:
- if mp.application_headers is None:
- mp.application_headers = {}
- mp.application_headers["subject"] = msg.subject
- if msg.to is not None:
- if mp.application_headers is None:
- mp.application_headers = {}
- mp.application_headers["to"] = msg.to
- if msg.durable:
- dp.delivery_mode = delivery_mode.persistent
- enc, dec = get_codec(msg.content_type)
- body = enc(msg.content)
- _ssn.message_transfer(destination=_snd._exchange,
- message=Message010(dp, mp, body),
- sync=True)
- log.debug("SENT [%s] %s", snd.session, msg)
- # XXX: really need to make this async so that we don't give up the lock
- _ssn.sync()
- # XXX: should we log the ack somehow too?
-
- @synchronized
- def _message_transfer(self, ssn, cmd):
- m = Message010(cmd.payload)
- m.headers = cmd.headers
- m.id = cmd.id
- msg = self._decode(m)
- rcv = ssn.receivers[int(cmd.destination)]
- msg._receiver = rcv
- rcv.received += 1
- log.debug("RECV [%s] %s", ssn, msg)
- ssn.incoming.append(msg)
- self.notifyAll()
- return INCOMPLETE
-
- def _decode(self, message):
- dp = message.get("delivery_properties")
- mp = message.get("message_properties")
- ap = mp.application_headers
- enc, dec = get_codec(mp.content_type)
- content = dec(message.body)
- msg = Message(content)
- msg.id = mp.message_id
- if ap is not None:
- msg.to = ap.get("to")
- msg.subject = ap.get("subject")
- msg.user_id = mp.user_id
- 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
- msg.properties = mp.application_headers
- msg.content_type = mp.content_type
- msg._transfer_id = message.id
- return msg
-
-__all__ = ["Connection", "Pattern", "Session", "Sender", "Receiver", "Message",
- "Empty", "timestamp", "uuid4"]
+__all__ = ["Connection", "Session", "Sender", "Receiver", "Pattern", "Message",
+ "ConnectionError", "ConnectError", "SessionError", "Disconnected",
+ "SendError", "InsufficientCapacity", "ReceiveError", "Empty",
+ "timestamp", "uuid4", "UNLIMITED", "AMQP_PORT", "AMQPS_PORT"]
diff --git a/qpid/python/qpid/ops.py b/qpid/python/qpid/ops.py
index 447f9953df..11e7d11fe9 100644
--- a/qpid/python/qpid/ops.py
+++ b/qpid/python/qpid/ops.py
@@ -74,10 +74,7 @@ class Compound(object):
def dispatch(self, target, *args):
handler = "do_%s" % self.NAME
- if hasattr(target, handler):
- getattr(target, handler)(self, *args)
- else:
- print "UNHANDLED:", target, args
+ getattr(target, handler)(self, *args)
def __repr__(self, extras=()):
return "%s(%s)" % (self.__class__.__name__,
diff --git a/qpid/python/qpid/tests/messaging.py b/qpid/python/qpid/tests/messaging.py
index 6062895519..7623c1f93b 100644
--- a/qpid/python/qpid/tests/messaging.py
+++ b/qpid/python/qpid/tests/messaging.py
@@ -23,7 +23,8 @@
import time
from qpid.tests import Test
from qpid.harness import Skipped
-from qpid.messaging import Connection, ConnectError, Disconnected, Empty, Message, UNLIMITED, uuid4
+from qpid.messaging import Connection, ConnectError, Disconnected, Empty, \
+ InsufficientCapacity, Message, UNLIMITED, uuid4
from Queue import Queue, Empty as QueueEmpty
class Base(Test):
@@ -71,13 +72,15 @@ class Base(Test):
ssn.acknowledge()
assert msg.content == content, "expected %r, got %r" % (content, msg.content)
- def drain(self, rcv, limit=None):
+ def drain(self, rcv, limit=None, timeout=0, expected=None):
contents = []
try:
while limit is None or len(contents) < limit:
- contents.append(rcv.fetch(0).content)
+ contents.append(rcv.fetch(timeout=timeout).content)
except Empty:
pass
+ if expected is not None:
+ assert expected == contents, "expected %s, got %s" % (expected, contents)
return contents
def assertEmpty(self, rcv):
@@ -224,27 +227,27 @@ class SessionTests(Base):
# XXX, we need a convenient way to assert that required queues are
# empty on setup, and possibly also to drain queues on teardown
- def testAcknowledge(self):
+ def ackTest(self, acker, ack_capacity=None):
# send a bunch of messages
snd = self.ssn.sender("test-ack-queue")
- tid = "a"
- contents = ["testAcknowledge[%s, %s]" % (i, tid) for i in range(10)]
+ contents = [self.content("ackTest", i) for i in range(15)]
for c in contents:
snd.send(c)
# drain the queue, verify the messages are there and then close
# without acking
rcv = self.ssn.receiver(snd.target)
- assert contents == self.drain(rcv)
+ self.drain(rcv, expected=contents)
self.ssn.close()
# drain the queue again, verify that they are all the messages
# were requeued, and ack this time before closing
self.ssn = self.conn.session()
+ if ack_capacity is not None:
+ self.ssn.ack_capacity = ack_capacity
rcv = self.ssn.receiver("test-ack-queue")
- drained = self.drain(rcv)
- assert contents == drained, "expected %s, got %s" % (contents, drained)
- self.ssn.acknowledge()
+ self.drain(rcv, expected=contents)
+ acker(self.ssn)
self.ssn.close()
# drain the queue a final time and verify that the messages were
@@ -253,6 +256,33 @@ class SessionTests(Base):
rcv = self.ssn.receiver("test-ack-queue")
self.assertEmpty(rcv)
+ def testAcknowledge(self):
+ self.ackTest(lambda ssn: ssn.acknowledge())
+
+ def testAcknowledgeAsync(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False))
+
+ def testAcknowledgeAsyncAckCap0(self):
+ try:
+ try:
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 0)
+ assert False, "acknowledge shouldn't succeed with ack_capacity of zero"
+ except InsufficientCapacity:
+ pass
+ finally:
+ self.ssn.ack_capacity = UNLIMITED
+ self.drain(self.ssn.receiver("test-ack-queue"))
+ self.ssn.acknowledge()
+
+ def testAcknowledgeAsyncAckCap1(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 1)
+
+ def testAcknowledgeAsyncAckCap5(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 5)
+
+ def testAcknowledgeAsyncAckCapUNLIMITED(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), UNLIMITED)
+
def send(self, ssn, queue, base, count=1):
snd = ssn.sender(queue)
contents = []
@@ -543,6 +573,48 @@ class SenderTests(Base):
def testSendMap(self):
self.checkContent({"testSendMap": self.test_id, "pie": "blueberry", "pi": 3.14})
+ def asyncTest(self, capacity):
+ self.snd.capacity = capacity
+ 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.ssn.acknowledge()
+
+ def testSendAsyncCapacity0(self):
+ try:
+ self.asyncTest(0)
+ assert False, "send shouldn't succeed with zero capacity"
+ except InsufficientCapacity:
+ # this is expected
+ pass
+
+ def testSendAsyncCapacity1(self):
+ self.asyncTest(1)
+
+ def testSendAsyncCapacity5(self):
+ self.asyncTest(5)
+
+ def testSendAsyncCapacityUNLIMITED(self):
+ self.asyncTest(UNLIMITED)
+
+ def testCapacityTimeout(self):
+ self.snd.capacity = 1
+ msgs = []
+ caught = False
+ while len(msgs) < 100:
+ m = self.content("testCapacity", len(msgs))
+ try:
+ self.snd.send(m, sync=False, timeout=0)
+ msgs.append(m)
+ except InsufficientCapacity:
+ caught = True
+ break
+ self.drain(self.rcv, expected=msgs)
+ self.ssn.acknowledge()
+ assert caught, "did not exceed capacity"
+
class MessageTests(Base):
def testCreateString(self):
diff --git a/qpid/python/qpid/util.py b/qpid/python/qpid/util.py
index c46716b88f..3409d777f9 100644
--- a/qpid/python/qpid/util.py
+++ b/qpid/python/qpid/util.py
@@ -134,3 +134,9 @@ class URL:
if self.port:
s += ":%s" % self.port
return s
+
+def default(value, default):
+ if value is None:
+ return default
+ else:
+ return value
diff --git a/qpid/python/tests/datatypes.py b/qpid/python/tests/datatypes.py
index b00e5e78f8..00e649d6cf 100644
--- a/qpid/python/tests/datatypes.py
+++ b/qpid/python/tests/datatypes.py
@@ -148,6 +148,34 @@ class RangedSetTest(TestCase):
assert range.lower == 0
assert range.upper == 8
+ def testEmpty(self):
+ s = RangedSet()
+ assert s.empty()
+ s.add(0, -1)
+ assert s.empty()
+ s.add(0, 0)
+ assert not s.empty()
+
+ def testMinMax(self):
+ s = RangedSet()
+ assert s.max() is None
+ assert s.min() is None
+ s.add(0, 10)
+ assert s.max() == 10
+ assert s.min() == 0
+ s.add(0, 5)
+ assert s.max() == 10
+ assert s.min() == 0
+ s.add(0, 11)
+ assert s.max() == 11
+ assert s.min() == 0
+ s.add(15, 20)
+ assert s.max() == 20
+ assert s.min() == 0
+ s.add(-10, -5)
+ assert s.max() == 20
+ assert s.min() == -10
+
class RangeTest(TestCase):
def testIntersect1(self):
diff --git a/qpid/python/tests_0-10/alternate_exchange.py b/qpid/python/tests_0-10/alternate_exchange.py
index 3b75145907..4d8617eb8e 100644
--- a/qpid/python/tests_0-10/alternate_exchange.py
+++ b/qpid/python/tests_0-10/alternate_exchange.py
@@ -141,7 +141,61 @@ class AlternateExchangeTests(TestBase010):
session.exchange_delete(exchange="e")
session.exchange_delete(exchange="alternate")
self.assertEquals(530, e.args[0].error_code)
-
+
+
+ def test_modify_existing_exchange_alternate(self):
+ """
+ Ensure that attempting to modify an exhange to change
+ the alternate throws an exception
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="alt2", type="direct")
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt1")
+ try:
+ # attempt to change the alternate on an already existing exchange
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt2")
+ self.fail("Expected changing an alternate on an existing exchange to fail")
+ except SessionException, e:
+ self.assertEquals(530, e.args[0].error_code)
+ session = self.conn.session("alternate", 2)
+ session.exchange_delete(exchange="onealternate")
+ session.exchange_delete(exchange="alt2")
+ session.exchange_delete(exchange="alt1")
+
+
+ def test_add_alternate_to_exchange(self):
+ """
+ Ensure that attempting to modify an exhange by adding
+ an alternate throws an exception
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="noalternate", type="fanout")
+ try:
+ # attempt to add an alternate on an already existing exchange
+ session.exchange_declare(exchange="noalternate", type="fanout", alternate_exchange="alt1")
+ self.fail("Expected adding an alternate on an existing exchange to fail")
+ except SessionException, e:
+ self.assertEquals(530, e.args[0].error_code)
+ session = self.conn.session("alternate", 2)
+ session.exchange_delete(exchange="noalternate")
+ session.exchange_delete(exchange="alt1")
+
+
+ def test_del_alternate_to_exchange(self):
+ """
+ Ensure that attempting to modify an exhange by declaring
+ it again without an alternate does nothing
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt1")
+ # attempt to re-declare without an alternate - silently ignore
+ session.exchange_declare(exchange="onealternate", type="fanout" )
+ session.exchange_delete(exchange="onealternate")
+ session.exchange_delete(exchange="alt1")
+
def assertEmpty(self, queue):
try:
diff --git a/qpid/python/tests_0-10/management.py b/qpid/python/tests_0-10/management.py
index 51c2a687cb..53573f309e 100644
--- a/qpid/python/tests_0-10/management.py
+++ b/qpid/python/tests_0-10/management.py
@@ -295,3 +295,25 @@ class ManagementTest (TestBase010):
sleep(1)
self.assertEqual(handler.check(), "pass")
+ def test_connection_close(self):
+ """
+ Test management method for closing connection
+ """
+ self.startQmf()
+ conn = self.connect()
+ session = conn.session("my-named-session")
+
+ #using qmf find named session and close the corresponding connection:
+ qmf_ssn_object = self.qmf.getObjects(_class="session", name="my-named-session")[0]
+ qmf_ssn_object._connectionRef_.close()
+
+ #check that connection is closed
+ try:
+ conn.session("another-session")
+ self.fail("Expected failure from closed connection")
+ except: None
+
+ #make sure that the named session has been closed and the name can be re-used
+ conn = self.connect()
+ session = conn.session("my-named-session")
+ session.queue_declare(queue="whatever", exclusive=True, auto_delete=True)
diff --git a/qpid/specs/management-schema.xml b/qpid/specs/management-schema.xml
index e72ba1cdd7..c25aca67ed 100644
--- a/qpid/specs/management-schema.xml
+++ b/qpid/specs/management-schema.xml
@@ -169,7 +169,7 @@
<property name="type" type="sstr" access="RO"/>
<property name="durable" type="bool" access="RO"/>
<property name="autoDelete" type="bool" access="RO"/>
- <property name="altExchange" type="objId" access="RO" optional="y"/>
+ <property name="altExchange" type="objId" references="Exchange" access="RO" optional="y"/>
<property name="arguments" type="map" access="RO" desc="Arguments supplied in exchange.declare"/>
<statistic name="producerCount" type="hilo32" desc="Current producers on exchange"/>
diff --git a/qpid/wcf/QpidWcf.sln b/qpid/wcf/QpidWcf.sln
new file mode 100644
index 0000000000..54d8dd7b0b
--- /dev/null
+++ b/qpid/wcf/QpidWcf.sln
@@ -0,0 +1,114 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AmqpTypes", "src\Apache\Qpid\AmqpTypes\AmqpTypes.csproj", "{820BFC34-A40F-46BA-B86B-05334854CA17}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Interop", "src\Apache\Qpid\Interop\Interop.vcproj", "{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}"
+ ProjectSection(ProjectDependencies) = postProject
+ {820BFC34-A40F-46BA-B86B-05334854CA17} = {820BFC34-A40F-46BA-B86B-05334854CA17}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "test\Apache\Qpid\Test\Channel\Functional\FunctionalTests.csproj", "{E2D8C779-E417-40BA-BEE1-EE034268482F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channel", "src\Apache\Qpid\Channel\Channel.csproj", "{8AABAB30-7D1E-4539-B7D1-05450262BAD2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Any CPU.Build.0 = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Win32.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|x64.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|x86.ActiveCfg = Release|Any CPU
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Any CPU.Build.0 = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Win32.Build.0 = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|x64.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|x86.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Any CPU.ActiveCfg = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Win32.ActiveCfg = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Win32.Build.0 = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|x64.ActiveCfg = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|x86.ActiveCfg = Release|Win32
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x64.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x86.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x64.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x64.Build.0 = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x86.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x86.Build.0 = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Win32.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|x64.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/qpid/wcf/ReadMe.txt b/qpid/wcf/ReadMe.txt
new file mode 100644
index 0000000000..0ef3e06ce5
--- /dev/null
+++ b/qpid/wcf/ReadMe.txt
@@ -0,0 +1,162 @@
+1. WCF supported features
+=========================
+
+1. WCF service model programming using one way contracts
+2. WCF channel model programming using IInputChannel and IOutputChannel based factories
+3. Programmatic access to AMQP message properties on WCF messages
+4. AMQP version 0-10 (as provided by the Qpid C++ native client library)
+5. Shared connections for multiple channels based on binding parameters
+6. WCF to WCF applications (using SOAP message encoders)
+7. WCF to non-WCF applications (using raw content encoders)
+8. Rudimentary AMQP type support for headers (Int and String)
+9. Channel functional tests using NUnit
+10. Programming samples
+
+
+2. Planned features (not yet available)
+=======================================
+
+1. Full AMQP type support, including maps and arrays
+2. System.Transactions integration (local and distributed with dynamic escalation)
+3. Prefetch window for inbound messages
+4. Shared sessions
+5. Connection failover with AMQP broker clusters
+6. Temporary queues
+7. Broker management
+8. System logging and tracing
+9. CMake build system support
+10. Transport and message based security
+
+
+3. Prerequisites
+================
+
+1. Qpid C++ client and common libraries for Windows including BOOST
+Ensure the location of the Boost library (e.g. %BOOST_ROOT%\lib) is
+included in your PATH environment variable.
+
+2. .NET Framework 3.5 SP1
+Install the .NET Framework from http://www.microsoft.com/net/
+
+3. Windows SDK
+Install the Windows SDK for the version of Windows that you are using
+from http://msdn.microsoft.com/en-us/windows/bb980924.aspx
+
+4. NUnit
+Install NUnit from http://www.nunit.org
+
+NOTE: In the following instructions %QPID_ROOT% refers to the root of
+qpid source code location e.g. C:\trunk\qpid
+
+5. Build Qpid cpp
+Run CMake and choose "%QPID_ROOT%\cpp\build" as the location for "Where to
+build the binaries". Build at least the "qpidd", "qpidclient" and
+"qpidcommon" projects.
+
+
+4. Building the solution file
+=============================
+
+Option 1: Using MSBuild
+
+1. %systemroot%\Microsoft.NET\Framework\v3.5\MSBuild.exe %QPID_ROOT%\wcf\QpidWcf.sln
+2. %systemroot%\Microsoft.NET\Framework\v3.5\MSBuild.exe %QPID_ROOT%\wcf\tools\QCreate\QCreate.sln
+
+
+Option 2: Using Visual Studio 2008 (the Professional Edition, Team
+System Development Edition, or Team System Team Suite SKU)
+
+1. Open the solution file QpidWcf.sln in Visual Studio.
+2. Make sure that the reference to 'nunit.framework.dll' by the 'FunctionalTests'
+ project is appropriately resolved.
+3. Select the Debug configuration.
+3. Right-click the solution file in the Solution Explorer and select 'Build Solution'.
+4. Follow the above steps to build %QPID_ROOT%\wcf\tools\QCreate.sln as well.
+
+
+5. Executing tests
+==================
+
+1. Make sure that the batch file
+ %QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional\RunTests.bat has the correct
+ values for the nunit_exe, qpid_dll_location and configuration_name variables as per
+ your installation.
+2. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+3. Execute RunTests.bat from its location e.g. %QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional.
+
+
+6. Building and executing samples
+=================================
+
+WCFToWCFDirect
+
+1. Copy the dlls Apache.Qpid.Channel.dll and Apache.Qpid.Interop.dll that you built
+ in step 2 to the %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect folder.
+
+2. Build the solution WCFToWCFDirect.sln.
+
+3. Copy qpidclient.dll and qpidcommon.dll from the Qpid build folder
+ e.g. %QPID_ROOT%\cpp\build\src\Debug to the same location as the exe files
+ e.g. bin\Debug of each of the projects. These dlls are needed at runtime.
+
+4. Copy qpidclient.dll and qpidcommon.dll to %QPID_ROOT%\wcf\tools\QCreate\Debug folder.
+
+5. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+
+6. Create queue required using the QCreate tool located at
+ %QPID_ROOT%\wcf\tools\QCreate\Debug. The syntax is QCreate %QPID_ROOT%. For
+ this sample you should do
+
+ QCreate amq.direct routing_key message_queue
+
+7. Start Service.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect\Service\bin\Debug.
+
+8. Start Client.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect\Client\bin\Debug.
+
+
+WCFToWCFPubSub
+
+1. Copy the dlls Apache.Qpid.Channel.dll and Apache.Qpid.Interop.dll that you built
+ in step 2 to the %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub folder.
+
+2. Build the solution WCFToWCFPubSub.sln.
+
+3. Copy qpidclient.dll and qpidcommon.dll from the Qpid build folder
+ e.g. %QPID_ROOT%\cpp\build\src\Debug to the same location as the exe files
+ e.g. bin\Debug of each of the projects. These dlls are needed at runtime.
+
+4. Copy qpidclient.dll and qpidcommon.dll to %QPID_ROOT%\wcf\tools\QCreate\Debug folder.
+
+5. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+
+6. Create queues required using the QCreate tool located at
+ \wcf\tools\QCreate\Debug. The syntax is QCreate %QPID_ROOT%. For this sample you
+ should do
+
+ QCreate amq.topic usa.# usa
+ QCreate amq.topic #.news news
+
+7. Start Topic_Consumer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Topic_Consumer\bin\Debug.
+
+8. Start Another_Topic_Consumer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Another_Topic_Consumer\bin\Debug.
+
+9. Start Topic_Producer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Topic_Producer\bin\Debug.
+
+
+7. Known Issues
+===============
+
+1. The Release configuration of the build (specified using the
+ /p:Configuration=Release switch with MSBuild) fails.
+
+2. The AmqpChannelListener is limited to single threaded use and the async methods
+ throw NotImplementedException.
+
+3. The AmqpChannelListener can hang on close for 60 seconds.
+
+
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs
new file mode 100644
index 0000000000..93ac97bc66
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Samples.Channel.WCFToWCFDirect
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ class Client
+ {
+ static void Main(string[] args)
+ {
+ try
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create endpoint address.
+ Uri amqpClientUri = new Uri("amqp:amq.direct?routingkey=routing_key");
+ EndpointAddress endpointAddress = new EndpointAddress(amqpClientUri);
+
+ // Create a client with given client endpoint configuration.
+ ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(amqpBinding, endpointAddress);
+ IHelloService clientProxy = channelFactory.CreateChannel();
+
+ Console.WriteLine();
+
+ string name = "name";
+ for (int i = 0; i < 5; i++)
+ {
+ Console.WriteLine("Sending message: " + name + (i + 1));
+ clientProxy.SayHello(name + (i + 1));
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Press <ENTER> to terminate client.");
+ Console.ReadLine();
+
+ channelFactory.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Exception: {0}", e);
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj
new file mode 100644
index 0000000000..7e1d2d9f5d
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{0CCD5711-2072-47B8-B902-07EC12C04159}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Client</RootNamespace>
+ <AssemblyName>Client</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Client.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Service\Service.csproj">
+ <Project>{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}</Project>
+ <Name>Service</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..414a3b5858
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Client")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c3743ce0-3054-4188-8cd7-3a22734ee313")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..2b75210ce3
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Service")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Service")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5447546e-8547-4b0c-981a-1757ab8d9ec5")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs
new file mode 100644
index 0000000000..0342097ed9
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs
@@ -0,0 +1,83 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Samples.Channel.WCFToWCFDirect
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ // Define a service contract.
+ [ServiceContract]
+ public interface IHelloService
+ {
+ [OperationContract(IsOneWay = true, Action="*")]
+ void SayHello(string name);
+ }
+
+ // Service class which implements the service contract.
+ [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
+ public class HelloService : IHelloService
+ {
+ [OperationBehavior]
+ public void SayHello(string name)
+ {
+ Console.WriteLine("Hello " + name);
+ }
+ }
+
+ class Service
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ AmqpBinding amqpBinding = new AmqpBinding();
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:message_queue");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The service is ready.");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj
new file mode 100644
index 0000000000..3252380c98
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Service</RootNamespace>
+ <AssemblyName>Service</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Messaging" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Service.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln b/qpid/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln
new file mode 100644
index 0000000000..6f30a5e053
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{0CCD5711-2072-47B8-B902-07EC12C04159}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Service", "Service\Service.csproj", "{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs
new file mode 100644
index 0000000000..c1e3ebbc88
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs
@@ -0,0 +1,67 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ class Another_Topic_Consumer
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService2") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:news");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The consumer is now listening on the queue \"news\".");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj
new file mode 100644
index 0000000000..47769e086d
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Another_Topic_Consumer</RootNamespace>
+ <AssemblyName>Another_Topic_Consumer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Another_Topic_Consumer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Topic_Consumer\Topic_Consumer.csproj">
+ <Project>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</Project>
+ <Name>Topic_Consumer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..8c22cb6d1f
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Another_Topic_Consumer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Another_Topic_Consumer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ba584c88-26a8-4910-a9a1-b4632b9adf01")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..19fea85618
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Topic_Consumer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Topic_Consumer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3facd6d1-f604-4ac9-ace3-7b7acff471eb")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs
new file mode 100644
index 0000000000..c4dd1e2256
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ // Define a service contract.
+ [ServiceContract]
+ public interface IHelloService
+ {
+ [OperationContract(IsOneWay = true)]
+ void SayHello(string name);
+ }
+
+ // Service class which implements the service contract.
+ public class HelloService : IHelloService
+ {
+ [OperationBehavior]
+ public void SayHello(string name)
+ {
+ Console.WriteLine("Hello " + name);
+ }
+ }
+
+ class Consumer
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService1") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:usa");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The consumer is now listening on the queue \"usa\".");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj
new file mode 100644
index 0000000000..b2151c0631
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Topic_Consumer</RootNamespace>
+ <AssemblyName>Topic_Consumer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Topic_Consumer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..87310bf92a
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Topic_Producer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Topic_Producer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a70e852d-a510-4e00-af72-68bb8547696f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs
new file mode 100644
index 0000000000..e3850eb4c0
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ class Topic_Producer
+ {
+ static void Main(string[] args)
+ {
+ try
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create endpoint address.
+ Uri amqpClientUri = new Uri("amqp:amq.topic?routingkey=usa.news");
+ EndpointAddress endpointAddress = new EndpointAddress(amqpClientUri);
+
+ // Create a client with given client endpoint configuration.
+ ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(amqpBinding, endpointAddress);
+ IHelloService clientProxy = channelFactory.CreateChannel();
+
+ Console.WriteLine();
+
+ string name = "name";
+ for (int i = 0; i < 5; i++)
+ {
+ Console.WriteLine("Sending message: " + name + (i + 1));
+ clientProxy.SayHello(name + (i+1));
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Press <ENTER> to terminate client.");
+ Console.ReadLine();
+
+ channelFactory.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Exception: {0}", e);
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj
new file mode 100644
index 0000000000..b4318ead3f
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{67B413EF-3B9C-4988-87DE-0386C209D368}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Topic_Producer</RootNamespace>
+ <AssemblyName>Topic_Producer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Topic_Producer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Topic_Consumer\Topic_Consumer.csproj">
+ <Project>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</Project>
+ <Name>Topic_Consumer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln b/qpid/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln
new file mode 100644
index 0000000000..d8a56ea8db
--- /dev/null
+++ b/qpid/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln
@@ -0,0 +1,52 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Topic_Consumer", "Topic_Consumer\Topic_Consumer.csproj", "{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Topic_Producer", "Topic_Producer\Topic_Producer.csproj", "{67B413EF-3B9C-4988-87DE-0386C209D368}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Another_Topic_Consumer", "Another_Topic_Consumer\Another_Topic_Consumer.csproj", "{6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs
new file mode 100644
index 0000000000..980ae78361
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpBoolean : AmqpType
+ {
+ bool value;
+
+ public AmqpBoolean(bool i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpBoolean(this.value);
+ }
+
+ public bool Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs
new file mode 100644
index 0000000000..c114e98a71
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpInt : AmqpType
+ {
+ int value;
+
+ public AmqpInt(int i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpInt(this.value);
+ }
+
+ public int Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs
new file mode 100644
index 0000000000..0f649dcd36
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs
@@ -0,0 +1,292 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpProperties
+ {
+ // AMQP 0-10 delivery properties
+ private bool durable;
+ private Nullable<TimeSpan> timeToLive;
+ private string routingKey;
+
+ // AMQP 0-10 message properties
+ private string replyToExchange;
+ private string replyToRoutingKey;
+ private byte[] userId;
+ private byte[] correlationId;
+ private string contentType;
+
+ // for application and vendor properties
+ Dictionary<String, AmqpType> propertyMap;
+
+ public AmqpProperties()
+ {
+ }
+
+ // AMQP 0-10 "message.delivery-properties
+ internal bool HasDeliveryProperties
+ {
+ get
+ {
+ return ((this.routingKey != null) || this.durable || this.timeToLive.HasValue);
+ }
+ }
+
+ internal bool HasMappedProperties
+ {
+ get
+ {
+ if (this.propertyMap != null)
+ {
+ if (this.propertyMap.Count > 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ // AMQP 0-10 "message.message-properties"
+ internal bool HasMessageProperties
+ {
+ get
+ {
+ if ((this.replyToExchange != null) ||
+ (this.replyToRoutingKey != null) ||
+ (this.userId != null) ||
+ (this.correlationId != null) ||
+ (this.contentType != null))
+ {
+ return true;
+ }
+
+ if (this.propertyMap == null)
+ {
+ return false;
+ }
+
+ return (this.propertyMap.Count != 0);
+ }
+ }
+
+ public Dictionary<String, AmqpType> PropertyMap
+ {
+ get
+ {
+ if (this.propertyMap == null)
+ {
+ this.propertyMap = new Dictionary<string, AmqpType>();
+ }
+ return propertyMap;
+ }
+ set { this.propertyMap = value; }
+ }
+
+ internal bool Empty
+ {
+ get
+ {
+ if (this.HasDeliveryProperties || this.HasMessageProperties)
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public string ContentType
+ {
+ get { return contentType; }
+ // TODO: validate
+ set { contentType = value; }
+ }
+
+ public byte[] CorrelationId
+ {
+ get { return correlationId; }
+ set
+ {
+ if (value != null)
+ {
+ if (value.Length > 65535)
+ {
+ throw new ArgumentException("CorrelationId too big");
+ }
+ }
+ correlationId = value;
+ }
+ }
+
+ public byte[] UserId
+ {
+ get { return userId; }
+ set
+ {
+ if (value != null)
+ {
+ if (value.Length > 65535)
+ {
+ throw new ArgumentException("UserId too big");
+ }
+ }
+ userId = value;
+ }
+ }
+
+ public TimeSpan? TimeToLive
+ {
+ get { return this.timeToLive; }
+ set { this.timeToLive = value; }
+ }
+
+ public string RoutingKey
+ {
+ get { return this.routingKey; }
+ set { this.routingKey = value; }
+ }
+
+ public string ReplyToExchange
+ {
+ get { return this.replyToExchange; }
+ }
+
+ public string ReplyToRoutingKey
+ {
+ get { return this.replyToRoutingKey; }
+ }
+
+ // this changes from 0-10 to 1.0
+ public void SetReplyTo(string exchange, string routingKey)
+ {
+ if ((exchange == null && routingKey == null))
+ {
+ throw new ArgumentNullException("SetReplyTo");
+ }
+
+ this.replyToExchange = exchange;
+ this.replyToRoutingKey = routingKey;
+ }
+
+ public bool Durable
+ {
+ get { return durable; }
+ set { durable = value; }
+ }
+
+ public void Clear()
+ {
+ this.timeToLive = null;
+ this.routingKey = null;
+ this.replyToRoutingKey = null;
+ this.replyToExchange = null;
+ this.durable = false;
+ this.contentType = null;
+ this.userId = null;
+ this.correlationId = null;
+ this.propertyMap = null;
+ }
+
+ public AmqpProperties Clone()
+ {
+ // memberwise clone ok for string, byte[], and value types
+ AmqpProperties clonedProps = (AmqpProperties)this.MemberwiseClone();
+
+ // deeper copy for the dictionary
+ if (this.propertyMap != null)
+ {
+ if (this.propertyMap.Count > 0)
+ {
+ Dictionary<string, AmqpType> clonedDictionary = new Dictionary<string, AmqpType>(this.propertyMap.Count);
+ foreach (KeyValuePair<string, AmqpType> original in this.propertyMap)
+ {
+ clonedDictionary.Add(original.Key, original.Value.Clone());
+ }
+
+ clonedProps.propertyMap = clonedDictionary;
+ }
+ else
+ {
+ clonedProps.propertyMap = null;
+ }
+ }
+ return clonedProps;
+ }
+
+ // adds/replaces from the other AmqpProperty object.
+ // just inserts references, i.e. provides shallow copy semantics (see Clone for deep copy)
+ public void MergeFrom(AmqpProperties other)
+ {
+ if (other.timeToLive.HasValue)
+ {
+ this.timeToLive = other.timeToLive;
+ }
+
+ if ((other.replyToRoutingKey != null) || (other.replyToExchange != null))
+ {
+ this.replyToExchange = other.replyToExchange;
+ this.replyToRoutingKey = other.replyToRoutingKey;
+ }
+
+ if (other.routingKey != null)
+ {
+ this.routingKey = other.routingKey;
+ }
+
+ if (other.durable)
+ {
+ this.durable = true;
+ }
+
+ if (other.contentType != null)
+ {
+ this.contentType = other.contentType;
+ }
+
+ if (other.correlationId != null)
+ {
+ this.correlationId = other.correlationId;
+ }
+
+ if (other.userId != null)
+ {
+ this.userId = other.userId;
+ }
+
+ if (other.propertyMap != null)
+ {
+ if (other.propertyMap.Count > 0)
+ {
+ Dictionary<string, AmqpType> thisMap = this.PropertyMap;
+ foreach (KeyValuePair<string, AmqpType> kvp in other.propertyMap)
+ {
+ thisMap[kvp.Key] = kvp.Value;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs
new file mode 100644
index 0000000000..87cebe878c
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ // for big strings: str16 in 0-10 and str32 in 1.0
+
+ public class AmqpString : AmqpType
+ {
+ string value;
+ Encoding encoding;
+
+ public AmqpString(string s)
+ {
+ this.value = s;
+ this.encoding = Encoding.UTF8;
+ }
+
+ public AmqpString(string s, Encoding enc)
+ {
+ ValidateEncoding(enc);
+ this.value = s;
+ this.encoding = enc;
+ }
+
+ public Encoding Encoding
+ {
+ get { return encoding; }
+ set
+ {
+ ValidateEncoding(value);
+ encoding = value;
+ }
+ }
+
+ private void ValidateEncoding(Encoding enc)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("Encoding");
+ }
+
+ if ((enc != Encoding.UTF8) && (enc != Encoding.Unicode))
+ {
+ throw new ArgumentException("Encoding not one of UTF8 or Unicode");
+ }
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpString(this.value);
+ }
+
+ public string Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs
new file mode 100644
index 0000000000..8cd3ac9e4a
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs
@@ -0,0 +1,33 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public abstract class AmqpType
+ {
+ public abstract void Encode(byte[] bufer, int offset, int count);
+ public abstract int EncodedSize { get; }
+ public abstract AmqpType Clone();
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj
new file mode 100644
index 0000000000..9c13d47296
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{820BFC34-A40F-46BA-B86B-05334854CA17}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.AmqpTypes</RootNamespace>
+ <AssemblyName>Apache.Qpid.AmqpTypes</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AmqpBoolean.cs" />
+ <Compile Include="AmqpInt.cs" />
+ <Compile Include="AmqpProperties.cs" />
+ <Compile Include="AmqpString.cs" />
+ <Compile Include="AmqpType.cs" />
+ <Compile Include="AmqpUbyte.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="PropertyName.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+<Message Text="yet another debug line" />
+ </Target>
+ <Target Name="AfterBuild"
+ >
+<Message Text="a debug line before banana.netmodule" />
+ <PropertyGroup Condition="('$(TargetFrameworkVersion)' != 'v1.0') and ('$(TargetFrameworkVersion)' != 'v1.1')">
+ <NoWarn>$(NoWarn);1701;1702</NoWarn>
+ </PropertyGroup>
+
+ <Csc
+ AdditionalLibPaths="$(AdditionalLibPaths)"
+ AddModules="@(AddModules)"
+ AllowUnsafeBlocks="$(AllowUnsafeBlocks)"
+ BaseAddress="$(BaseAddress)"
+ CheckForOverflowUnderflow="$(CheckForOverflowUnderflow)"
+ CodePage="$(CodePage)"
+ DebugType="$(DebugType)"
+ DefineConstants="$(DefineConstants)"
+ DelaySign="$(DelaySign)"
+ DisabledWarnings="$(NoWarn)"
+ DocumentationFile="@(DocFileItem)"
+ EmitDebugInformation="$(DebugSymbols)"
+ ErrorReport="$(ErrorReport)"
+ FileAlignment="$(FileAlignment)"
+ GenerateFullPaths="$(GenerateFullPaths)"
+ KeyContainer="$(KeyContainerName)"
+ KeyFile="$(KeyOriginatorFile)"
+ LangVersion="$(LangVersion)"
+ MainEntryPoint="$(StartupObject)"
+ ModuleAssemblyName="banana"
+ NoConfig="true"
+ NoLogo="$(NoLogo)"
+ NoStandardLib="$(NoStdLib)"
+ NoWin32Manifest="$(NoWin32Manifest)"
+ Optimize="$(Optimize)"
+ OutputAssembly="@(IntermediateAssembly)"
+ PdbFile="$(PdbFile)"
+ Platform="$(PlatformTarget)"
+ References="@(ReferencePath)"
+ Resources="@(_CoreCompileResourceInputs);@(CompiledLicenseFile)"
+ ResponseFiles="$(CompilerResponseFile)"
+ Sources="@(Compile)"
+ TargetType="module"
+ ToolExe="$(CscToolExe)"
+ ToolPath="$(CscToolPath)"
+ TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
+ UseHostCompilerIfAvailable="$(UseHostCompilerIfAvailable)"
+ Utf8Output="$(Utf8Output)"
+ WarningLevel="$(WarningLevel)"
+ WarningsAsErrors="$(WarningsAsErrors)"
+ WarningsNotAsErrors="$(WarningsNotAsErrors)"
+ Win32Icon="$(ApplicationIcon)"
+ Win32Manifest="$(Win32Manifest)"
+ Win32Resource="$(Win32Resource)"
+ />
+
+ <ItemGroup>
+ <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" />
+ </ItemGroup>
+
+<Message Text="a debug line after banana.netmodule" />
+ </Target>
+ -->
+ <PropertyGroup>
+ <PostBuildEvent>cd "$(ProjectDir)bin\$(ConfigurationName)"
+del $(AssemblyName).dll
+del $(AssemblyName).pdb
+cd "$(ProjectDir)obj\$(ConfigurationName)"
+del $(AssemblyName).dll
+del $(AssemblyName).pdb
+cd "$(ProjectDir)"
+CreateNetModule.bat</PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs
new file mode 100644
index 0000000000..5ec8a732cf
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpUbyte : AmqpType
+ {
+ byte value;
+
+ public AmqpUbyte(byte i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpUbyte(this.value);
+ }
+
+ public byte Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat b/qpid/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat
new file mode 100755
index 0000000000..ddbe1407a7
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat
@@ -0,0 +1,19 @@
+
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+%systemroot%\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll" /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.DataSetExtensions.dll" /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\Apache.Qpid.AmqpTypes.netmodule /target:module *.cs \ No newline at end of file
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..0bce6f9795
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.AmqpTypes")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("79b8b5d9-047d-4f3b-8610-7fe112ce6416")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs b/qpid/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs
new file mode 100644
index 0000000000..b80f8b9e9e
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs
@@ -0,0 +1,35 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public sealed class PropertyName
+ {
+ public const string Priority = "amqpx.priority";
+ public const string ContentType = "amqp.content-type";
+ public const string ReplyTo = "amqp.reply-to";
+ public const string ReplyToExchange = "amqpx.qpid0-10.reply-to-exchange";
+ public const string RoutingKey = "amqpx.qpid0-10.routing-key";
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs
new file mode 100644
index 0000000000..e207f2fe45
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs
@@ -0,0 +1,60 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinaryBinding : AmqpBinding
+ {
+ public AmqpBinaryBinding()
+: base (new RawMessageEncodingBindingElement())
+ {
+ }
+
+ public AmqpBinaryBinding(string configurationName)
+ : this()
+ {
+ ApplyConfiguration(configurationName);
+ }
+
+ private void ApplyConfiguration(string configurationName)
+ {
+ AmqpBinaryBindingCollectionElement section = (AmqpBinaryBindingCollectionElement)ConfigurationManager.GetSection(AmqpConstants.AmqpBinaryBindingSectionName);
+ AmqpBinaryBindingConfigurationElement element = section.Bindings[configurationName];
+ if (element == null)
+ {
+ throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
+ "There is no binding named {0} at {1}.", configurationName, section.BindingName));
+ }
+ else
+ {
+ element.ApplyConfiguration(this);
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs
new file mode 100644
index 0000000000..de263bc4ef
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ /// <summary>
+ /// Implement application configuration of bindingExtensions for AmqpBinaryBinding
+ /// </summary>
+ public class AmqpBinaryBindingCollectionElement
+ : System.ServiceModel.Configuration.StandardBindingCollectionElement<AmqpBinaryBinding, AmqpBinaryBindingConfigurationElement>
+ {
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs
new file mode 100644
index 0000000000..a537a6c6c3
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs
@@ -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.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinaryBindingConfigurationElement : AmqpBindingConfigurationElement
+ {
+ public AmqpBinaryBindingConfigurationElement(string configurationName)
+ : base(configurationName)
+ {
+ }
+
+ public AmqpBinaryBindingConfigurationElement()
+ : this(null)
+ {
+ }
+
+ protected override Type BindingElementType
+ {
+ get { return typeof(AmqpBinaryBinding); }
+ }
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection properties = base.Properties;
+
+ return properties;
+ }
+ }
+
+ protected override void InitializeFrom(Binding binding)
+ {
+ base.InitializeFrom(binding);
+ AmqpBinaryBinding amqpBinding = (AmqpBinaryBinding)binding;
+ }
+
+ protected override void OnApplyConfiguration(Binding binding)
+ {
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ if (binding.GetType() != typeof(AmqpBinaryBinding))
+ {
+ throw new ArgumentException(string.Format("Invalid type for configuring an AMQP binding. Expected type: {0}. Type passed in: {1}.",
+ typeof(AmqpBinaryBinding).AssemblyQualifiedName,
+ binding.GetType().AssemblyQualifiedName));
+ }
+
+ base.OnApplyConfiguration(binding);
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
new file mode 100644
index 0000000000..b952faf9e5
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
@@ -0,0 +1,115 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinding : Binding
+ {
+ protected AmqpTransportBindingElement transport;
+ protected MessageEncodingBindingElement encoding;
+
+ public AmqpBinding()
+ {
+ transport = new AmqpTransportBindingElement();
+ encoding = new BinaryMessageEncodingBindingElement();
+ }
+
+ protected AmqpBinding(MessageEncodingBindingElement encoding)
+ {
+ this.encoding = encoding;
+ transport = new AmqpTransportBindingElement();
+ }
+
+ public AmqpBinding(string configurationName)
+ : this()
+ {
+ ApplyConfiguration(configurationName);
+ }
+
+ public string BrokerHost
+ {
+ get { return transport.BrokerHost; }
+ set { transport.BrokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return transport.BrokerPort; }
+ set { transport.BrokerPort = value; }
+ }
+
+ public bool Shared
+ {
+ get { return transport.Shared; }
+ set { transport.Shared = value; }
+ }
+
+ public TransferMode TransferMode
+ {
+ get { return transport.TransferMode; }
+ set { transport.TransferMode = value; }
+ }
+
+ public AmqpProperties DefaultMessageProperties
+ {
+ get { return transport.DefaultMessageProperties; }
+ set { transport.DefaultMessageProperties = value; }
+ }
+
+ public override string Scheme
+ {
+ get { return AmqpConstants.Scheme; }
+ }
+
+ public override BindingElementCollection CreateBindingElements()
+ {
+ BindingElementCollection bindingElements = new BindingElementCollection();
+
+ bindingElements.Add(encoding);
+ bindingElements.Add(transport);
+
+ return bindingElements.Clone();
+ }
+
+ private void ApplyConfiguration(string configurationName)
+ {
+ AmqpBindingCollectionElement section = (AmqpBindingCollectionElement)ConfigurationManager.GetSection(AmqpConstants.AmqpBindingSectionName);
+ AmqpBindingConfigurationElement element = section.Bindings[configurationName];
+ if (element == null)
+ {
+ throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
+ "There is no binding named {0} at {1}.", configurationName, section.BindingName));
+ }
+ else
+ {
+ element.ApplyConfiguration(this);
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs
new file mode 100644
index 0000000000..e8d3b6fad4
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ /// <summary>
+ /// Implement application configuration of bindingExtensions for AmqpBinding
+ /// </summary>
+ public class AmqpBindingCollectionElement
+ : System.ServiceModel.Configuration.StandardBindingCollectionElement<AmqpBinding, AmqpBindingConfigurationElement>
+ {
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
new file mode 100644
index 0000000000..3ec62e809d
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
@@ -0,0 +1,258 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBindingConfigurationElement : StandardBindingElement
+ {
+ // not regular config elements. See PostDeserialize
+ string brokerHost;
+ int brokerPort;
+
+ public AmqpBindingConfigurationElement(string configurationName)
+ : base(configurationName)
+ {
+ brokerHost = AmqpDefaults.BrokerHost;
+ brokerPort = AmqpDefaults.BrokerPort;
+ }
+
+ public AmqpBindingConfigurationElement()
+ : this(null)
+ {
+ }
+
+ protected override Type BindingElementType
+ {
+ get { return typeof(AmqpBinding); }
+ }
+
+ public string BrokerHost
+ {
+ get { return brokerHost; }
+ set { brokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return brokerPort; }
+ set { brokerPort = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.Shared, DefaultValue = false)]
+ public bool Shared
+ {
+ get { return (bool)base[AmqpConfigurationStrings.Shared]; }
+ set { base[AmqpConfigurationStrings.Shared] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.TransferMode, DefaultValue = AmqpDefaults.TransferMode)]
+ public TransferMode TransferMode
+ {
+ get { return (TransferMode)base[AmqpConfigurationStrings.TransferMode]; }
+ set { base[AmqpConfigurationStrings.TransferMode] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.Brokers)]
+ public BrokerCollection Brokers
+ {
+ get
+ {
+ return (BrokerCollection)base[AmqpConfigurationStrings.Brokers];
+ }
+ set
+ {
+ base[AmqpConfigurationStrings.Brokers] = value;
+ }
+ }
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection properties = base.Properties;
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.Shared,
+ typeof(bool), false, null, null, ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.TransferMode,
+ typeof(TransferMode), AmqpDefaults.TransferMode, null, null, ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty("brokers", typeof(BrokerCollection), null));
+ return properties;
+ }
+ }
+
+ protected override void InitializeFrom(Binding binding)
+ {
+ base.InitializeFrom(binding);
+ AmqpBinding amqpBinding = (AmqpBinding)binding;
+ this.BrokerHost = amqpBinding.BrokerHost;
+ this.BrokerPort = amqpBinding.BrokerPort;
+ this.TransferMode = amqpBinding.TransferMode;
+ this.Shared = amqpBinding.Shared;
+
+ AmqpProperties props = amqpBinding.DefaultMessageProperties;
+ }
+
+ protected override void OnApplyConfiguration(Binding binding)
+ {
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ if (!(binding is AmqpBinding))
+ {
+ throw new ArgumentException(string.Format("Invalid type for configuring an AMQP binding. Expected type: {0}. Type passed in: {1}.",
+ typeof(AmqpBinding).AssemblyQualifiedName,
+ binding.GetType().AssemblyQualifiedName));
+ }
+
+ AmqpBinding amqpBinding = (AmqpBinding)binding;
+ amqpBinding.BrokerHost = this.BrokerHost;
+ amqpBinding.BrokerPort = this.BrokerPort;
+ amqpBinding.TransferMode = this.TransferMode;
+ amqpBinding.Shared = this.Shared;
+ }
+
+ protected override void PostDeserialize()
+ {
+ base.PostDeserialize();
+
+ BrokerCollection brokers = Brokers;
+ if (brokers != null)
+ {
+ if (brokers.Count > 0)
+ {
+ // just grab the first element until failover is supported
+ System.Collections.IEnumerator brokersEnum = brokers.GetEnumerator();
+ // move to first element
+ brokersEnum.MoveNext();
+ BrokerElement be = (BrokerElement)brokersEnum.Current;
+ this.BrokerHost = be.Host;
+ this.BrokerPort = be.Port;
+ }
+ }
+ }
+ }
+
+ public class BrokerCollection : ConfigurationElementCollection
+ {
+ public BrokerCollection()
+ {
+ //this.AddElementName = "broker";
+ }
+
+ protected override ConfigurationElement CreateNewElement()
+ {
+ return new BrokerElement();
+ }
+
+ protected override void BaseAdd(ConfigurationElement element)
+ {
+ BrokerElement be = (BrokerElement)element;
+ if (this.BaseGet((Object)be.Key) != null)
+ {
+ throw new ConfigurationErrorsException("duplicate broker definition at line " + element.ElementInformation.LineNumber);
+ }
+ base.BaseAdd(element);
+ }
+
+ protected override Object GetElementKey(ConfigurationElement element)
+ {
+ BrokerElement be = (BrokerElement) element;
+ return be.Key;
+ }
+
+ protected override void PostDeserialize()
+ {
+ base.PostDeserialize();
+ if (this.Count == 0)
+ {
+ throw new ArgumentException("Brokers collection requires at least one broker");
+ }
+ if (this.Count > 1)
+ {
+ Console.WriteLine("Warning: multiple brokers not supported, selecting first instance");
+ }
+ BrokerElement be = (BrokerElement)this.BaseGet(0);
+ }
+
+ protected override string ElementName
+ {
+ get
+ {
+ return "broker";
+ }
+ }
+
+ public override ConfigurationElementCollectionType CollectionType
+ {
+ get
+ {
+ return ConfigurationElementCollectionType.BasicMap;
+ }
+ }
+ }
+
+ public class BrokerElement : ConfigurationElement
+ {
+ string key;
+
+ public BrokerElement()
+ {
+ Properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.BrokerHost,
+ typeof(string), AmqpDefaults.BrokerHost, null, null, ConfigurationPropertyOptions.None));
+ Properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.BrokerPort,
+ typeof(int), AmqpDefaults.BrokerPort, null, null, ConfigurationPropertyOptions.None));
+
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.BrokerHost, DefaultValue = AmqpDefaults.BrokerHost)]
+ public string Host
+ {
+ get { return (string)base[AmqpConfigurationStrings.BrokerHost]; }
+ set { base[AmqpConfigurationStrings.BrokerHost] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.BrokerPort, DefaultValue = AmqpDefaults.BrokerPort)]
+ public int Port
+ {
+ get { return (int)base[AmqpConfigurationStrings.BrokerPort]; }
+ set { base[AmqpConfigurationStrings.BrokerPort] = value; }
+ }
+
+ public string Key
+ {
+ get
+ {
+ if (this.key == null)
+ {
+ this.key = this.Host + ':' + this.Port;
+ }
+ return this.key;
+ }
+ }
+
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
new file mode 100644
index 0000000000..b8e2811527
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
@@ -0,0 +1,98 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+
+ class AmqpChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
+ {
+ MessageEncoderFactory messageEncoderFactory;
+ AmqpTransportBindingElement bindingElement;
+ AmqpChannelProperties channelProperties;
+ long maxBufferPoolSize;
+ bool shared;
+
+ internal AmqpChannelFactory(AmqpTransportBindingElement bindingElement, BindingContext context)
+ : base(context.Binding)
+ {
+ this.bindingElement = bindingElement;
+ this.channelProperties = bindingElement.ChannelProperties.Clone();
+ this.shared = bindingElement.Shared;
+ this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
+ Collection<MessageEncodingBindingElement> messageEncoderBindingElements
+ = context.BindingParameters.FindAll<MessageEncodingBindingElement>();
+
+ if(messageEncoderBindingElements.Count > 1)
+ {
+ throw new InvalidOperationException("More than one MessageEncodingBindingElement was found in the BindingParameters of the BindingContext");
+ }
+ else if (messageEncoderBindingElements.Count == 1)
+ {
+ this.messageEncoderFactory = messageEncoderBindingElements[0].CreateMessageEncoderFactory();
+ }
+ else
+ {
+ this.messageEncoderFactory = new TextMessageEncodingBindingElement().CreateMessageEncoderFactory();
+ }
+ }
+
+
+ public override T GetProperty<T>()
+ {
+ T mep = messageEncoderFactory.Encoder.GetProperty<T>();
+ if (mep != null)
+ {
+ return mep;
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)messageEncoderFactory.Encoder.MessageVersion;
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelFactory OnBeginOpen");
+ //// return null;
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelFactory OnEndOpen");
+ }
+
+ protected override TChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
+ {
+ return (TChannel)(object) new AmqpTransportChannel(this, this.channelProperties, remoteAddress, this.messageEncoderFactory.Encoder, this.maxBufferPoolSize, this.shared);
+ }
+
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
new file mode 100644
index 0000000000..f1de30406a
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
@@ -0,0 +1,142 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Globalization;
+
+ using Apache.Qpid.AmqpTypes;
+
+ /// <summary>
+ /// Collection of constants used by the Amqp Channel classes
+ /// </summary>
+ static class AmqpConstants
+ {
+ internal const string Scheme = "amqp";
+ internal const string AmqpBindingSectionName = "system.serviceModel/bindings/amqpBinding";
+ internal const string AmqpBinaryBindingSectionName = "system.serviceModel/bindings/amqpBinaryBinding";
+ internal const string AmqpTransportSectionName = "amqpTransport";
+ }
+
+ static class AmqpConfigurationStrings
+ {
+ public const string BrokerHost = "host";
+ public const string BrokerPort = "port";
+ public const string TransferMode = "transferMode";
+ public const string Brokers = "brokers";
+ public const string Shared = "shared";
+ public const string MaxBufferPoolSize = "maxBufferPoolSize";
+ public const string MaxReceivedMessageSize = "maxReceivedMessageSize";
+ }
+
+ static class AmqpDefaults
+ {
+ internal const string BrokerHost = "localhost";
+ internal const int BrokerPort = 5672;
+ internal const TransferMode TransferMode = System.ServiceModel.TransferMode.Buffered;
+ internal const byte Priority = 4;
+ internal const long MaxBufferPoolSize = 64 * 1024;
+ internal const int MaxReceivedMessageSize = 5 * 1024 * 1024; //64 * 1024;
+ }
+
+ // parking spot for properties that may be shared by separate channels on a single AMQP connection
+ internal class AmqpChannelProperties
+ {
+ string brokerHost;
+ int brokerPort;
+ TransferMode transferMode;
+ AmqpProperties defaultMessageProperties;
+
+ long maxBufferPoolSize;
+ int maxReceivedMessageSize;
+
+ internal AmqpChannelProperties()
+ {
+ this.brokerHost = AmqpDefaults.BrokerHost;
+ this.brokerPort = AmqpDefaults.BrokerPort;
+ this.transferMode = AmqpDefaults.TransferMode;
+ this.defaultMessageProperties = null;
+ this.maxBufferPoolSize = AmqpDefaults.MaxBufferPoolSize;
+ this.maxReceivedMessageSize = AmqpDefaults.MaxReceivedMessageSize;
+ }
+
+ public AmqpChannelProperties Clone()
+ {
+ AmqpChannelProperties props = (AmqpChannelProperties) this.MemberwiseClone();
+ if (this.defaultMessageProperties != null)
+ {
+ props.defaultMessageProperties = this.defaultMessageProperties.Clone();
+ }
+
+ return props;
+ }
+
+ internal string BrokerHost
+ {
+ get { return this.brokerHost; }
+ set { this.brokerHost = value; }
+ }
+
+ internal int BrokerPort
+ {
+ get { return this.brokerPort; }
+ set { this.brokerPort = value; }
+ }
+
+ internal TransferMode TransferMode
+ {
+ get { return this.transferMode; }
+ set { this.transferMode = value; }
+ }
+
+ internal AmqpProperties DefaultMessageProperties
+ {
+ get { return this.defaultMessageProperties; }
+ set { this.defaultMessageProperties = value; }
+ }
+
+ internal long MaxBufferPoolSize
+ {
+ get { return this.maxBufferPoolSize; }
+ set { this.maxBufferPoolSize = value; }
+ }
+
+ internal int MaxReceivedMessageSize
+ {
+ get { return this.maxReceivedMessageSize; }
+ set { this.maxReceivedMessageSize = value; }
+ }
+ }
+
+ static class AmqpChannelHelpers
+ {
+ internal static void ValidateTimeout(TimeSpan timeout)
+ {
+ if (timeout < TimeSpan.Zero)
+ {
+ throw new ArgumentOutOfRangeException("timeout", timeout, "Timeout must be greater than or equal to TimeSpan.Zero. To disable timeout, specify TimeSpan.MaxValue.");
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
new file mode 100644
index 0000000000..44fecdaf62
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
@@ -0,0 +1,174 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+
+ class AmqpChannelListener : ChannelListenerBase<IInputChannel>
+ {
+ MessageEncoderFactory messageEncoderFactory;
+ AmqpTransportBindingElement bindingElement;
+ AmqpChannelProperties channelProperties;
+ bool shared;
+ long maxBufferPoolSize;
+ Uri uri;
+ AmqpTransportChannel amqpTransportChannel;
+ delegate IInputChannel AsyncOnAcceptCaller (TimeSpan timeout);
+ AsyncOnAcceptCaller asyncOnAcceptCaller;
+ ManualResetEvent acceptWaitEvent;
+
+ internal AmqpChannelListener(AmqpTransportBindingElement bindingElement, BindingContext context)
+ : base(context.Binding)
+ {
+ this.bindingElement = bindingElement;
+ this.channelProperties = bindingElement.ChannelProperties.Clone();
+ this.shared = bindingElement.Shared;
+
+ this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
+
+ // TODO: review this. Should be unique hostname based
+ this.uri = context.ListenUriBaseAddress;
+ this.asyncOnAcceptCaller = new AsyncOnAcceptCaller(this.OnAcceptChannel);
+ this.acceptWaitEvent = new ManualResetEvent(false);
+
+ Collection<MessageEncodingBindingElement> messageEncoderBindingElements
+ = context.BindingParameters.FindAll<MessageEncodingBindingElement>();
+
+ if(messageEncoderBindingElements.Count > 1)
+ {
+ throw new InvalidOperationException("More than one MessageEncodingBindingElement was found in the BindingParameters of the BindingContext");
+ }
+ else if (messageEncoderBindingElements.Count == 1)
+ {
+ this.messageEncoderFactory = messageEncoderBindingElements[0].CreateMessageEncoderFactory();
+ }
+ else
+ {
+ this.messageEncoderFactory = new TextMessageEncodingBindingElement().CreateMessageEncoderFactory();
+ }
+ }
+
+ public override Uri Uri
+ {
+ get
+ {
+ return this.uri;
+ }
+ }
+
+
+
+ public override T GetProperty<T>()
+ {
+ T mep = messageEncoderFactory.Encoder.GetProperty<T>();
+ if (mep != null)
+ {
+ return mep;
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)messageEncoderFactory.Encoder.MessageVersion;
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginOpen");
+ //// return null;
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndOpen");
+ }
+
+ protected override bool OnWaitForChannel(TimeSpan timeout)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnWaitForChannel");
+ }
+
+ protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginWaitForChannel");
+ }
+
+ protected override bool OnEndWaitForChannel(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndWaitForChannel");
+ }
+
+ protected override IInputChannel OnAcceptChannel(TimeSpan timeout)
+ {
+ if (amqpTransportChannel == null)
+ {
+ amqpTransportChannel = new AmqpTransportChannel(this, this.channelProperties,
+ new EndpointAddress(uri), messageEncoderFactory.Encoder,
+ maxBufferPoolSize, this.shared);
+ return (IInputChannel)(object) amqpTransportChannel;
+ }
+
+ // TODO: remove "max one channel" restriction, add timeout processing
+ acceptWaitEvent.WaitOne();
+ return null;
+ }
+
+ protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return asyncOnAcceptCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override IInputChannel OnEndAcceptChannel(IAsyncResult result)
+ {
+ return asyncOnAcceptCaller.EndInvoke(result);
+ }
+
+ protected override void OnClose(TimeSpan timeout)
+ {
+ // TODO: (+ OnAbort)
+ }
+
+ protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginClose");
+ }
+
+ protected override void OnEndClose(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndClose");
+ }
+
+ protected override void OnAbort()
+ {
+ // TODO:
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
new file mode 100644
index 0000000000..f23b8072e9
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
@@ -0,0 +1,145 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpTransportBindingElement : TransportBindingElement
+ {
+ AmqpChannelProperties channelProperties;
+ bool shared;
+
+ public AmqpTransportBindingElement()
+ {
+ // start with default properties
+ channelProperties = new AmqpChannelProperties();
+ }
+
+ protected AmqpTransportBindingElement(AmqpTransportBindingElement other)
+ : base(other)
+ {
+ this.channelProperties = other.channelProperties.Clone();
+ this.shared = other.shared;
+ }
+
+ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ return (IChannelFactory<TChannel>)(object)new AmqpChannelFactory<TChannel>(this, context);
+ }
+
+ public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ return (IChannelListener<TChannel>)(object)new AmqpChannelListener(this, context);
+ }
+
+
+
+ public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
+ {
+ return ((typeof(TChannel) == typeof(IOutputChannel)) ||
+ (typeof(TChannel) == typeof(IInputChannel)));
+ }
+
+ public override bool CanBuildChannelListener<TChannel>(BindingContext context)
+ {
+ return ((typeof(TChannel) == typeof(IInputChannel)));
+ }
+
+ public override BindingElement Clone()
+ {
+ return new AmqpTransportBindingElement(this);
+ }
+
+ internal AmqpChannelProperties ChannelProperties
+ {
+ get { return channelProperties; }
+ }
+
+ public string BrokerHost
+ {
+ get { return this.channelProperties.BrokerHost; }
+ set { this.channelProperties.BrokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return this.channelProperties.BrokerPort; }
+ set { this.channelProperties.BrokerPort = value; }
+ }
+
+ public bool Shared
+ {
+ get { return this.shared; }
+ set { this.shared = value; }
+ }
+
+ public TransferMode TransferMode
+ {
+ get { return this.channelProperties.TransferMode; }
+ set { this.channelProperties.TransferMode = value; }
+ }
+
+ public AmqpProperties DefaultMessageProperties
+ {
+ get { return this.channelProperties.DefaultMessageProperties; }
+
+ set { this.channelProperties.DefaultMessageProperties = value; }
+ }
+
+ public override T GetProperty<T>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)MessageVersion.Default;
+ }
+
+
+ return context.GetInnerProperty<T>();
+ }
+
+ public override string Scheme
+ {
+ get
+ {
+ return AmqpConstants.Scheme;
+ }
+ }
+
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
new file mode 100644
index 0000000000..ca9c10be69
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
@@ -0,0 +1,592 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// TODO: flow control
+// timeout handling
+// transactions
+// check if should split into separate input and output classes (little overlap)
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Text;
+ using System.Threading;
+ using System.Globalization;
+ using System.Xml;
+
+ // the thin interop layer that provides access to the Qpid AMQP client libraries
+ using Apache.Qpid.Interop;
+ using Apache.Qpid.AmqpTypes;
+
+ /// <summary>
+ /// WCF client transport channel for accessing AMQP brokers using the Qpid C++ library
+ /// </summary>
+ public class AmqpTransportChannel : ChannelBase, IOutputChannel, IInputChannel
+ {
+ private static readonly EndpointAddress AnonymousAddress =
+ new EndpointAddress("http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous");
+
+ private EndpointAddress remoteAddress;
+ private MessageEncoder encoder;
+ private AmqpChannelProperties factoryChannelProperties;
+ private bool shared;
+ private string encoderContentType;
+
+ // input = 0-10 queue, output = 0-10 exchange
+ private string queueName;
+
+ private String routingKey;
+ private BufferManager bufferManager;
+ private AmqpProperties outputMessageProperties;
+
+ private InputLink inputLink;
+ private OutputLink outputLink;
+
+ private bool isInputChannel;
+ private bool streamed;
+
+ private AsyncTimeSpanCaller asyncOpenCaller;
+ private AsyncTimeSpanCaller asyncCloseCaller;
+
+ internal AmqpTransportChannel(ChannelManagerBase factory, AmqpChannelProperties channelProperties, EndpointAddress remoteAddress, MessageEncoder msgEncoder, long maxBufferPoolSize, bool sharedConnection)
+ : base(factory)
+ {
+ this.isInputChannel = (factory is ChannelListenerBase) || (factory is AmqpChannelFactory<IInputChannel>);
+
+ if (remoteAddress == null)
+ {
+ throw new ArgumentException("Null Endpoint Address");
+ }
+
+ this.factoryChannelProperties = channelProperties;
+ this.shared = sharedConnection;
+ this.remoteAddress = remoteAddress;
+
+ // pull out host, port, queue, and connection arguments
+ this.ParseAmqpUri(remoteAddress.Uri);
+
+ this.encoder = msgEncoder;
+ string ct = String.Empty;
+ if (this.encoder != null)
+ {
+ ct = this.encoder.ContentType;
+ if (ct != null)
+ {
+ int pos = ct.IndexOf(';');
+ if (pos != -1)
+ {
+ ct = ct.Substring(0, pos).Trim();
+ }
+ }
+ else
+ {
+ ct = "application/octet-stream";
+ }
+ }
+
+ this.encoderContentType = ct;
+
+ if (this.factoryChannelProperties.TransferMode == TransferMode.Streamed)
+ {
+ this.streamed = true;
+ }
+ else
+ {
+ if (!(this.factoryChannelProperties.TransferMode == TransferMode.Buffered))
+ {
+ throw new ArgumentException("TransferMode mode must be \"Streamed\" or \"Buffered\"");
+ }
+
+ this.streamed = false;
+ }
+
+ this.bufferManager = BufferManager.CreateBufferManager(maxBufferPoolSize, int.MaxValue);
+
+ this.asyncOpenCaller = new AsyncTimeSpanCaller(this.OnOpen);
+ this.asyncCloseCaller = new AsyncTimeSpanCaller(this.OnClose);
+
+ if (this.isInputChannel)
+ {
+ this.inputLink = ConnectionManager.GetInputLink(this.factoryChannelProperties, shared, false, this.queueName);
+ }
+ else
+ {
+ this.outputLink = ConnectionManager.GetOutputLink(this.factoryChannelProperties, shared, false, this.queueName);
+ }
+ }
+
+ private delegate bool AsyncTryReceiveCaller(TimeSpan timeout, out Message message);
+
+ private delegate void AsyncTimeSpanCaller(TimeSpan timeout);
+
+ EndpointAddress IOutputChannel.RemoteAddress
+ {
+ get
+ {
+ return this.remoteAddress;
+ }
+ }
+
+ // i.e what you would insert into a ReplyTo header to reach
+ // here. Presumably should be exchange/link and routing info,
+ // rather than the actual input queue name.
+ EndpointAddress IInputChannel.LocalAddress
+ {
+ get
+ {
+ // TODO: something better
+ return AnonymousAddress;
+ }
+ }
+
+ AmqpProperties OutputMessageProperties
+ {
+ get
+ {
+ if (this.outputMessageProperties == null)
+ {
+ this.outputMessageProperties = this.factoryChannelProperties.DefaultMessageProperties;
+ if (this.outputMessageProperties == null)
+ {
+ this.outputMessageProperties = new AmqpProperties();
+ }
+ }
+
+ return this.outputMessageProperties;
+ }
+ }
+
+ Uri IOutputChannel.Via
+ {
+ get
+ {
+ return this.remoteAddress.Uri;
+ }
+ }
+
+ public override T GetProperty<T>()
+ {
+ if (typeof(T) == typeof(IInputChannel))
+ {
+ if (this.isInputChannel)
+ {
+ return (T)(object)this;
+ }
+ }
+ else if (typeof(T) == typeof(IOutputChannel))
+ {
+ if (!this.isInputChannel)
+ {
+ return (T)(object)this;
+ }
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ public void Send(Message message, TimeSpan timeout)
+ {
+ this.ThrowIfDisposedOrNotOpen();
+ AmqpChannelHelpers.ValidateTimeout(timeout);
+
+ try
+ {
+ using (AmqpMessage amqpMessage = this.WcfToQpid(message))
+ {
+ this.outputLink.Send(amqpMessage, timeout);
+ }
+ }
+ finally
+ {
+ message.Close();
+ }
+ }
+
+ public void Send(Message message)
+ {
+ this.Send(message, this.DefaultSendTimeout);
+ }
+
+ public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ this.ThrowIfDisposedOrNotOpen();
+ AmqpChannelHelpers.ValidateTimeout(timeout);
+
+ try
+ {
+ using (AmqpMessage amqpMessage = this.WcfToQpid(message))
+ {
+ return this.outputLink.BeginSend(amqpMessage, timeout, callback, state);
+ }
+ }
+ finally
+ {
+ message.Close();
+ }
+ }
+
+ public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
+ {
+ return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
+ }
+
+ public void EndSend(IAsyncResult result)
+ {
+ this.outputLink.EndSend(result);
+ }
+
+ public Message Receive(TimeSpan timeout)
+ {
+ Message message;
+ if (this.TryReceive(timeout, out message))
+ {
+ return message;
+ }
+ else
+ {
+ throw new TimeoutException("Receive");
+ }
+ }
+
+ public Message Receive()
+ {
+ return this.Receive(this.DefaultReceiveTimeout);
+ }
+
+ public bool TryReceive(TimeSpan timeout, out Message message)
+ {
+ this.ThrowIfDisposedOrNotOpen();
+ AmqpMessage amqpMessage;
+ message = null;
+
+ if (this.inputLink.TryReceive(timeout, out amqpMessage))
+ {
+ message = this.QpidToWcf(amqpMessage);
+ return true;
+ }
+
+ return false;
+ }
+
+ public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginTryReceive(timeout, callback, state);
+ }
+
+ public bool EndTryReceive(IAsyncResult result, out Message message)
+ {
+ AmqpMessage amqpMessage = null;
+ if (!this.inputLink.EndTryReceive(result, out amqpMessage))
+ {
+ message = null;
+ return false;
+ }
+ message = QpidToWcf(amqpMessage);
+ return true;
+ }
+
+ public bool WaitForMessage(TimeSpan timeout)
+ {
+ return this.inputLink.WaitForMessage(timeout);
+ }
+
+ public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginTryReceive(timeout, callback, state);
+ }
+
+ public IAsyncResult BeginReceive(AsyncCallback callback, object state)
+ {
+ return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
+ }
+
+ public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginWaitForMessage(timeout, callback, state);
+ }
+
+ public Message EndReceive(IAsyncResult result)
+ {
+ Message message;
+ if (this.EndTryReceive(result, out message))
+ {
+ return message;
+ }
+ else
+ {
+ throw new TimeoutException("EndReceive");
+ }
+ }
+
+ public bool EndWaitForMessage(IAsyncResult result)
+ {
+ return this.inputLink.EndWaitForMessage(result);
+ }
+
+ public void CloseEndPoint()
+ {
+ if (this.inputLink != null)
+ {
+ this.inputLink.Close();
+ }
+ if (this.outputLink != null)
+ {
+ this.outputLink.Close();
+ }
+ }
+
+ /// <summary>
+ /// Open connection to Broker
+ /// </summary>
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ // TODO: move open logic to here from constructor
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.asyncOpenCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ this.asyncOpenCaller.EndInvoke(result);
+ }
+
+ protected override void OnAbort()
+ {
+ //// TODO: check for network-less qpid teardown or launch special thread
+ this.Cleanup();
+ }
+
+ /// <summary>
+ /// Shutdown gracefully
+ /// </summary>
+ protected override void OnClose(TimeSpan timeout)
+ {
+ this.CloseEndPoint();
+ this.Cleanup();
+ }
+
+ protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.asyncCloseCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndClose(IAsyncResult result)
+ {
+ this.asyncCloseCaller.EndInvoke(result);
+ }
+
+ private AmqpMessage WcfToQpid(Message wcfMessage)
+ {
+ object obj;
+ AmqpProperties applicationProperties = null;
+ bool success = false;
+ AmqpMessage amqpMessage = null;
+
+ if (wcfMessage.Properties.TryGetValue("AmqpProperties", out obj))
+ {
+ applicationProperties = obj as AmqpProperties;
+ }
+
+ try
+ {
+ AmqpProperties outgoingProperties = new AmqpProperties();
+
+ // Start with AMQP properties from the binding and the URI
+ if (this.factoryChannelProperties.DefaultMessageProperties != null)
+ {
+ outgoingProperties.MergeFrom(this.factoryChannelProperties.DefaultMessageProperties);
+ }
+
+ if (this.routingKey != null)
+ {
+ outgoingProperties.RoutingKey = this.routingKey;
+ }
+
+ // Add the Properties set by the application on this particular message.
+ // Application properties trump channel properties
+ if (applicationProperties != null)
+ {
+ outgoingProperties.MergeFrom(applicationProperties);
+ }
+
+ amqpMessage = this.outputLink.CreateMessage();
+ amqpMessage.Properties = outgoingProperties;
+
+ // copy the WCF message body to the AMQP message body
+ if (this.streamed)
+ {
+ this.encoder.WriteMessage(wcfMessage, amqpMessage.BodyStream);
+ }
+ else
+ {
+ ArraySegment<byte> encodedBody = this.encoder.WriteMessage(wcfMessage, int.MaxValue, this.bufferManager);
+ try
+ {
+ amqpMessage.BodyStream.Write(encodedBody.Array, encodedBody.Offset, encodedBody.Count);
+ }
+ finally
+ {
+ this.bufferManager.ReturnBuffer(encodedBody.Array);
+ }
+ }
+
+ success = true;
+ }
+ finally
+ {
+ if (!success && (amqpMessage != null))
+ {
+ amqpMessage.Dispose();
+ }
+ }
+ return amqpMessage;
+ }
+
+
+ private Message QpidToWcf(AmqpMessage amqpMessage)
+ {
+ if (amqpMessage == null)
+ {
+ return null;
+ }
+
+ Message wcfMessage = null;
+ byte[] managedBuffer = null;
+
+ try
+ {
+ if (this.streamed)
+ {
+ wcfMessage = this.encoder.ReadMessage(amqpMessage.BodyStream, int.MaxValue);
+ }
+ else
+ {
+ int count = (int)amqpMessage.BodyStream.Length;
+ managedBuffer = this.bufferManager.TakeBuffer(count);
+ int nr = amqpMessage.BodyStream.Read(managedBuffer, 0, count);
+ ArraySegment<byte> bufseg = new ArraySegment<byte>(managedBuffer, 0, count);
+
+ wcfMessage = this.encoder.ReadMessage(bufseg, this.bufferManager);
+
+ // set to null for finally{} block, since the encoder is now responsible for
+ // returning the BufferManager memory
+ managedBuffer = null;
+ }
+
+ // This message will be discarded unless the "To" header matches
+ // the WCF endpoint dispatcher's address filter (or the service is
+ // AddressFilterMode=AddressFilterMode.Any).
+
+ this.remoteAddress.ApplyTo(wcfMessage);
+
+ if (amqpMessage.Properties != null)
+ {
+ wcfMessage.Properties.Add("AmqpProperties", amqpMessage.Properties);
+ }
+ }
+ catch (XmlException xmlException)
+ {
+ throw new ProtocolException(
+ "There is a problem with the XML that was received from the network. See inner exception for more details.",
+ xmlException);
+ }
+ catch (Exception e)
+ {
+ // TODO: logging
+ Console.WriteLine("TX channel encoder exception " + e);
+ }
+ finally
+ {
+ // close the amqpMessage unless the body will be read at a later time.
+ if (!this.streamed || wcfMessage == null)
+ {
+ amqpMessage.Close();
+ }
+
+ // the handoff to the encoder failed
+ if (managedBuffer != null)
+ {
+ this.bufferManager.ReturnBuffer(managedBuffer);
+ }
+ }
+
+ return wcfMessage;
+ }
+
+ private void Cleanup()
+ {
+ this.bufferManager.Clear();
+ }
+
+ // "amqp:queue1" | "amqp:stocks@broker1.com" | "amqp:queue3?routingkey=key"
+ private void ParseAmqpUri(Uri uri)
+ {
+ if (uri.Scheme != AmqpConstants.Scheme)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "The scheme {0} specified in address is not supported.", uri.Scheme), "uri");
+ }
+
+ this.queueName = uri.LocalPath;
+
+ if ((this.queueName.IndexOf('@') != -1) && this.isInputChannel)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "Invalid input queue name: \"{0}\" specified.", this.queueName), "uri");
+ }
+
+ // search out session parameters in the query portion of the URI
+
+ string routingParseKey = "routingkey=";
+ char[] charSeparators = new char[] { '?', ';' };
+ string[] args = uri.Query.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
+ foreach (string s in args)
+ {
+ if (s.StartsWith(routingParseKey))
+ {
+ this.routingKey = s.Substring(routingParseKey.Length);
+ }
+ }
+
+ if (this.queueName == String.Empty)
+ {
+ if (this.isInputChannel)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "Empty queue target specifier not allowed."), "uri");
+ }
+ else
+ {
+ if (this.routingKey == null)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "No target queue or routing key specified."), "uri");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/Channel.csproj b/qpid/wcf/src/Apache/Qpid/Channel/Channel.csproj
new file mode 100644
index 0000000000..0b04eba986
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/Channel.csproj
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{8AABAB30-7D1E-4539-B7D1-05450262BAD2}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Channel</RootNamespace>
+ <AssemblyName>Apache.Qpid.Channel</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <StartupObject>
+ </StartupObject>
+ <SignAssembly>false</SignAssembly>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ItemGroup>
+ <Compile Include="AmqpBinaryBinding.cs" />
+ <Compile Include="AmqpBinaryBindingCollectionElement.cs" />
+ <Compile Include="AmqpBinaryBindingConfigurationElement.cs" />
+ <Compile Include="AmqpChannelFactory.cs" />
+ <Compile Include="AmqpChannelHelpers.cs" />
+ <Compile Include="AmqpChannelListener.cs" />
+ <Compile Include="AmqpBinding.cs" />
+ <Compile Include="AmqpBindingCollectionElement.cs" />
+ <Compile Include="AmqpBindingConfigurationElement.cs" />
+ <Compile Include="AmqpTransportBindingElement.cs" />
+ <Compile Include="AmqpTransportChannel.cs" />
+ <Compile Include="ConnectionManager.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="RawMessage.cs" />
+ <Compile Include="RawMessageEncoder.cs" />
+ <Compile Include="RawMessageEncoderFactory.cs" />
+ <Compile Include="RawMessageEncodingBindingElement.cs" />
+ <Compile Include="RawXmlReader.cs" />
+ <Compile Include="RawXmlWriter.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.XML" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Interop\Interop.vcproj">
+ <Project>{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}</Project>
+ <Name>Interop</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs b/qpid/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs
new file mode 100644
index 0000000000..a63e5333f4
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs
@@ -0,0 +1,266 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Threading;
+
+ using Apache.Qpid.Interop;
+
+ // The ConnectionManager looks after a shareable pool of AmqpConnection and AmqpSession
+ // objects. If two connection requests could be shared (see MakeKey() properties), and
+ // are designated as shareable, then they will be paired up. Each shared connection is
+ // a separate instance of a ManagedConnection. All unshared connections use a single
+ // instance of ManagedConnection with locking turned off. The ManagedConnection object
+ // registers for notifictation when a connection goes idle (all grandchild InputLink and
+ // OutputLink objects have been closed), and closes the connection.
+
+ // TODO: the session sharing is roughed-in via comments but needs completing.
+
+ internal sealed class ConnectionManager
+ {
+ // A side effect of creating InputLinks and OutputLinks is that counters
+ // in the respective AmqpSession and AmqpConnection are updated, so care
+ // must be taken to hold the lock across acquiring a session and opening
+ // a link on it.
+
+ // one for each shared connection
+ private static Dictionary<string, ManagedConnection> sharedInstances;
+
+ // this one creates and releases connections that are not shared. No locking required.
+ private static ManagedConnection unsharedInstance;
+
+ // lock for finding or creating ManagedConnection instances
+ private static Object connectionLock;
+
+ static ConnectionManager()
+ {
+ unsharedInstance = null;
+ sharedInstances = new Dictionary<string, ManagedConnection>();
+ connectionLock = new Object();
+ }
+
+ private static string MakeKey(AmqpChannelProperties props)
+ {
+ return props.BrokerHost + ':' + props.BrokerPort + ':' + props.TransferMode;
+ }
+
+ private static ManagedConnection GetManagedConnection(AmqpChannelProperties channelProperties, bool connectionSharing)
+ {
+ if (connectionSharing)
+ {
+ string key = MakeKey(channelProperties);
+ lock (connectionLock)
+ {
+ ManagedConnection mc = null;
+ if (!sharedInstances.TryGetValue(key, out mc))
+ {
+ mc = new ManagedConnection(true);
+ sharedInstances.Add(key, mc);
+ }
+ return mc;
+ }
+ }
+ else
+ {
+ lock (connectionLock)
+ {
+ if (unsharedInstance == null)
+ {
+ unsharedInstance = new ManagedConnection(false);
+ }
+ return unsharedInstance;
+ }
+ }
+ }
+
+ public static OutputLink GetOutputLink(AmqpChannelProperties channelProperties, bool connectionSharing, bool sessionSharing, string qname)
+ {
+ ManagedConnection mc = GetManagedConnection(channelProperties, connectionSharing);
+ return (OutputLink)mc.GetLink(channelProperties, sessionSharing, null, qname);
+ }
+
+ public static InputLink GetInputLink(AmqpChannelProperties channelProperties, bool connectionSharing, bool sessionSharing, string qname)
+ {
+ ManagedConnection mc = GetManagedConnection(channelProperties, connectionSharing);
+ return (InputLink)mc.GetLink(channelProperties, sessionSharing, qname, null);
+ }
+
+
+
+ class ManagedConnection
+ {
+ private Boolean shared;
+ private AmqpConnection sharedConnection;
+ //private Dictionary<string, AmqpSession> sharedSessions;
+
+ public ManagedConnection(bool shared)
+ {
+ this.shared = shared;
+ }
+
+
+ public object GetLink(AmqpChannelProperties channelProperties, bool sessionSharing, string inputQueue, string outputQueue)
+ {
+ AmqpConnection connection = null;
+ AmqpSession session = null;
+ Object link = null;
+ bool newConnection = false;
+ //bool newSession = false;
+ bool success = false;
+
+ // when called in the non-shared case, only stack variables should be used for holding connections/sessions/links
+
+ if (this.shared)
+ {
+ Monitor.Enter(this); // lock
+ }
+
+ try
+ {
+ if (this.shared)
+ {
+ // TODO: check shared connection not closed (i.e. network drop) and refresh this instance if needed
+ if (sessionSharing)
+ {
+ throw new NotImplementedException("shared session");
+ /* * ... once we have a defined shared session config parameter:
+
+ // lazilly create
+ if (this.sharedSessions == null)
+ {
+ this.sharedSessions = new Dictionary<string, AmqpSession>();
+ }
+
+ alreadydeclaredstring sessionKey = channelProperties.name_of_key_goes_here;
+ this.sharedSessions.TryGetValue(sessionKey, out session);
+
+ * */
+ }
+
+ if (this.sharedConnection != null)
+ {
+ connection = this.sharedConnection;
+ }
+ }
+
+ if (connection == null)
+ {
+ connection = new AmqpConnection(channelProperties.BrokerHost, channelProperties.BrokerPort);
+ newConnection = true;
+ if (this.shared)
+ {
+ connection.OnConnectionIdle += new ConnectionIdleEventHandler(this.IdleConnectionHandler);
+ }
+ else
+ {
+ connection.OnConnectionIdle += new ConnectionIdleEventHandler(UnsharedIdleConnectionHandler);
+ }
+ }
+
+ if (session == null)
+ {
+ session = connection.CreateSession();
+ //newSession = true;
+ }
+
+ if (inputQueue != null)
+ {
+ link = session.CreateInputLink(inputQueue);
+ }
+ else
+ {
+ link = session.CreateOutputLink(outputQueue);
+ }
+
+ if (this.shared)
+ {
+ if (newConnection)
+ {
+ this.sharedConnection = connection;
+ }
+ /*
+ if (newSession)
+ {
+ sharedSessions.Add(foo, session);
+ }
+ * */
+ }
+
+ success = true;
+ }
+ finally
+ {
+ if (this.shared)
+ {
+ Monitor.Exit(this);
+ }
+ if (!success)
+ {
+ /*
+ if (newSession)
+ {
+ session.Close();
+ }
+ */
+ if (newConnection)
+ {
+ connection.Close();
+ }
+ }
+ }
+
+ return link;
+ }
+
+
+ static void UnsharedIdleConnectionHandler(Object sender, EventArgs empty)
+ {
+ if (sender is AmqpConnection)
+ {
+ AmqpConnection connection = (AmqpConnection)sender;
+ connection.Close();
+ }
+ }
+
+ void IdleConnectionHandler(Object sender, EventArgs empty)
+ {
+ lock (this)
+ {
+ if (sharedConnection != sender || sharedConnection == null)
+ {
+ return;
+ }
+ if (!sharedConnection.IsIdle)
+ {
+ // Another thread made the connection busy again.
+ // That's OK. Another idle event will come along later.
+ return;
+ }
+ sharedConnection.Close(); // also closes all child sessions
+ sharedConnection = null;
+ //sharedSessions = null;
+ }
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs b/qpid/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..bc047d59b3
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Channel")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ac02bbb0-2c19-43fb-a36c-b1b0a50eaf1a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawMessage.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawMessage.cs
new file mode 100644
index 0000000000..5925fa47dc
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawMessage.cs
@@ -0,0 +1,374 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.ServiceModel.Channels;
+ using System.Xml;
+
+ // This incoming Message is backed either by a Stream (bodyStream) or a byte array (bodyBytes).
+ // If bodyBytes belongs to a BufferManager, we must return it when done.
+ // The pay-off is OnGetReaderAtBodyContents().
+ // Most of the complexity is dealing with the OnCreateBufferedCopy() machinery.
+ internal class RawMessage : Message
+ {
+ private MessageHeaders headers;
+ private MessageProperties properties;
+ private XmlDictionaryReaderQuotas readerQuotas;
+ private Stream bodyStream;
+ private byte[] bodyBytes;
+ private int index;
+ private int count;
+ private BufferManager bufferManager;
+
+ public RawMessage(byte[] buffer, int index, int count, BufferManager bufferManager, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports MessageEncoder.ReadMessage(ArraySegment<byte> b, BufferManager mgr, string contentType)
+ if (quotas == null)
+ {
+ quotas = new XmlDictionaryReaderQuotas();
+ }
+
+ this.headers = new MessageHeaders(MessageVersion.None);
+ this.properties = new MessageProperties();
+ this.readerQuotas = quotas;
+ this.bodyBytes = buffer;
+ this.index = index;
+ this.count = count;
+ this.bufferManager = bufferManager;
+ }
+
+ public RawMessage(Stream stream, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports MessageEncoder.ReadMessage(System.IO.Stream s, int max, string contentType)
+ if (quotas == null)
+ {
+ quotas = new XmlDictionaryReaderQuotas();
+ }
+
+ this.headers = new MessageHeaders(MessageVersion.None);
+ this.properties = new MessageProperties();
+ this.bodyStream = stream;
+ }
+
+ public RawMessage(MessageHeaders headers, MessageProperties properties, byte[] bytes, int index, int count, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports internal needs for CreateBufferedCopy().CreateMessage()
+ this.headers = new MessageHeaders(headers);
+ this.properties = new MessageProperties(properties);
+ this.bodyBytes = bytes;
+ this.index = index;
+ this.count = count;
+ this.readerQuotas = quotas;
+ }
+
+ public override MessageHeaders Headers
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return this.headers;
+ }
+ }
+
+ public override bool IsEmpty
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return false;
+ }
+ }
+
+ public override bool IsFault
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return false;
+ }
+ }
+
+ public override MessageProperties Properties
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return this.properties;
+ }
+ }
+
+ public override MessageVersion Version
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return MessageVersion.None;
+ }
+ }
+
+ protected override void OnBodyToString(XmlDictionaryWriter writer)
+ {
+ if (this.bodyStream != null)
+ {
+ writer.WriteString("Stream");
+ }
+ else
+ {
+ writer.WriteStartElement(RawMessageEncoder.StreamElementName, string.Empty);
+ writer.WriteBase64(this.bodyBytes, this.index, this.count);
+ writer.WriteEndElement();
+ }
+ }
+
+ protected override void OnClose()
+ {
+ Exception deferEx = null;
+ try
+ {
+ base.OnClose();
+ }
+ catch (Exception e)
+ {
+ deferEx = e;
+ }
+
+ try
+ {
+ if (this.properties != null)
+ {
+ this.properties.Dispose();
+ }
+ }
+ catch (Exception e)
+ {
+ if (deferEx == null)
+ {
+ deferEx = e;
+ }
+ }
+
+ try
+ {
+ if (this.bufferManager != null)
+ {
+ this.bufferManager.ReturnBuffer(this.bodyBytes);
+ this.bufferManager = null;
+ }
+ }
+ catch (Exception e)
+ {
+ if (deferEx == null)
+ {
+ deferEx = e;
+ }
+ }
+
+ if (deferEx != null)
+ {
+ throw deferEx;
+ }
+ }
+
+ protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
+ {
+ if (this.bodyStream != null)
+ {
+ int len = (int)this.bodyStream.Length;
+ byte[] buf = new byte[len];
+ this.bodyStream.Read(buf, 0, len);
+ this.bodyStream = null;
+ this.bodyBytes = buf;
+ this.count = len;
+ this.index = 0;
+ }
+ else
+ {
+ if (this.bufferManager != null)
+ {
+ // we could take steps to share the buffer among copies and release the memory
+ // after the last user finishes by a reference count or such, but we are already
+ // far from the intended optimized use. Make one GC managed memory copy that is
+ // shared by all.
+ byte[] buf = new byte[this.count];
+
+ Buffer.BlockCopy(this.bodyBytes, this.index, buf, 0, this.count);
+ this.bufferManager.ReturnBuffer(this.bodyBytes);
+ this.bufferManager = null;
+ this.bodyBytes = buf;
+ this.index = 0;
+ }
+ }
+
+ return new RawMessageBuffer(this.headers, this.properties, this.bodyBytes, this.index, this.count, this.readerQuotas);
+ }
+
+ protected override XmlDictionaryReader OnGetReaderAtBodyContents()
+ {
+ Stream readerStream = null;
+ bool ownsStream;
+
+ if (this.bodyStream != null)
+ {
+ readerStream = this.bodyStream;
+ ownsStream = false;
+ }
+ else
+ {
+ // create stream for duration of XmlReader.
+ ownsStream = true;
+ if (this.bufferManager != null)
+ {
+ readerStream = new RawMemoryStream(this.bodyBytes, this.index, this.count, this.bufferManager);
+ this.bufferManager = null;
+ }
+ else
+ {
+ readerStream = new MemoryStream(this.bodyBytes, this.index, this.count, false);
+ }
+ }
+
+ return new RawXmlReader(readerStream, this.readerQuotas, ownsStream);
+ }
+
+ protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
+ {
+ writer.WriteStartElement(RawMessageEncoder.StreamElementName, string.Empty);
+ if (this.bodyStream != null)
+ {
+ int len = (int)this.bodyStream.Length;
+ byte[] buf = new byte[len];
+ this.bodyStream.Read(buf, 0, len);
+ writer.WriteBase64(buf, 0, len);
+ }
+ else
+ {
+ writer.WriteBase64(this.bodyBytes, this.index, this.count);
+ }
+
+ writer.WriteEndElement();
+ }
+
+ private class RawMemoryStream : MemoryStream
+ {
+ private BufferManager bufferManager;
+ private byte[] buffer;
+
+ public RawMemoryStream(byte[] bytes, int index, int count, BufferManager mgr)
+ : base(bytes, index, count, false)
+ {
+ this.bufferManager = mgr;
+ this.buffer = bytes;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (this.bufferManager != null)
+ {
+ try
+ {
+ this.bufferManager.ReturnBuffer(this.buffer);
+ }
+ finally
+ {
+ this.bufferManager = null;
+ base.Dispose(disposing);
+ }
+ }
+ }
+ }
+
+ private class RawMessageBuffer : MessageBuffer
+ {
+ private bool closed;
+ private MessageHeaders headers;
+ private MessageProperties properties;
+ private byte[] bodyBytes;
+ private int index;
+ private int count;
+ private XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawMessageBuffer(MessageHeaders headers, MessageProperties properties, byte[] bytes, int index, int count, XmlDictionaryReaderQuotas quotas)
+ : base()
+ {
+ this.headers = new MessageHeaders(headers);
+ this.properties = new MessageProperties(properties);
+ this.bodyBytes = bytes;
+ this.index = index;
+ this.count = count;
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ quotas.CopyTo(this.readerQuotas);
+ }
+
+ public override int BufferSize
+ {
+ get { return this.count; }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.headers = null;
+ if (this.properties != null)
+ {
+ this.properties.Dispose();
+ this.properties = null;
+ }
+
+ this.bodyBytes = null;
+ this.readerQuotas = null;
+ }
+ }
+
+ public override Message CreateMessage()
+ {
+ if (this.closed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return new RawMessage(this.headers, this.properties, this.bodyBytes, this.index, this.count, this.readerQuotas);
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs
new file mode 100644
index 0000000000..76dae6f6c7
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs
@@ -0,0 +1,113 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel;
+ using System.Xml;
+
+
+ class RawMessageEncoder : MessageEncoder
+ {
+ public const string StreamElementName = "Binary";
+
+ XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawMessageEncoder(XmlDictionaryReaderQuotas quotas)
+ {
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ if (quotas != null)
+ {
+ quotas.CopyTo(this.readerQuotas);
+ }
+ }
+
+ public override string ContentType
+ {
+ get { return null; }
+ }
+
+ public override bool IsContentTypeSupported(string contentType)
+ {
+ return true;
+ }
+
+ public override string MediaType
+ {
+ get { return null; }
+ }
+
+ public override MessageVersion MessageVersion
+ {
+ get { return MessageVersion.None; }
+ }
+
+ public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
+ {
+ RawMessage message = new RawMessage(buffer.Array, buffer.Offset, buffer.Count, bufferManager, readerQuotas);
+ message.Properties.Encoder = this;
+ return message;
+ }
+
+ public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
+ {
+ RawMessage message = new RawMessage(stream, readerQuotas);
+ message.Properties.Encoder = this;
+ return message;
+ }
+
+ private void CheckType(XmlDictionaryReader reader, XmlNodeType type)
+ {
+ if (reader.NodeType != type)
+ {
+ throw new System.IO.InvalidDataException(String.Format("RawMessageEncoder xml check {0} type should be {1}", type, reader.NodeType));
+ }
+ }
+
+ public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
+ {
+ MemoryStream tempStream = new MemoryStream();
+ this.WriteMessage(message, tempStream);
+ int len = messageOffset + (int)tempStream.Length;
+ byte[] buf = bufferManager.TakeBuffer(len);
+ MemoryStream targetStream = new MemoryStream(buf);
+ if (messageOffset > 0)
+ {
+ targetStream.Seek(messageOffset, SeekOrigin.Begin);
+ }
+
+ tempStream.WriteTo(targetStream);
+ targetStream.Close();
+
+ return new ArraySegment<byte>(buf, messageOffset, len - messageOffset);
+ }
+
+ public override void WriteMessage(Message message, Stream stream)
+ {
+ using (XmlWriter writer = new RawXmlWriter(stream))
+ {
+ message.WriteMessage(writer);
+ writer.Flush();
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs
new file mode 100644
index 0000000000..5c015f9a1b
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Xml;
+ using System.ServiceModel.Channels;
+
+ internal class RawMessageEncoderFactory : MessageEncoderFactory
+ {
+ RawMessageEncoder encoder;
+
+ public RawMessageEncoderFactory(XmlDictionaryReaderQuotas quotas)
+ {
+ this.encoder = new RawMessageEncoder(quotas);
+ }
+
+ public override MessageEncoder Encoder
+ {
+ get { return this.encoder; }
+ }
+
+ public override MessageVersion MessageVersion
+ {
+ get { return encoder.MessageVersion; }
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs
new file mode 100644
index 0000000000..5ec10a976d
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs
@@ -0,0 +1,102 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel.Channels;
+
+ public class RawMessageEncodingBindingElement : MessageEncodingBindingElement
+ {
+
+ public RawMessageEncodingBindingElement()
+ : base()
+ {
+ }
+
+ RawMessageEncodingBindingElement(RawMessageEncodingBindingElement originalBindingElement)
+ {
+ }
+
+ public override MessageEncoderFactory CreateMessageEncoderFactory()
+ {
+ return new RawMessageEncoderFactory(null);
+ }
+
+
+ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.BuildInnerChannelFactory<TChannel>();
+ }
+
+ public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ return context.CanBuildInnerChannelFactory<TChannel>();
+ }
+
+ public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.BuildInnerChannelListener<TChannel>();
+ }
+
+ public override bool CanBuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.CanBuildInnerChannelListener<TChannel>();
+ }
+
+
+ public override BindingElement Clone()
+ {
+ return new RawMessageEncodingBindingElement(this);
+ }
+
+
+
+ public override MessageVersion MessageVersion
+ {
+ get
+ {
+ return MessageVersion.None;
+ }
+
+ set
+ {
+ if (value != MessageVersion.None)
+ throw new ArgumentException("Unsupported message version");
+ }
+ }
+
+
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs
new file mode 100644
index 0000000000..8fadfce441
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs
@@ -0,0 +1,353 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.Xml;
+
+ internal class RawXmlReader : XmlDictionaryReader
+ {
+ ////this class presents a hardcoded XML InfoSet: "<rawtag>X</rawtag>" where X is the entire stream content
+
+ private Stream stream;
+ private bool closed;
+ private bool streamOwner;
+ private ReaderPosition position;
+ private string contentAsBase64;
+ private XmlNameTable xmlNameTable;
+ private XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawXmlReader(Stream stream, XmlDictionaryReaderQuotas quotas, bool streamOwner)
+ {
+ this.stream = stream;
+ this.streamOwner = streamOwner;
+ if (quotas == null)
+ {
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ }
+ else
+ {
+ this.readerQuotas = quotas;
+ }
+ }
+
+ private enum ReaderPosition
+ {
+ None,
+ StartElement,
+ Content,
+ EndElement,
+ EOF
+ }
+
+ public override int AttributeCount
+ {
+ get { return 0; }
+ }
+
+ public override string BaseURI
+ {
+ get { return string.Empty; }
+ }
+
+ public override int Depth
+ {
+ get { return (this.position == ReaderPosition.Content) ? 1 : 0; }
+ }
+
+ public override bool EOF
+ {
+ get { return this.position == ReaderPosition.EOF; }
+ }
+
+ public override bool HasAttributes
+ {
+ get { return false; }
+ }
+
+ public override bool HasValue
+ {
+ get { return this.position == ReaderPosition.Content; }
+ }
+
+ public override bool IsEmptyElement
+ {
+ get { return false; }
+ }
+
+ public override string LocalName
+ {
+ get
+ {
+ if (this.position == ReaderPosition.StartElement)
+ {
+ return RawMessageEncoder.StreamElementName;
+ }
+
+ return null;
+ }
+ }
+
+ public override string NamespaceURI
+ {
+ get { return string.Empty; }
+ }
+
+ public override XmlNameTable NameTable
+ {
+ get
+ {
+ if (this.xmlNameTable == null)
+ {
+ this.xmlNameTable = new NameTable();
+ this.xmlNameTable.Add(RawMessageEncoder.StreamElementName);
+ }
+
+ return this.xmlNameTable;
+ }
+ }
+
+ public override XmlNodeType NodeType
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.StartElement:
+ return XmlNodeType.Element;
+ case ReaderPosition.Content:
+ return XmlNodeType.Text;
+ case ReaderPosition.EndElement:
+ return XmlNodeType.EndElement;
+ default:
+ // and StreamPosition.EOF
+ return XmlNodeType.None;
+ }
+ }
+ }
+
+ public override string Prefix
+ {
+ get { return string.Empty; }
+ }
+
+ public override ReadState ReadState
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.None:
+ return ReadState.Initial;
+ case ReaderPosition.StartElement:
+ case ReaderPosition.Content:
+ case ReaderPosition.EndElement:
+ return ReadState.Interactive;
+ case ReaderPosition.EOF:
+ return ReadState.Closed;
+ default:
+ return ReadState.Error;
+ }
+ }
+ }
+
+ public override string Value
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.Content:
+ if (this.contentAsBase64 == null)
+ {
+ this.contentAsBase64 = Convert.ToBase64String(this.ReadContentAsBase64());
+ }
+
+ return this.contentAsBase64;
+
+ default:
+ return string.Empty;
+ }
+ }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.position = ReaderPosition.EOF;
+ this.readerQuotas = null;
+ if (this.streamOwner)
+ {
+ this.stream.Close();
+ }
+ }
+ }
+
+ public override string GetAttribute(int i)
+ {
+ throw new ArgumentOutOfRangeException("i", i, "Argument not in set of valid values");
+ }
+
+ public override string GetAttribute(string name, string namespaceURI)
+ {
+ return null;
+ }
+
+ public override string GetAttribute(string name)
+ {
+ return null;
+ }
+
+ public override string LookupNamespace(string prefix)
+ {
+ if (prefix == string.Empty)
+ {
+ return string.Empty;
+ }
+ else if (prefix == "xml")
+ {
+ return "http://www.w3.org/XML/1998/namespace";
+ }
+ else if (prefix == "xmlns")
+ {
+ return "http://www.w3.org/2000/xmlns/";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public override bool MoveToAttribute(string name, string ns)
+ {
+ return false;
+ }
+
+ public override bool MoveToAttribute(string name)
+ {
+ return false;
+ }
+
+ public override bool MoveToElement()
+ {
+ if (this.position == ReaderPosition.None)
+ {
+ this.position = ReaderPosition.StartElement;
+ return true;
+ }
+
+ return false;
+ }
+
+ public override bool MoveToFirstAttribute()
+ {
+ return false;
+ }
+
+ public override bool MoveToNextAttribute()
+ {
+ return false;
+ }
+
+ public override bool Read()
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.None:
+ this.position = ReaderPosition.StartElement;
+ return true;
+ case ReaderPosition.StartElement:
+ this.position = ReaderPosition.Content;
+ return true;
+ case ReaderPosition.Content:
+ this.position = ReaderPosition.EndElement;
+ return true;
+ case ReaderPosition.EndElement:
+ this.position = ReaderPosition.EOF;
+ return false;
+ case ReaderPosition.EOF:
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ public override bool ReadAttributeValue()
+ {
+ return false;
+ }
+
+ public override int ReadContentAsBase64(byte[] buffer, int index, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (this.position != ReaderPosition.Content)
+ {
+ throw new InvalidOperationException("XML reader not in Element");
+ }
+
+ if (count == 0)
+ {
+ return 0;
+ }
+
+ int readCount = this.stream.Read(buffer, index, count);
+ if (readCount == 0)
+ {
+ this.position = ReaderPosition.EndElement;
+ }
+
+ return readCount;
+ }
+
+ public override int ReadContentAsBinHex(byte[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void ResolveEntity()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override bool TryGetBase64ContentLength(out int length)
+ {
+ // The whole stream is this one element
+ if (!this.closed && this.stream.CanSeek)
+ {
+ long streamLength = this.stream.Length;
+ if (streamLength <= int.MaxValue)
+ {
+ length = (int)streamLength;
+ return true;
+ }
+ }
+
+ length = -1;
+ return false;
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs b/qpid/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs
new file mode 100644
index 0000000000..7d05b70807
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs
@@ -0,0 +1,221 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.Xml;
+
+ internal sealed class RawXmlWriter : XmlDictionaryWriter
+ {
+
+ WriteState state;
+ Stream stream;
+ bool closed;
+ bool rawWritingEnabled;
+
+ public RawXmlWriter(Stream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("Stream");
+ }
+
+ this.stream = stream;
+ this.state = WriteState.Start;
+ }
+
+ public override WriteState WriteState
+ {
+ get
+ {
+ return this.state;
+ }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.state = WriteState.Closed;
+ this.rawWritingEnabled = false;
+ }
+ }
+
+ public override void Flush()
+ {
+ this.ThrowIfClosed();
+ this.stream.Flush();
+ }
+
+ public override string LookupPrefix(string ns)
+ {
+ return null;
+ }
+
+ public override void WriteBase64(byte[] buffer, int index, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ ThrowIfClosed();
+
+ if (!this.rawWritingEnabled)
+ {
+ throw new InvalidOperationException("XmlWriter not in Element");
+ }
+
+ this.stream.Write(buffer, index, count);
+ this.state = WriteState.Content;
+ }
+
+ public override void WriteStartElement(string prefix, string localName, string ns)
+ {
+ ThrowIfClosed();
+ if (this.state != WriteState.Start)
+ {
+ throw new InvalidOperationException("Start Element Already Called");
+ }
+
+ if (!string.IsNullOrEmpty(prefix) || !string.IsNullOrEmpty(ns) || localName != RawMessageEncoder.StreamElementName)
+ {
+ throw new XmlException("Wrong XML Start Element Name");
+ }
+ this.state = WriteState.Element;
+ this.rawWritingEnabled = true;
+ }
+
+ public override void WriteEndElement()
+ {
+ ThrowIfClosed();
+ if (!this.rawWritingEnabled)
+ {
+ throw new InvalidOperationException("Unexpected End Element");
+ }
+ this.rawWritingEnabled = false;
+ }
+
+ public override void WriteFullEndElement()
+ {
+ this.WriteEndElement();
+ }
+
+ public override void WriteEndDocument()
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ public override void WriteStartDocument()
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ public override void WriteStartDocument(bool standalone)
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ private void ThrowIfClosed()
+ {
+ if (this.closed)
+ {
+ throw new InvalidOperationException("XML Writer closed");
+ }
+ }
+
+
+ public override void WriteString(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteCData(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteCharEntity(char ch)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteChars(char[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteComment(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteDocType(string name, string pubid, string sysid, string subset)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteEndAttribute()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteEntityRef(string name)
+ {
+ throw new NotSupportedException();
+ }
+
+
+ public override void WriteProcessingInstruction(string name, string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteRaw(string data)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteRaw(char[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteStartAttribute(string prefix, string localName, string ns)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteSurrogateCharEntity(char lowChar, char highChar)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteWhitespace(string ws)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp b/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp
new file mode 100644
index 0000000000..02d6c7ab18
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp
@@ -0,0 +1,165 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/framing/FrameSet.h"
+
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+
+// Note on locks: Use "this" for fast counting and idle/busy
+// notifications. Use the "sessions" list to serialize session
+// creation/reaping and overall tear down.
+// TODO: switch "this" lock to separate non-visible Object.
+
+
+AmqpConnection::AmqpConnection(String^ server, int port) :
+ connectionp(NULL),
+ busyCount(0),
+ disposed(false)
+{
+ bool success = false;
+ System::Exception^ openException = nullptr;
+ sessions = gcnew Collections::Generic::List<AmqpSession^>();
+
+ try {
+ connectionp = new Connection;
+ connectionp->open (QpidMarshal::ToNative(server), port);
+ // TODO: registerFailureCallback for failover
+ success = true;
+ const ConnectionSettings& settings = connectionp->getNegotiatedSettings();
+ this->maxFrameSize = settings.maxFrameSize;
+ } catch (const qpid::Exception& error) {
+ String^ errmsg = gcnew String(error.what());
+ openException = gcnew QpidException(errmsg);
+ } finally {
+ if (!success) {
+ Cleanup();
+ if (openException == nullptr) {
+ openException = gcnew QpidException ("unknown connection failure");
+ }
+ throw openException;
+ }
+ }
+}
+
+void AmqpConnection::Cleanup()
+{
+ {
+ lock l(sessions);
+ if (disposed)
+ return;
+ disposed = true;
+ }
+
+ try {
+ // let the child sessions clean up
+ for each(AmqpSession^ s in sessions) {
+ s->ConnectionClosed();
+ }
+ }
+ finally
+ {
+ if (connectionp != NULL) {
+ connectionp->close();
+ delete connectionp;
+ connectionp = NULL;
+ }
+ }
+}
+
+AmqpConnection::~AmqpConnection()
+{
+ Cleanup();
+}
+
+AmqpConnection::!AmqpConnection()
+{
+ Cleanup();
+}
+
+void AmqpConnection::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+AmqpSession^ AmqpConnection::CreateSession()
+{
+ lock l(sessions);
+ if (disposed) {
+ throw gcnew ObjectDisposedException("AmqpConnection");
+ }
+ AmqpSession^ session = gcnew AmqpSession(this, connectionp);
+ sessions->Add(session);
+ return session;
+}
+
+// called whenever a child session becomes newly busy (a first reader or writer since last idle)
+
+void AmqpConnection::NotifyBusy()
+{
+ bool changed = false;
+ {
+ lock l(this);
+ if (busyCount++ == 0)
+ changed = true;
+ }
+}
+
+// called whenever a child session becomes newly idle (a last reader or writer has closed)
+// The connection is idle when none of its child sessions are busy
+
+void AmqpConnection::NotifyIdle()
+{
+ bool connectionIdle = false;
+ {
+ lock l(this);
+ if (--busyCount == 0)
+ connectionIdle = true;
+ }
+ if (connectionIdle) {
+ OnConnectionIdle(this, System::EventArgs::Empty);
+ }
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.h b/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.h
new file mode 100644
index 0000000000..2641391e82
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpConnection.h
@@ -0,0 +1,71 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace std;
+using namespace qpid::client;
+
+ref class AmqpSession;
+
+public delegate void ConnectionIdleEventHandler(Object^ sender, EventArgs^ eventArgs);
+
+public ref class AmqpConnection
+{
+private:
+ Connection* connectionp;
+ void Cleanup();
+ bool disposed;
+ Collections::Generic::List<AmqpSession^>^ sessions;
+ bool isOpen;
+ int busyCount;
+ int maxFrameSize;
+
+ internal:
+ void NotifyBusy();
+ void NotifyIdle();
+
+ property int MaxFrameSize {
+ int get () { return maxFrameSize; }
+ }
+
+public:
+ AmqpConnection(System::String^ server, int port);
+ ~AmqpConnection();
+ !AmqpConnection();
+ void Close();
+ AmqpSession^ CreateSession();
+ event ConnectionIdleEventHandler^ OnConnectionIdle;
+
+ property bool IsOpen {
+ bool get() { return isOpen; }
+ };
+
+ property bool IsIdle {
+ bool get() { return (busyCount == 0); }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp b/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp
new file mode 100644
index 0000000000..5c333aff60
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+AmqpMessage::AmqpMessage(MessageBodyStream ^mbs) :
+ messageBodyStream(mbs),
+ disposed(false)
+{
+}
+
+void AmqpMessage::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ messageBodyStream->Close();
+}
+
+AmqpMessage::~AmqpMessage()
+{
+ Cleanup();
+}
+
+AmqpMessage::!AmqpMessage()
+{
+ Cleanup();
+}
+
+void AmqpMessage::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.h b/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.h
new file mode 100644
index 0000000000..f0801d30dc
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpMessage.h
@@ -0,0 +1,61 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+
+
+public ref class AmqpMessage
+{
+private:
+ MessageBodyStream^ messageBodyStream;
+ AmqpTypes::AmqpProperties^ amqpProperties;
+ bool disposed;
+ void Cleanup();
+
+internal:
+ AmqpMessage(MessageBodyStream ^bstream);
+
+public:
+ ~AmqpMessage();
+ !AmqpMessage();
+ void Close();
+
+ property AmqpTypes::AmqpProperties^ Properties {
+ AmqpTypes::AmqpProperties^ get () { return amqpProperties; }
+ void set(AmqpTypes::AmqpProperties^ p) { amqpProperties = p; }
+ }
+
+ property System::IO::Stream^ BodyStream {
+ System::IO::Stream^ get() { return messageBodyStream; }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
new file mode 100644
index 0000000000..bab73da74e
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
@@ -0,0 +1,287 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/client/Message.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/client/Future.h"
+
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "AmqpMessage.h"
+#include "MessageBodyStream.h"
+#include "InputLink.h"
+#include "OutputLink.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+
+AmqpSession::AmqpSession(AmqpConnection^ conn, qpid::client::Connection* qpidConnectionp) :
+ connection(conn),
+ sessionp(NULL),
+ sessionImplp(NULL),
+ subs_mgrp(NULL),
+ openCount(0)
+{
+ bool success = false;
+
+ try {
+ sessionp = new qpid::client::AsyncSession;
+ *sessionp = qpidConnectionp->newSession();
+ subs_mgrp = new SubscriptionManager (*sessionp);
+ success = true;
+ waiters = gcnew Collections::Generic::List<CompletionWaiter^>();
+ } finally {
+ if (!success) {
+ Cleanup();
+ throw gcnew QpidException ("session creation failure");
+ }
+ }
+}
+
+
+void AmqpSession::Cleanup()
+{
+ if (subscriptionp != NULL) {
+ subscriptionp->cancel();
+ delete subscriptionp;
+ subscriptionp=NULL;
+ }
+
+ if (subs_mgrp != NULL) {
+ subs_mgrp->stop();
+ delete subs_mgrp;
+ subs_mgrp = NULL;
+ }
+
+ if (localQueuep != NULL) {
+ delete localQueuep;
+ localQueuep = NULL;
+ }
+
+ if (sessionp != NULL) {
+ sessionp->close();
+ delete sessionp;
+ sessionp = NULL;
+ sessionImplp = NULL;
+ }
+
+ if (connectionp != NULL) {
+ connectionp->close();
+ delete connectionp;
+ connectionp = NULL;
+ }
+}
+
+
+// Called by the parent AmqpConnection
+
+void AmqpSession::ConnectionClosed()
+{
+ Cleanup();
+}
+
+InputLink^ AmqpSession::CreateInputLink(System::String^ sourceQueue)
+{
+ return CreateInputLink(sourceQueue, true, false, nullptr, nullptr);
+}
+
+InputLink^ AmqpSession::CreateInputLink(System::String^ sourceQueue, bool exclusive, bool temporary,
+ System::String^ filterKey, System::String^ exchange)
+{
+ InputLink^ link = gcnew InputLink (this, sourceQueue, sessionp, subs_mgrp, exclusive, temporary, filterKey, exchange);
+ {
+ lock l(waiters);
+ if (openCount == 0) {
+ connection->NotifyBusy();
+ }
+ openCount++;
+ }
+ return link;
+}
+
+OutputLink^ AmqpSession::CreateOutputLink(System::String^ targetQueue)
+{
+ OutputLink^ link = gcnew OutputLink (this, targetQueue);
+
+ lock l(waiters);
+
+ if (sessionImplp == NULL) {
+ // not needed unless sending messages
+ SessionBase_0_10Access sa(*sessionp);
+ boost::shared_ptr<SessionImpl> sip = sa.get();
+ sessionImplp = sip.get();
+ }
+
+ if (openCount == 0) {
+ connection->NotifyBusy();
+ }
+ openCount++;
+
+ return link;
+}
+
+
+// called whenever a child InputLink or OutputLink is closed or finalized
+void AmqpSession::NotifyClosed()
+{
+ lock l(waiters);
+ openCount--;
+ if (openCount == 0) {
+ connection->NotifyIdle();
+ }
+}
+
+
+CompletionWaiter^ AmqpSession::SendMessage (System::String^ queue, MessageBodyStream ^mbody, TimeSpan timeout, bool async, AsyncCallback^ callback, Object^ state)
+{
+ lock l(waiters);
+ if (sessionp == NULL)
+ throw gcnew ObjectDisposedException("Send");
+
+ // create an AMQP message.transfer command to use with the partial frameset from the MessageBodyStream
+
+ std::string exname = QpidMarshal::ToNative(queue);
+ FrameSet *framesetp = (FrameSet *) mbody->GetFrameSet().ToPointer();
+ uint8_t acceptMode=1;
+ uint8_t acquireMode=0;
+ MessageTransferBody mtcmd(ProtocolVersion(0,10), exname, acceptMode, acquireMode);
+ // ask for a command completion
+ mtcmd.setSync(true);
+
+ //send it
+
+ Future *futurep = NULL;
+ try {
+ futurep = new Future(sessionImplp->send(mtcmd, *framesetp));
+
+ CompletionWaiter^ waiter = nullptr;
+ if (async || (timeout != TimeSpan::MaxValue)) {
+ waiter = gcnew CompletionWaiter(this, timeout, (IntPtr) futurep, callback, state);
+ // waiter is responsible for releasing the Future native resource
+ futurep = NULL;
+ addWaiter(waiter);
+ }
+
+ l.release();
+
+ if (waiter != nullptr)
+ return waiter;
+
+ // synchronous send with no timeout: no need to involve the asyncHelper thread
+
+ internalWaitForCompletion((IntPtr) futurep);
+ }
+ finally {
+ if (futurep != NULL)
+ delete (futurep);
+ }
+ return nullptr;
+}
+
+void AmqpSession::Bind(System::String^ queue, System::String^ exchange, System::String^ filterKey)
+{
+ sessionp->exchangeBind(arg::queue=QpidMarshal::ToNative(queue),
+ arg::exchange=QpidMarshal::ToNative(exchange),
+ arg::bindingKey=QpidMarshal::ToNative(filterKey));
+
+}
+
+
+void AmqpSession::internalWaitForCompletion(IntPtr fp)
+{
+ lock l(waiters);
+ if (sessionp == NULL)
+ throw gcnew ObjectDisposedException("AmqpSession");
+
+ // increment the smart pointer count to sessionImplp to guard agains async close
+ Session sessionCopy(*sessionp);
+
+ l.release();
+ // Qpid native lib call to wait for the command completion
+ ((Future *)fp.ToPointer())->wait(*sessionImplp);
+}
+
+// call with lock held
+void AmqpSession::addWaiter(CompletionWaiter^ waiter)
+{
+ waiters->Add(waiter);
+ if (!helperRunning) {
+ helperRunning = true;
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &AmqpSession::asyncHelper));
+ }
+}
+
+
+void AmqpSession::removeWaiter(CompletionWaiter^ waiter)
+{
+ // a waiter can be removed from anywhere in the list if timed out
+
+ lock l(waiters);
+ int idx = waiters->IndexOf(waiter);
+ if (idx == -1) {
+ // TODO: assert or log
+ }
+ else {
+ waiters->RemoveAt(idx);
+ }
+}
+
+
+// process CompletionWaiter list one at a time.
+
+void AmqpSession::asyncHelper(Object ^unused)
+{
+ lock l(waiters);
+
+ while (true) {
+ if (waiters->Count == 0) {
+ helperRunning = false;
+ return;
+ }
+
+ CompletionWaiter^ waiter = waiters[0];
+ l.release();
+ // can block, but for short time
+ // the waiter removes itself from the list, possibly as the timer thread on timeout
+ waiter->Run();
+ l.acquire();
+ }
+}
+
+
+}}} // namespace Apache::Qpid::Cli
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h
new file mode 100644
index 0000000000..b959a4123a
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AmqpSession.h
@@ -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.
+*/
+
+#pragma once
+
+#include "AmqpConnection.h"
+#include "MessageBodyStream.h"
+#include "CompletionWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+ref class InputLink;
+ref class OutputLink;
+
+public ref class AmqpSession
+{
+private:
+ AmqpConnection^ connection;
+ Connection* connectionp;
+ AsyncSession* sessionp;
+ SessionImpl* sessionImplp;
+ SubscriptionManager* subs_mgrp;
+ Subscription* subscriptionp;
+ LocalQueue* localQueuep;
+ Collections::Generic::List<CompletionWaiter^>^ waiters;
+ bool helperRunning;
+ int openCount;
+
+ void Cleanup();
+ void asyncHelper(Object ^);
+ void addWaiter(CompletionWaiter^ waiter);
+
+public:
+ OutputLink^ CreateOutputLink(System::String^ targetQueue);
+ InputLink^ CreateInputLink(System::String^ sourceQueue);
+
+ // 0-10 specific support
+ InputLink^ CreateInputLink(System::String^ sourceQueue, bool exclusive, bool temporary, System::String^ filterKey, System::String^ exchange);
+ void Bind(System::String^ queue, System::String^ exchange, System::String^ filterKey);
+
+internal:
+ AmqpSession(AmqpConnection^ connection, qpid::client::Connection* qpidConnection);
+ void NotifyClosed();
+ CompletionWaiter^ SendMessage (System::String^ queue, MessageBodyStream ^mbody, TimeSpan timeout, bool async, AsyncCallback^ callback, Object^ state);
+ void ConnectionClosed();
+ void internalWaitForCompletion(IntPtr Future);
+ void removeWaiter(CompletionWaiter^ waiter);
+
+ property AmqpConnection^ Connection {
+ AmqpConnection^ get () { return connection; }
+ }
+
+
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp b/qpid/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp
new file mode 100644
index 0000000000..91c23ae30a
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using namespace System;
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("Apache.Qpid.Interop")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("")];
+[assembly:AssemblyProductAttribute("")];
+[assembly:AssemblyCopyrightAttribute("")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute("1.0.*")];
+
+[assembly:ComVisible(false)];
+
+[assembly:CLSCompliantAttribute(true)];
+
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp
new file mode 100644
index 0000000000..e39ee1b1ae
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp
@@ -0,0 +1,145 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "CompletionWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+// A class to provide IAsyncResult semantics for a qpid AsyncSession command (i.e. 0-10 messageTransfer)
+// when the client session receives a "Completion" notification from the Broker.
+
+
+CompletionWaiter::CompletionWaiter(AmqpSession^ parent, TimeSpan timeSpan, IntPtr future, AsyncCallback^ callback, Object^ state)
+{
+ this->qpidFuture = future;
+ this->asyncCallback = callback;
+ this->state = state;
+ this->parent = parent;
+ this->thisLock = gcnew Object();
+ // do this after the Completion Waiter is fully initialized, in case of
+ // very small timespan
+ if (timeSpan != TimeSpan::MaxValue) {
+ this->timer = gcnew Timer(timeoutCallback, this, timeSpan, TimeSpan::FromMilliseconds(-1));
+ }
+}
+
+
+void CompletionWaiter::WaitForCompletion()
+{
+ if (isCompleted)
+ return;
+
+ lock l(thisLock);
+ while (!isCompleted) {
+ Monitor::Wait(thisLock);
+ }
+}
+
+void CompletionWaiter::Run()
+{
+ // no locks required in this method
+ if (isCompleted)
+ return;
+
+ try {
+ // Wait for the arrival of the "AMQP Completion" indication from the Broker
+ parent->internalWaitForCompletion(qpidFuture);
+ }
+ catch (System::Exception^ e) {
+ runException = e;
+ }
+ finally {
+ delete(qpidFuture.ToPointer());
+ qpidFuture = (IntPtr) NULL;
+ }
+
+ if (timer != nullptr) {
+ timer->~Timer();
+ timer = nullptr;
+ }
+
+ Complete(false);
+}
+
+
+// "Complete" here means complete the AsyncResult, which may precede broker "command completion" if timed out
+
+void CompletionWaiter::Complete(bool isTimerThread)
+{
+ lock l(thisLock);
+ if (isCompleted)
+ return;
+
+ isCompleted = true;
+ if (isTimerThread)
+ timedOut = true;
+
+ Monitor::PulseAll(thisLock);
+
+ // do this check and signal while locked
+ if (asyncWaitHandle != nullptr)
+ asyncWaitHandle->Set();
+
+ l.release();
+
+ parent->removeWaiter(this);
+
+ if (asyncCallback != nullptr) {
+ // guard against application callback exception
+ try {
+ asyncCallback(this);
+ }
+ catch (System::Exception^) {
+ // log it?
+ }
+ }
+}
+
+
+void CompletionWaiter::TimeoutCallback(Object^ state)
+{
+ CompletionWaiter^ waiter = (CompletionWaiter^) state;
+ waiter->Complete(true);
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
new file mode 100644
index 0000000000..197ac632b0
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
@@ -0,0 +1,99 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+
+public ref class CompletionWaiter : IAsyncResult
+{
+private:
+ bool timedOut;
+ // has an owner thread
+ bool assigned;
+ // can Run (i.e. earlier CompletionWaiters in the queue have completed)
+ System::Exception^ runException;
+ AsyncCallback^ asyncCallback;
+ Threading::Timer ^timer;
+ bool isCompleted;
+ Object^ state;
+ Object^ thisLock;
+ ManualResetEvent^ asyncWaitHandle;
+ AmqpSession^ parent;
+ IntPtr qpidFuture;
+ void Complete(bool isTimerThread);
+ static void TimeoutCallback(Object^ state);
+ static TimerCallback^ timeoutCallback = gcnew TimerCallback(CompletionWaiter::TimeoutCallback);
+
+ internal:
+ CompletionWaiter(AmqpSession^ parent, TimeSpan timeSpan, IntPtr future, AsyncCallback ^callback, Object^ state);
+
+ void Run();
+ void WaitForCompletion();
+
+ property bool Assigned {
+ bool get () { return assigned; }
+ }
+
+ property bool TimedOut {
+ bool get () { return timedOut; }
+ }
+
+
+ public:
+
+ virtual property bool IsCompleted {
+ bool get () { return isCompleted; }
+ }
+
+ virtual property bool CompletedSynchronously {
+ bool get () { return false; }
+ }
+
+ virtual property WaitHandle^ AsyncWaitHandle {
+ WaitHandle^ get () {
+ if (asyncWaitHandle != nullptr) {
+ return asyncWaitHandle;
+ }
+
+ msclr::lock l(thisLock);
+ if (asyncWaitHandle == nullptr) {
+ asyncWaitHandle = gcnew ManualResetEvent(isCompleted);
+ }
+ return asyncWaitHandle;
+ }
+ }
+
+
+ virtual property Object^ AsyncState {
+ Object^ get () { return state; }
+ }
+
+
+
+
+};
+
+}}} // namespace Apache::Qpid::Interop
+
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp
new file mode 100644
index 0000000000..cee394b05d
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.cpp
@@ -0,0 +1,685 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+// Scalability note: When using async methods, an async helper thread is created
+// to block on the Demux BlockingQueue. This design should be revised in line
+// with proposed changes to the native library to reduce the number of servicing
+// threads for large numbers of subscriptions.
+
+
+// The folowing def must match the "Frames" private typedef.
+// TODO, make Qpid-cpp "Frames" definition visible.
+typedef qpid::InlineVector<AMQFrame, 4> FrameSetFrames;
+
+InputLink::InputLink(AmqpSession^ session, System::String^ sourceQueue,
+ qpid::client::AsyncSession *qpidSessionp, qpid::client::SubscriptionManager *qpidSubsMgrp,
+ bool exclusive,
+ bool temporary, System::String^ filterKey, System::String^ exchange) :
+ amqpSession(session),
+ subscriptionp(NULL),
+ localQueuep(NULL),
+ queuePtrp(NULL),
+ dequeuedFrameSetpp(NULL),
+ disposed(false),
+ finalizing(false)
+{
+ bool success = false;
+ System::Exception^ linkException = nullptr;
+
+ waiters = gcnew Collections::Generic::List<MessageWaiter^>();
+
+ try {
+ std::string qname = QpidMarshal::ToNative(sourceQueue);
+
+ if (temporary) {
+ qpidSessionp->queueDeclare(arg::queue=qname, arg::durable=false, arg::autoDelete=true, arg::exclusive=true);
+ qpidSessionp->exchangeBind(arg::exchange=QpidMarshal::ToNative(exchange),
+ arg::queue=qname, arg::bindingKey=QpidMarshal::ToNative(filterKey));
+ qpidSessionp->sync();
+ }
+
+ localQueuep = new LocalQueue;
+ SubscriptionSettings settings;
+ settings.flowControl = FlowControl::messageCredit(0);
+ Subscription sub = qpidSubsMgrp->subscribe(*localQueuep, qname, settings);
+ subscriptionp = new Subscription (sub); // copy smart pointer for later IDisposable cleanup
+
+ // the roundabout way to obtain localQueuep->queue
+ SessionBase_0_10Access sa(*qpidSessionp);
+ boost::shared_ptr<SessionImpl> simpl = sa.get();
+ queuePtrp = new Demux::QueuePtr(simpl->getDemux().get(sub.getName()));
+
+ success = true;
+ } finally {
+ if (!success) {
+ Cleanup();
+ linkException = gcnew QpidException ("InputLink creation failure");
+ throw linkException;
+ }
+ }
+}
+
+void InputLink::ReleaseNative()
+{
+ // involves talking to the Broker unless the connection is broken
+ if (subscriptionp != NULL) {
+ try {
+ subscriptionp->cancel();
+ }
+ catch (const std::exception& error) {
+ // TODO: log this properly
+ std::cout << "shutdown error " << error.what() << std::endl;
+ }
+ }
+
+ // free native mem (or smart pointers) that we own
+ if (subscriptionp != NULL)
+ delete subscriptionp;
+ if (queuePtrp != NULL)
+ delete queuePtrp;
+ if (localQueuep != NULL)
+ delete localQueuep;
+ if (dequeuedFrameSetpp != NULL)
+ delete dequeuedFrameSetpp;
+}
+
+void InputLink::Cleanup()
+{
+ {
+ lock l(waiters);
+ if (disposed)
+ return;
+
+ disposed = true;
+
+ // if the asyncHelper exists and is idle, unblock it
+ if (asyncHelperWaitHandle != nullptr) {
+ asyncHelperWaitHandle->Set();
+ }
+
+ // wakeup anyone waiting for messages
+ if (queuePtrp != NULL)
+ (*queuePtrp)->close();
+
+ try {}
+ finally
+ {
+ ReleaseNative();
+ }
+
+ }
+ amqpSession->NotifyClosed();
+}
+
+InputLink::~InputLink()
+{
+ Cleanup();
+}
+
+InputLink::!InputLink()
+{
+ Cleanup();
+}
+
+void InputLink::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+// call with lock held
+bool InputLink::haveMessage()
+{
+ if (dequeuedFrameSetpp != NULL)
+ return true;
+
+ if (queuePtrp != NULL) {
+ if ((*queuePtrp)->size() > 0)
+ return true;
+ }
+ return false;
+}
+
+IntPtr InputLink::nextLocalMessage()
+{
+ lock l(waiters);
+ if (disposed)
+ return (IntPtr) NULL;
+
+ // A message already pulled off BlockingQueue?
+ if (dequeuedFrameSetpp != NULL) {
+ QpidFrameSetPtr* rv = dequeuedFrameSetpp;
+ dequeuedFrameSetpp = NULL;
+ return (IntPtr) rv;
+ }
+
+ if ((*queuePtrp)->empty())
+ return (IntPtr) NULL;
+
+ bool received = false;
+ QpidFrameSetPtr* frameSetpp = new QpidFrameSetPtr;
+
+ try {
+ received = (*queuePtrp)->pop(*frameSetpp, qpid::sys::TIME_INFINITE);
+ if (received) {
+ QpidFrameSetPtr* rv = frameSetpp;
+ // no need to free native in finally block
+ frameSetpp = NULL;
+ return (IntPtr) rv;
+ }
+ } catch(const std::exception& error) {
+ // should be no async tampering with queue since we hold the lock and have a
+ // smart pointer ref to the native LocalQueue, even if the network connection fails...
+ cout << "unknown exception in InputLink.nextLocalMessage() " << error.what() <<endl;
+ // TODO: log this
+ }
+ finally {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ }
+ }
+
+ return (IntPtr) NULL;
+}
+
+
+
+void InputLink::unblockWaiter()
+{
+ // to be followed by resetQueue() below
+ lock l(waiters);
+ if (disposed)
+ return;
+ (*queuePtrp)->close();
+}
+
+
+
+// Set things right after unblockWaiter(). Closing and opening a Qpid BlockingQueue unsticks
+// a blocking thread without interefering with queue contents or the ability to push
+// new incoming messages.
+
+void InputLink::resetQueue()
+{
+ lock l(waiters);
+ if (disposed)
+ return;
+ if ((*queuePtrp)->isClosed()) {
+ (*queuePtrp)->open();
+ }
+}
+
+
+// returns true if there is a message to consume, i.e. nextLocalMessage() won't block
+
+bool InputLink::internalWaitForMessage()
+{
+ Demux::QueuePtr demuxQueuePtr;
+
+ bool received = false;
+ QpidFrameSetPtr* frameSetpp = NULL;
+ try {
+ lock l(waiters);
+ if (disposed)
+ return false;
+ if (haveMessage())
+ return true;
+
+ // TODO: prefetch window of messages, compatible with both 0-10 and 1.0.
+ subscriptionp->grantMessageCredit(1);
+
+ // get a scoped smart ptr ref to guard against async close or hangup
+ demuxQueuePtr = *queuePtrp;
+ frameSetpp = new QpidFrameSetPtr;
+
+ l.release();
+ // Async cleanup is now possible. Only use demuxQueuePtr until lock reacquired.
+ received = demuxQueuePtr->pop(*frameSetpp, qpid::sys::TIME_INFINITE);
+ l.acquire();
+
+ if (received) {
+ dequeuedFrameSetpp = frameSetpp;
+ frameSetpp = NULL; // native will eventually be freed in Cleanup or MessageBodyStream
+ }
+
+ return true;
+ } catch(const std::exception& ) {
+ // timeout or connection closed
+ return false;
+ }
+ finally {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ }
+ }
+
+ return false;
+}
+
+
+// call with lock held
+void InputLink::addWaiter(MessageWaiter^ waiter)
+{
+ waiters->Add(waiter);
+ if (waiters->Count == 1) {
+ // mark this waiter as ready to run
+ // Only the waiter at the head of the queue is active.
+ waiter->Activate();
+ }
+
+ if (waiter->Assigned)
+ return;
+
+ if (asyncHelperWaitHandle == nullptr) {
+ asyncHelperWaitHandle = gcnew ManualResetEvent(false);
+ ThreadStart^ threadDelegate = gcnew ThreadStart(this, &InputLink::asyncHelper);
+ (gcnew Thread(threadDelegate))->Start();
+ }
+
+ if (waiters->Count == 1) {
+ // wake up the asyncHelper
+ asyncHelperWaitHandle->Set();
+ }
+}
+
+
+void InputLink::removeWaiter(MessageWaiter^ waiter) {
+ // a waiter can be removed from anywhere in the list if timed out
+
+ lock l(waiters);
+ int idx = waiters->IndexOf(waiter);
+ if (idx == -1) {
+ // TODO: assert or log
+ if (asyncHelperWaitHandle != nullptr) {
+ // just in case.
+ asyncHelperWaitHandle->Set();
+ }
+ return;
+ }
+ waiters->RemoveAt(idx);
+
+ // let the next waiter know it's his turn.
+ if (waiters->Count > 0) {
+ MessageWaiter^ nextWaiter = waiters[0];
+
+ // wakeup the asyncHelper thread to help out if necessary.
+ if (!nextWaiter->Assigned) {
+ asyncHelperWaitHandle->Set();
+ }
+
+ l.release();
+ nextWaiter->Activate();
+ return;
+ }
+ else {
+ if (disposed && (asyncHelperWaitHandle != nullptr)) {
+ asyncHelperWaitHandle->Set();
+ }
+ }
+}
+
+
+void InputLink::asyncHelper()
+{
+ lock l(waiters);
+
+ while (true) {
+ if (disposed && (waiters->Count == 0)) {
+ asyncHelperWaitHandle = nullptr;
+ return;
+ }
+
+ if (waiters->Count > 0) {
+ MessageWaiter^ waiter = waiters[0];
+
+ l.release();
+ if (waiter->AcceptForWork()) {
+ waiter->Run();
+ }
+ l.acquire();
+ }
+
+ // sleep if more work may be coming or it is currently someone else's turn
+ if (((waiters->Count == 0) && !disposed) || ((waiters->Count != 0) && waiters[0]->Assigned)) {
+ // wait for something to do
+ asyncHelperWaitHandle->Reset();
+ l.release();
+ asyncHelperWaitHandle->WaitOne();
+ l.acquire();
+ }
+ }
+}
+
+void InputLink::sync()
+{
+ // for the timeout thread
+ lock l(waiters);
+}
+
+
+AmqpMessage^ InputLink::createAmqpMessage(IntPtr msgp)
+{
+ QpidFrameSetPtr* fspp = (QpidFrameSetPtr*) msgp.ToPointer();
+ bool ownFrameSet = true;
+ bool haveProperties = false;
+
+ try {
+ MessageBodyStream^ mstream = gcnew MessageBodyStream(fspp);
+ ownFrameSet = false; // stream releases on close/dispose
+
+ AmqpMessage^ amqpMessage = gcnew AmqpMessage(mstream);
+
+ AMQHeaderBody* headerBodyp = (*fspp)->getHeaders();
+ uint64_t contentSize = (*fspp)->getContentSize();
+ SequenceSet frameSetID((*fspp)->getId());
+
+ // target managed representation
+ AmqpProperties^ amqpProperties = gcnew AmqpProperties();
+
+ // source native representation
+ const DeliveryProperties* deliveryProperties = headerBodyp->get<DeliveryProperties>();
+ const qpid::framing::MessageProperties* messageProperties = headerBodyp->get<qpid::framing::MessageProperties>();
+
+ if (deliveryProperties) {
+ if (deliveryProperties->hasRoutingKey()) {
+ haveProperties = true;
+
+ amqpProperties->RoutingKey = gcnew String(deliveryProperties->getRoutingKey().c_str());
+ }
+
+ if (deliveryProperties->hasDeliveryMode()) {
+ if (deliveryProperties->getDeliveryMode() == qpid::framing::PERSISTENT)
+ amqpProperties->Durable = true;
+ }
+
+ if (deliveryProperties->hasTtl()) {
+ long long ticks = deliveryProperties->getTtl() * TimeSpan::TicksPerMillisecond;
+ amqpProperties->TimeToLive = Nullable<TimeSpan>(TimeSpan::FromTicks(ticks));
+ }
+ }
+
+ if (messageProperties) {
+
+ if (messageProperties->hasReplyTo()) {
+ haveProperties = true;
+ const ReplyTo& rpto = messageProperties->getReplyTo();
+ String^ rk = nullptr;
+ String^ ex = nullptr;
+ if (rpto.hasRoutingKey()) {
+ rk = gcnew String(rpto.getRoutingKey().c_str());
+ }
+ if (rpto.hasExchange()) {
+ ex = gcnew String(rpto.getExchange().c_str());
+ }
+ amqpProperties->SetReplyTo(ex,rk);
+ }
+
+ if (messageProperties->hasContentType()) {
+ haveProperties = true;
+ amqpProperties->ContentType = gcnew String(messageProperties->getContentType().c_str());
+
+ if (messageProperties->hasContentEncoding()) {
+ String^ enc = gcnew String(messageProperties->getContentEncoding().c_str());
+ if (!String::IsNullOrEmpty(enc)) {
+ // TODO: properly assemble 1.0 style to 0-10 for all cases
+ amqpProperties->ContentType += "; charset=" + enc;
+ }
+ }
+ }
+
+ if (messageProperties->hasCorrelationId()) {
+ haveProperties = true;
+ const std::string& ncid = messageProperties->getCorrelationId();
+ int len = ncid.size();
+ array<unsigned char>^ mcid = gcnew array<unsigned char>(len);
+ Marshal::Copy ((IntPtr) (void *) ncid.data(), mcid, 0, len);
+ amqpProperties->CorrelationId = mcid;
+ }
+
+ if (messageProperties->hasUserId()) {
+ haveProperties = true;
+ const std::string& nuid = messageProperties->getUserId();
+ int len = nuid.size();
+ array<unsigned char>^ muid = gcnew array<unsigned char>(len);
+ Marshal::Copy ((IntPtr) (void *) nuid.data(), muid, 0, len);
+ amqpProperties->UserId = muid;
+ }
+
+ if (messageProperties->hasApplicationHeaders()) {
+ haveProperties = true;
+ const qpid::framing::FieldTable& fieldTable = messageProperties->getApplicationHeaders();
+ int count = fieldTable.count();
+
+ if (count > 0) {
+ haveProperties = true;
+ Collections::Generic::Dictionary<System::String^, AmqpType^>^ mmap =
+ gcnew Collections::Generic::Dictionary<System::String^, AmqpType^>(count);
+
+ for(qpid::framing::FieldTable::ValueMap::const_iterator i = fieldTable.begin(); i != fieldTable.end(); i++) {
+
+ qpid::framing::FieldValue::Data &data = i->second->getData();
+
+ // TODO: replace these generic int/string conversions with handler for each AMQP specific type:
+ // uint8_t dataType = i->second->getType();
+ // switch (dataType) { case TYPE_CODE_STR8: ... }
+
+ if (data.convertsToInt()) {
+ mmap->Add (gcnew String(i->first.data()), gcnew AmqpInt((int) i->second->getData().getInt()));
+ }
+ if (data.convertsToString()) {
+ std::string ns = data.getString();
+ String^ ms = gcnew String(ns.data(), 0, ns.size());
+ mmap->Add (gcnew String(i->first.data()), gcnew AmqpString(ms));
+ }
+ }
+
+ amqpProperties->PropertyMap = mmap;
+ }
+
+ }
+ }
+
+ if (haveProperties) {
+ amqpMessage->Properties = amqpProperties;
+ }
+
+ // We have a message we can return to the caller.
+ // Tell the broker we got it.
+ subscriptionp->accept(frameSetID);
+ return amqpMessage;
+ }
+ finally {
+ if (ownFrameSet)
+ delete (fspp);
+ }
+}
+
+ // As for IInputChannel:
+ // if success, return true + amqpMessage
+ // elseif timeout, return false
+ // elseif closed/EOF, return true and amqpMessage = null
+ // else throw an Exception
+
+bool InputLink::TryReceive(TimeSpan timeout, [Out] AmqpMessage^% amqpMessage)
+{
+ lock l(waiters);
+
+ if (waiters->Count == 0) {
+ // see if there is a message already available without blocking
+ IntPtr fspp = nextLocalMessage();
+ if (fspp.ToPointer() != NULL) {
+ amqpMessage = createAmqpMessage(fspp);
+ return true;
+ }
+ }
+
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, true, false, nullptr, nullptr);
+ addWaiter(waiter);
+
+ l.release();
+ waiter->Run();
+ l.acquire();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ IntPtr waiterMsg = waiter->Message;
+ if (waiterMsg.ToPointer() == NULL) {
+ if (disposed) {
+ // indicate normal EOF on channel
+ amqpMessage = nullptr;
+ return true;
+ }
+ }
+
+ amqpMessage = createAmqpMessage(waiterMsg);
+ return true;
+}
+
+IAsyncResult^ InputLink::BeginTryReceive(TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+
+ //TODO: if haveMessage() complete synchronously
+
+ lock l(waiters);
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, true, true, callback, state);
+ addWaiter(waiter);
+ return waiter;
+}
+
+bool InputLink::EndTryReceive(IAsyncResult^ result, [Out] AmqpMessage^% amqpMessage)
+{
+
+ // TODO: validate result
+
+ MessageWaiter^ waiter = (MessageWaiter ^) result;
+
+ waiter->WaitForCompletion();
+
+ if (waiter->RunException != nullptr)
+ throw waiter->RunException;
+
+ if (waiter->TimedOut) {
+ amqpMessage = nullptr;
+ return false;
+ }
+
+ IntPtr waiterMsg = waiter->Message;
+ if (waiterMsg.ToPointer() == NULL) {
+ if (disposed) {
+ // indicate normal EOF on channel
+ amqpMessage = nullptr;
+ return true;
+ }
+ }
+
+ amqpMessage = createAmqpMessage(waiterMsg);
+ return true;
+}
+
+
+bool InputLink::WaitForMessage(TimeSpan timeout)
+{
+ lock l(waiters);
+
+ if (waiters->Count == 0) {
+ // see if there is a message already available without blocking
+ if (haveMessage())
+ return true;
+ }
+
+ // Same as for TryReceive, except consuming = false
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, false, false, nullptr, nullptr);
+ addWaiter(waiter);
+
+ l.release();
+ waiter->Run();
+ l.acquire();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ return true;
+}
+
+IAsyncResult^ InputLink::BeginWaitForMessage(TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+ lock l(waiters);
+
+ // Same as for BeginTryReceive, except consuming = false
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, false, true, callback, state);
+ addWaiter(waiter);
+ return waiter;
+}
+
+bool InputLink::EndWaitForMessage(IAsyncResult^ result)
+{
+ MessageWaiter^ waiter = (MessageWaiter ^) result;
+
+ waiter->WaitForCompletion();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ return true;
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h
new file mode 100644
index 0000000000..366780c137
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/InputLink.h
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+#include "MessageWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+// smart pointer to the low level AMQP 0-10 frames of the message
+typedef qpid::framing::FrameSet::shared_ptr QpidFrameSetPtr;
+
+public ref class InputLink
+{
+private:
+ AmqpSession^ amqpSession;
+ Subscription* subscriptionp;
+ LocalQueue* localQueuep;
+ Demux::QueuePtr* queuePtrp;
+ Collections::Generic::List<MessageWaiter^>^ waiters;
+ bool disposed;
+ bool finalizing;
+ QpidFrameSetPtr* dequeuedFrameSetpp;
+ ManualResetEvent^ asyncHelperWaitHandle;
+
+ void Cleanup();
+ void ReleaseNative();
+ bool haveMessage();
+ void addWaiter(MessageWaiter^ waiter);
+ void asyncHelper();
+ AmqpMessage^ createAmqpMessage(IntPtr msgp);
+
+internal:
+ InputLink(AmqpSession^ session, System::String^ sourceQueue, qpid::client::AsyncSession *qpidSessionp,
+ qpid::client::SubscriptionManager *qpidSubsMgrp, bool exclusive, bool temporary, System::String^ filterKey,
+ System::String^ exchange);
+
+ bool internalWaitForMessage();
+ void unblockWaiter();
+ void resetQueue();
+ IntPtr nextLocalMessage();
+ void removeWaiter(MessageWaiter^ waiter);
+ void sync();
+
+public:
+ ~InputLink();
+ !InputLink();
+ void Close();
+
+ bool TryReceive(TimeSpan timeout, [Out] AmqpMessage ^% amqpMessage);
+ IAsyncResult^ BeginTryReceive(TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ bool EndTryReceive(IAsyncResult^ result, [Out] AmqpMessage^% amqpMessage);
+
+ bool WaitForMessage(TimeSpan timeout);
+ IAsyncResult^ BeginWaitForMessage(TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ bool EndWaitForMessage(IAsyncResult^ result);
+
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj b/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj
new file mode 100644
index 0000000000..32f78c8344
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/Interop.vcproj
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Interop"
+ ProjectGUID="{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}"
+ RootNamespace="Interop"
+ Keyword="ManagedCProj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="copy ..\AmqpTypes\obj\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule $(ConfigurationName)"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/FU Debug\Apache.Qpid.AmqpTypes.netmodule"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\..\cpp\build\include;..\..\..\..\..\cpp\build\src;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_NONSTDC_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;_SCL_SECURE_NO_WARNINGS;BOOST_ALL_DYN_LINK"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="..\..\..\..\..\cpp\build\src\Debug\qpidcommon.lib ..\..\..\..\..\cpp\build\src\Debug\qpidclient.lib Debug\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalDependencies="$(NoInherit)"
+ OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;$(BOOST_ROOT)\lib&quot;"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(NoInherit)"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ <AssemblyReference
+ RelativePath="System.dll"
+ AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.Data.dll"
+ AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.XML.dll"
+ AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.Runtime.Serialization.dll"
+ AssemblyName="System.Runtime.Serialization, Version=3.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="196608"
+ />
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\AmqpConnection.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpMessage.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpSession.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AssemblyInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\CompletionWaiter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\InputLink.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageBodyStream.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageWaiter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\OutputLink.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\AmqpConnection.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpMessage.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpSession.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CompletionWaiter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\InputLink.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageBodyStream.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageWaiter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\OutputLink.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QpidException.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QpidMarshal.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp b/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp
new file mode 100644
index 0000000000..f2cb5740d3
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp
@@ -0,0 +1,337 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
+
+#include "MessageBodyStream.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+// Thefolowing def must match "Frames" private typedef.
+// TODO: make "Frames" publicly visible.
+typedef qpid::InlineVector<AMQFrame, 4> FrameSetFrames;
+
+using namespace std;
+
+static void ThrowIfBadArgs (array<unsigned char>^ buffer, int offset, int count)
+{
+ if (buffer == nullptr)
+ throw gcnew ArgumentNullException("buffer");
+
+ if (offset < 0)
+ throw gcnew ArgumentOutOfRangeException("offset");
+
+ if (count < 0)
+ throw gcnew ArgumentOutOfRangeException("count");
+
+ if ((offset + count) > buffer->Length)
+ throw gcnew ArgumentException("offset + count");
+}
+
+
+// Input stream constructor
+
+MessageBodyStream::MessageBodyStream(FrameSet::shared_ptr *fspp)
+{
+ isInputStream = true;
+ frameSetpp = fspp;
+ fragmentCount = 0;
+ length = 0;
+ position = 0;
+ currentFramep = NULL;
+
+ const std::string *datap; // pointer to the fragment's string variable that holds the content
+
+ for(FrameSetFrames::const_iterator i = (*frameSetpp)->begin(); i != (*frameSetpp)->end(); i++) {
+ if (i->getBody()->type() == CONTENT_BODY) {
+ fragmentCount++;
+ datap = &(i->castBody<AMQContentBody>()->getData());
+ length += datap->size();
+ }
+ }
+
+ // fragmentCount can be zero for an empty message
+
+ fragmentIndex = 0;
+ fragmentPosition = 0;
+
+ if (fragmentCount == 0) {
+ currentFragment = NULL;
+ fragmentLength = 0;
+ }
+ else if (fragmentCount == 1) {
+ currentFragment = datap->data();
+ fragmentLength = (int) length;
+ }
+ else {
+ fragments = gcnew array<IntPtr>(fragmentCount);
+ fragmentIndex = 0;
+ for(FrameSetFrames::const_iterator i = (*frameSetpp)->begin(); i != (*frameSetpp)->end(); i++) {
+ if (i->getBody()->type() == CONTENT_BODY) {
+ datap = &(i->castBody<AMQContentBody>()->getData());
+ fragments[fragmentIndex++] = (IntPtr) (void *) datap;
+ }
+ }
+ fragmentIndex = 0;
+ datap = (const std::string *) fragments[0].ToPointer();
+ currentFragment = datap->data();
+ fragmentLength = datap->size();
+ }
+}
+
+
+int MessageBodyStream::Read(array<unsigned char>^ buffer, int offset, int count)
+{
+ if (!isInputStream)
+ throw gcnew NotSupportedException();
+ if (disposed)
+ throw gcnew ObjectDisposedException("Stream");
+ if (count == 0)
+ return 0;
+ ThrowIfBadArgs(buffer, offset, count);
+
+ int nRead = 0;
+ int remaining = count;
+
+ while (nRead < count) {
+ int fragAvail = fragmentLength - fragmentPosition;
+ int copyCount = min (fragAvail, remaining);
+ if (copyCount == 0) {
+ // no more to read
+ return nRead;
+ }
+
+ // copy from native space
+ IntPtr nativep = (IntPtr) (void *) (currentFragment + fragmentPosition);
+ Marshal::Copy (nativep, buffer, offset, copyCount);
+ nRead += copyCount;
+ remaining -= copyCount;
+ fragmentPosition += copyCount;
+ offset += copyCount;
+
+ // advance to next fragment?
+ if (fragmentPosition == fragmentLength) {
+ if (++fragmentIndex < fragmentCount) {
+ const std::string *datap = (const std::string *) fragments[fragmentIndex].ToPointer();
+ currentFragment = datap->data();
+ fragmentLength = datap->size();
+ fragmentPosition = 0;
+ }
+ }
+ }
+
+ return nRead;
+}
+
+
+void MessageBodyStream::pushCurrentFrame(bool lastFrame)
+{
+ // set flags as in SessionImpl::sendContent.
+ if (currentFramep->getBody()->type() == CONTENT_BODY) {
+
+ if ((fragmentCount == 1) && lastFrame) {
+ // only one content frame
+ currentFramep->setFirstSegment(false);
+ }
+ else {
+ currentFramep->setFirstSegment(false);
+ currentFramep->setLastSegment(true);
+ if (fragmentCount != 1) {
+ currentFramep->setFirstFrame(false);
+ }
+ if (!lastFrame) {
+ currentFramep->setLastFrame(false);
+ }
+ }
+ }
+ else {
+ // the header frame
+ currentFramep->setFirstSegment(false);
+ if (!lastFrame) {
+ // there will be at least one content frame
+ currentFramep->setLastSegment(false);
+ }
+ }
+
+ // add to frame set. This makes a copy and ref counts the body
+ (*frameSetpp)->append(*currentFramep);
+
+ delete currentFramep;
+
+ currentFramep = NULL;
+}
+
+
+IntPtr MessageBodyStream::GetFrameSet()
+{
+ if (currentFramep != NULL) {
+ // No more content. Tidy up the pending (possibly single header) frame.
+ pushCurrentFrame(true);
+ }
+
+ if (frameSetpp == NULL) {
+ return (IntPtr) NULL;
+ }
+
+ // shared_ptr.get()
+ return (IntPtr) (void *) (*frameSetpp).get();
+}
+
+IntPtr MessageBodyStream::GetHeader()
+{
+ return (IntPtr) headerBodyp;
+}
+
+
+// Ouput stream constructor
+
+MessageBodyStream::MessageBodyStream(int maxFrameSize)
+{
+ isInputStream = false;
+
+ maxFrameContentSize = maxFrameSize - AMQFrame::frameOverhead();
+ SequenceNumber unused; // only meaningful on incoming frames
+ frameSetpp = new FrameSet::shared_ptr(new FrameSet(unused));
+ fragmentCount = 0;
+ length = 0;
+ position = 0;
+
+ // header goes first in the outgoing frameset
+
+ boost::intrusive_ptr<AMQBody> headerBody(new AMQHeaderBody);
+ currentFramep = new AMQFrame(headerBody);
+ headerBodyp = static_cast<AMQHeaderBody*>(headerBody.get());
+
+ // mark this header frame as "full" to force the first write to create a new content frame
+ fragmentPosition = maxFrameContentSize;
+}
+
+void MessageBodyStream::Write(array<unsigned char>^ buffer, int offset, int count)
+{
+ if (isInputStream)
+ throw gcnew NotSupportedException();
+ if (disposed)
+ throw gcnew ObjectDisposedException("Stream");
+ if (count == 0)
+ return;
+ ThrowIfBadArgs(buffer, offset, count);
+
+ if (currentFramep == NULL) {
+ // GetFrameSet() has been called and we no longer exclusively own the underlying frames.
+ throw gcnew InvalidOperationException ("Mesage Body output already completed");
+ }
+
+ if (count <= 0)
+ return;
+
+ // keep GC memory movement at bay while copying to native space
+ pin_ptr<unsigned char> pinnedBuf = &buffer[0];
+
+ string *datap;
+
+ int remaining = count;
+ while (remaining > 0) {
+ if (fragmentPosition == maxFrameContentSize) {
+ // move to a new frame, but not until ready to add new content.
+ // zero content is valid, or the final write may exactly fill to maxFrameContentSize
+
+ pushCurrentFrame(false);
+
+ currentFramep = new AMQFrame(AMQContentBody());
+ fragmentPosition = 0;
+ fragmentCount++;
+ }
+
+ int copyCount = min (remaining, (maxFrameContentSize - fragmentPosition));
+ datap = &(currentFramep->castBody<AMQContentBody>()->getData());
+
+ char *outp = (char *) pinnedBuf + offset;
+ if (fragmentPosition == 0) {
+ datap->assign(outp, copyCount);
+ }
+ else {
+ datap->append(outp, copyCount);
+ }
+
+ position += copyCount;
+ fragmentPosition += copyCount;
+ remaining -= copyCount;
+ offset += copyCount;
+ }
+}
+
+
+void MessageBodyStream::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ try {}
+ finally
+ {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ frameSetpp = NULL;
+ }
+ if (currentFramep != NULL) {
+ delete currentFramep;
+ currentFramep = NULL;
+ }
+ }
+}
+
+MessageBodyStream::~MessageBodyStream()
+{
+ Cleanup();
+}
+
+MessageBodyStream::!MessageBodyStream()
+{
+ Cleanup();
+}
+
+void MessageBodyStream::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h b/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h
new file mode 100644
index 0000000000..fa8e3f6bde
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h
@@ -0,0 +1,131 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace std;
+
+
+// This class provides memory streaming of the message body contents
+// between native and managed space. To avoid additional memory copies
+// in native space, it reads and writes directly to the low level Qpid
+// frames.
+
+public ref class MessageBodyStream : System::IO::Stream
+{
+private:
+ bool isInputStream;
+ long long length;
+ long long position;
+
+ // the boost smart pointer that keeps the message body frames in memory
+ FrameSet::shared_ptr *frameSetpp;
+
+ int fragmentCount;
+ int fragmentIndex;
+ const char* currentFragment;
+ int fragmentPosition;
+ int fragmentLength;
+ array<IntPtr>^ fragments;
+
+ int maxFrameContentSize;
+ AMQFrame* currentFramep;
+ void* headerBodyp;
+ bool disposed;
+ bool finalizing;
+ void Cleanup();
+
+internal:
+ // incoming message
+ MessageBodyStream(FrameSet::shared_ptr *fspp);
+ // outgoing message
+ MessageBodyStream(int maxFrameSize);
+ void pushCurrentFrame(bool last);
+public:
+ ~MessageBodyStream();
+ !MessageBodyStream();
+ virtual void Close() override;
+ virtual int Read(
+ [InAttribute] [OutAttribute] array<unsigned char>^ buffer,
+ int offset,
+ int count) override;
+
+ virtual void Write(
+ array<unsigned char>^ buffer,
+ int offset,
+ int count) override;
+
+
+ IntPtr GetFrameSet();
+ IntPtr GetHeader();
+
+ virtual void Flush() override {} // noop
+
+
+ // TODO: see CanSeek below.
+ virtual long long Seek(
+ long long offset,
+ System::IO::SeekOrigin origin) override {throw gcnew System::NotSupportedException(); }
+
+ // TODO: see CanSeek below.
+ virtual void SetLength(
+ long long value) override {throw gcnew System::NotSupportedException(); }
+
+ virtual property long long Length {
+ long long get() override { return length; }
+ };
+
+ virtual property long long Position {
+ long long get() override { return position; }
+ void set(long long p) override { throw gcnew System::NotSupportedException(); }
+ };
+
+
+ virtual property bool CanRead {
+ bool get () override { return isInputStream; }
+ }
+
+ virtual property bool CanWrite {
+ bool get () override { return !isInputStream; }
+ }
+
+ // Note: this class must return true to signal that the Length property works.
+ // Required by the raw message encoder.
+ // "If a class derived from Stream does not support seeking, calls to Length,
+ // SetLength, Position, and Seek throw a NotSupportedException".
+
+ virtual property bool CanSeek {
+ bool get () override { return true; }
+ }
+
+ virtual property bool CanTimeout {
+ bool get () override { return isInputStream; }
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp
new file mode 100644
index 0000000000..f7a28b0692
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp
@@ -0,0 +1,251 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "MessageWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+
+MessageWaiter::MessageWaiter(InputLink^ parent, TimeSpan timeSpan, bool consuming, bool async, AsyncCallback ^callback, Object^ state)
+{
+ this->consuming = consuming;
+ if (!consuming) {
+ GC::SuppressFinalize(this);
+ }
+
+ if (async) {
+ this->async = true;
+ this->asyncCallback = callback;
+ this->state = state;
+ }
+ else {
+ this->assigned = true;
+ }
+ this->parent = parent;
+ this->thisLock = gcnew Object();
+
+ // do this after the Message Waiter is fully initialized, in case of
+ // very small timespan
+ if (timeSpan != TimeSpan::MaxValue) {
+ this->timer = gcnew Timer(timeoutCallback, this, timeSpan, TimeSpan::FromMilliseconds(-1));
+ }
+}
+
+MessageWaiter::~MessageWaiter()
+{
+ if (message != IntPtr::Zero) {
+ try{}
+ finally {
+ delete message.ToPointer();
+ message = IntPtr::Zero;
+ }
+ }
+}
+
+MessageWaiter::!MessageWaiter()
+{
+ this->~MessageWaiter();
+}
+
+
+void MessageWaiter::WaitForCompletion()
+{
+ if (isCompleted)
+ return;
+
+ lock l(thisLock);
+ while (!isCompleted) {
+ Monitor::Wait(thisLock);
+ }
+}
+
+void MessageWaiter::Activate()
+{
+ if (activated)
+ return;
+
+ lock l(thisLock);
+ if (!activated) {
+ activated = true;
+ Monitor::PulseAll(thisLock);
+ }
+}
+
+
+void MessageWaiter::Run()
+{
+ lock l(thisLock);
+
+ // wait until Activate(), i.e. our turn in the waiter list or a timeout
+ while (!activated) {
+ Monitor::Wait(thisLock);
+ }
+ bool haveMessage = false;
+ bool mustReset = false;
+
+ if (!timedOut)
+ blocking = true;
+
+ if (blocking) {
+ l.release();
+
+ try {
+ haveMessage = parent->internalWaitForMessage();
+ }
+ catch (System::Exception^ e) {
+ runException = e;
+ }
+
+ l.acquire();
+ blocking = false;
+ if (timedOut) {
+ // TimeoutCallback() called parent->unblockWaiter()
+ mustReset = true;
+ // let the timer thread move past critical region
+ while (processingTimeout) {
+ Monitor::Wait(thisLock);
+ }
+ }
+ }
+
+ if (timer != nullptr) {
+ timer->~Timer();
+ timer = nullptr;
+ }
+
+ if (haveMessage) {
+ timedOut = false; // for the case timeout and message arrival are essentially tied
+ if (!consuming) {
+ // just waiting
+ haveMessage = false;
+ }
+ }
+
+ if (haveMessage || mustReset) {
+ l.release();
+ if (haveMessage) {
+ // hang on to it for when the async caller gets around to retrieving
+ message = parent->nextLocalMessage();
+ }
+ if (mustReset) {
+ parent->resetQueue();
+ }
+ l.acquire();
+ }
+
+ isCompleted = true;
+ Monitor::PulseAll(thisLock);
+
+ // do this check and signal while locked
+ if (asyncWaitHandle != nullptr)
+ asyncWaitHandle->Set();
+
+ l.release();
+ parent->removeWaiter(this);
+
+
+ if (asyncCallback != nullptr) {
+ // guard against application callback exception
+ try {
+ asyncCallback(this);
+ }
+ catch (System::Exception^) {
+ // log it?
+ }
+ }
+
+}
+
+bool MessageWaiter::AcceptForWork()
+{
+ lock l(thisLock);
+ if (!assigned) {
+ assigned = true;
+ return true;
+ }
+ return false;
+}
+
+void MessageWaiter::TimeoutCallback(Object^ state)
+{
+ MessageWaiter^ waiter = (MessageWaiter^) state;
+ if (waiter->isCompleted)
+ return;
+
+ // make sure parent has finished initializing us before we get going
+ waiter->parent->sync();
+
+ lock l(waiter->thisLock);
+ if (waiter->timer == nullptr) {
+ // the waiter is in the clean up phase and doesn't need a wakeup
+ return;
+ }
+
+ // timedOut, blocking and processingTimeout work as a unit
+ waiter->timedOut = true;
+ if (waiter->blocking) {
+ // let the waiter know that we are busy with an upcoming unblock operation
+ waiter->processingTimeout = true;
+ }
+
+ waiter->Activate();
+
+ if (waiter->processingTimeout) {
+ // call with lock off
+ l.release();
+ waiter->parent->unblockWaiter();
+
+ // synchronize with blocked thread
+ l.acquire();
+ waiter->processingTimeout = false;
+ Monitor::PulseAll(waiter->thisLock);
+ }
+
+ l.release();
+
+ // If waiter has no associated thread, we must move it to completion
+ if (waiter->AcceptForWork()) {
+ waiter->Run(); // does not block since timedOut == true
+ }
+}
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
new file mode 100644
index 0000000000..3eb4919646
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
@@ -0,0 +1,127 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+
+public ref class MessageWaiter : IAsyncResult
+{
+private:
+ // Receive() or WaitForMessage()
+ bool consuming;
+ bool consumed;
+ bool timedOut;
+ bool async;
+ // has an owner thread
+ bool assigned;
+ // can Run (i.e. earlier MessageWaiters in the queue have completed)
+ bool activated;
+ // is making a call to internalWaitForMessage() which (usually) blocks
+ bool blocking;
+ // the timeout timer thread is lurking
+ bool processingTimeout;
+ // the saved exception from within Run() for async delivery
+ System::Exception^ runException;
+ AsyncCallback^ asyncCallback;
+ Threading::Timer ^timer;
+ bool isCompleted;
+ bool completedSynchronously;
+ Object^ state;
+ Object^ thisLock;
+ ManualResetEvent^ asyncWaitHandle;
+ InputLink^ parent;
+ static void TimeoutCallback(Object^ state);
+ static TimerCallback^ timeoutCallback = gcnew TimerCallback(MessageWaiter::TimeoutCallback);
+ IntPtr message;
+ !MessageWaiter();
+ ~MessageWaiter();
+
+ internal:
+ MessageWaiter(InputLink^ parent, TimeSpan timeSpan, bool consuming, bool async, AsyncCallback ^callback, Object^ state);
+
+ void Run();
+ bool AcceptForWork();
+ void Activate();
+ void WaitForCompletion();
+
+// inline void SetCompletedSynchronously (bool v) { completedSynchronously = v; }
+
+ property IntPtr Message {
+ IntPtr get () {
+ if (!consuming || consumed)
+ throw gcnew InvalidOperationException("Message property");
+ consumed = true;
+ IntPtr v = message;
+ message = IntPtr::Zero;
+ GC::SuppressFinalize(this);
+ return v;
+ }
+ // void set (IntPtr v) { message = v; }
+ }
+
+ property bool Assigned {
+ bool get () { return assigned; }
+ }
+
+ property bool TimedOut {
+ bool get () { return timedOut; }
+ }
+
+
+ property System::Exception^ RunException {
+ System::Exception^ get() { return runException; }
+ }
+
+ public:
+
+ virtual property bool IsCompleted {
+ bool get () { return isCompleted; }
+ }
+
+ virtual property bool CompletedSynchronously {
+ bool get () { return completedSynchronously; }
+ }
+
+ virtual property WaitHandle^ AsyncWaitHandle {
+ WaitHandle^ get () {
+ if (asyncWaitHandle != nullptr) {
+ return asyncWaitHandle;
+ }
+
+ msclr::lock l(thisLock);
+ if (asyncWaitHandle == nullptr) {
+ asyncWaitHandle = gcnew ManualResetEvent(isCompleted);
+ }
+ return asyncWaitHandle;
+ }
+ }
+
+ virtual property Object^ AsyncState {
+ Object^ get () { return state; }
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
+
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.cpp b/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.cpp
new file mode 100644
index 0000000000..27725b8207
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.cpp
@@ -0,0 +1,251 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+
+
+#include "AmqpSession.h"
+#include "AmqpMessage.h"
+#include "OutputLink.h"
+#include "QpidMarshal.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+
+OutputLink::OutputLink(AmqpSession^ session, String^ defaultQueue) :
+ amqpSession(session),
+ queue(defaultQueue),
+ disposed(false),
+ maxFrameSize(session->Connection->MaxFrameSize),
+ finalizing(false)
+{
+}
+
+void OutputLink::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ amqpSession->NotifyClosed();
+}
+
+OutputLink::~OutputLink()
+{
+ Cleanup();
+}
+
+OutputLink::!OutputLink()
+{
+ Cleanup();
+}
+
+void OutputLink::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+
+AmqpMessage^ OutputLink::CreateMessage()
+{
+ MessageBodyStream ^mbody = gcnew MessageBodyStream(maxFrameSize);
+ AmqpMessage ^amqpm = gcnew AmqpMessage(mbody);
+ return amqpm;
+}
+
+
+void OutputLink::ManagedToNative(AmqpMessage^ m)
+{
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) m->BodyStream;
+
+ AmqpProperties^ mprops = m->Properties;
+
+ if (mprops != nullptr) {
+ AMQHeaderBody* bodyp = (AMQHeaderBody*) messageBodyStream->GetHeader().ToPointer();
+
+ if (mprops->HasDeliveryProperties) {
+ DeliveryProperties* deliveryPropertiesp = bodyp->get<DeliveryProperties>(true);
+
+ if (mprops->RoutingKey != nullptr) {
+ deliveryPropertiesp->setRoutingKey(QpidMarshal::ToNative(mprops->RoutingKey));
+ }
+
+ if (mprops->Durable) {
+ deliveryPropertiesp->setDeliveryMode(qpid::framing::PERSISTENT);
+ }
+
+ if (mprops->TimeToLive.HasValue) {
+ long long ttl = mprops->TimeToLive.Value.Ticks;
+ bool was_positive = (ttl > 0);
+ if (ttl < 0)
+ ttl = 0;
+ ttl = ttl / TimeSpan::TicksPerMillisecond;
+ if ((ttl == 0) && was_positive)
+ ttl = 1;
+ deliveryPropertiesp->setTtl(ttl);
+ }
+ }
+
+ if (mprops->HasMessageProperties) {
+ qpid::framing::MessageProperties* messagePropertiesp =
+ bodyp->get<qpid::framing::MessageProperties>(true);
+
+ String^ replyToExchange = mprops->ReplyToExchange;
+ String^ replyToRoutingKey = mprops->ReplyToRoutingKey;
+ if ((replyToExchange != nullptr) || (replyToRoutingKey != nullptr)) {
+ qpid::framing::ReplyTo nReplyTo;
+ if (replyToExchange != nullptr) {
+ nReplyTo.setExchange(QpidMarshal::ToNative(replyToExchange));
+ }
+ if (replyToRoutingKey != nullptr) {
+ nReplyTo.setRoutingKey(QpidMarshal::ToNative(replyToRoutingKey));
+ }
+ messagePropertiesp->setReplyTo(nReplyTo);
+ }
+
+ // TODO: properly split 1.0 style to 0-10 content type + encoding
+
+ String^ contentType = mprops->ContentType;
+ if (contentType != nullptr) {
+ String^ type = nullptr;
+ String^ enc = nullptr;
+ int idx = contentType->IndexOf(';');
+ if (idx == -1) {
+ type = contentType;
+ }
+ else {
+ type = contentType->Substring(0, idx);
+ contentType = contentType->Substring(idx + 1);
+ idx = contentType->IndexOf('=');
+ if (idx != -1) {
+ enc = contentType->Substring(idx + 1);
+ enc = enc->Trim();
+ }
+ }
+ if (!String::IsNullOrEmpty(type)) {
+ messagePropertiesp->setContentType(QpidMarshal::ToNative(type));
+ }
+ if (!String::IsNullOrEmpty(enc)) {
+ messagePropertiesp->setContentEncoding(QpidMarshal::ToNative(enc));
+ }
+ }
+
+
+ array<unsigned char>^ mbytes = mprops->CorrelationId;
+ if (mbytes != nullptr) {
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string s((char *) pinnedBuf, mbytes->Length);
+ messagePropertiesp->setCorrelationId(s);
+ }
+
+ mbytes = mprops->UserId;
+ if (mbytes != nullptr) {
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string s((char *) pinnedBuf, mbytes->Length);
+ messagePropertiesp->setUserId(s);
+ }
+
+ if (mprops->HasMappedProperties) {
+ qpid::framing::FieldTable fieldTable;
+ // TODO: add support for abitrary AMQP types
+ for each (Collections::Generic::KeyValuePair<System::String^, AmqpType^> kvp in mprops->PropertyMap) {
+ Type^ type = kvp.Value->GetType();
+ if (type == AmqpInt::typeid) {
+ fieldTable.setInt(QpidMarshal::ToNative(kvp.Key),
+ ((AmqpInt ^) kvp.Value)->Value);
+ }
+ else if (type == AmqpString::typeid) {
+ AmqpString^ str = (AmqpString ^) kvp.Value;
+ // For now, FieldTable supports a single string type
+ fieldTable.setString(QpidMarshal::ToNative(kvp.Key), QpidMarshal::ToNative(str->Value));
+ }
+ }
+
+ messagePropertiesp->setApplicationHeaders(fieldTable);
+ }
+ }
+ }
+}
+
+
+
+void OutputLink::Send(AmqpMessage^ amqpMessage, TimeSpan timeout)
+{
+ // copy properties from managed space to the native counterparts
+ ManagedToNative(amqpMessage);
+
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) amqpMessage->BodyStream;
+ CompletionWaiter^ waiter = amqpSession->SendMessage(queue, messageBodyStream, timeout, false, nullptr, nullptr);
+
+ if (waiter != nullptr) {
+ waiter->WaitForCompletion();
+ if (waiter->TimedOut) {
+ throw gcnew TimeoutException("Receive");
+ }
+ }
+ // else: SendMessage() has already waited for the Completion
+
+}
+
+IAsyncResult^ OutputLink::BeginSend(AmqpMessage^ amqpMessage, TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+ ManagedToNative(amqpMessage);
+
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) amqpMessage->BodyStream;
+ CompletionWaiter^ waiter = amqpSession->SendMessage(queue, messageBodyStream, timeout, true, callback, state);
+ return waiter;
+}
+
+void OutputLink::EndSend(IAsyncResult^ result)
+{
+ CompletionWaiter^ waiter = (CompletionWaiter ^) result;
+ waiter->WaitForCompletion();
+ if (waiter->TimedOut) {
+ throw gcnew TimeoutException("Receive");
+ }
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.h b/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.h
new file mode 100644
index 0000000000..1f049a7412
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/OutputLink.h
@@ -0,0 +1,64 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+
+public ref class OutputLink
+{
+private:
+ AmqpSession^ amqpSession;
+ String^ queue;
+ bool disposed;
+ bool finalizing;
+ void Cleanup();
+ AmqpTypes::AmqpProperties^ defaultProperties;
+ void ManagedToNative(AmqpMessage^ m);
+ int maxFrameSize;
+
+internal:
+ OutputLink(AmqpSession^ session, String^ defaultQueue);
+
+public:
+ ~OutputLink();
+ !OutputLink();
+ void Close();
+ AmqpMessage^ CreateMessage();
+ void Send(AmqpMessage^ m, TimeSpan timeout);
+ IAsyncResult^ BeginSend(AmqpMessage^ amqpMessage, TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ void EndSend(IAsyncResult^ result);
+
+ property AmqpTypes::AmqpProperties^ DefaultProperties {
+ AmqpTypes::AmqpProperties^ get () { return defaultProperties; }
+ void set(AmqpTypes::AmqpProperties^ p) { defaultProperties = p; }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/QpidException.h b/qpid/wcf/src/Apache/Qpid/Interop/QpidException.h
new file mode 100644
index 0000000000..91677a5e73
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/QpidException.h
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+
+public ref class QpidException : System::Exception
+{
+ public:
+
+ QpidException() : System::Exception() {}
+ QpidException(String^ estring) : System::Exception(estring) {}
+
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/src/Apache/Qpid/Interop/QpidMarshal.h b/qpid/wcf/src/Apache/Qpid/Interop/QpidMarshal.h
new file mode 100644
index 0000000000..3e22af7b39
--- /dev/null
+++ b/qpid/wcf/src/Apache/Qpid/Interop/QpidMarshal.h
@@ -0,0 +1,53 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Text;
+
+
+// Helper functions for marshaling.
+
+private ref class QpidMarshal
+{
+ public:
+
+ // marshal_as<T> not available in all Visual Studio editions.
+
+ static std::string ToNative (System::String^ managed) {
+ if (managed->Length == 0) {
+ return std::string();
+ }
+ array<unsigned char>^ mbytes = Encoding::UTF8->GetBytes(managed);
+ if (mbytes->Length == 0) {
+ return std::string();
+ }
+
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string native((char *) pinnedBuf, mbytes->Length);
+ return native;
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs
new file mode 100644
index 0000000000..bf20b5083d
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs
@@ -0,0 +1,190 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class AsyncTest
+ {
+ private const int MessageCount = 20;
+ private const string Queue = "amqp:amq.direct?routingkey=routing_key";
+ private Uri endpoint = new Uri("amqp:message_queue");
+ private TimeSpan standardTimeout = TimeSpan.FromSeconds(10.0); // seconds
+
+ [Test]
+ public void NonTryReceives()
+ {
+ this.SendMessages(this.standardTimeout, this.standardTimeout);
+ this.ReceiveNonTryMessages(this.standardTimeout, this.standardTimeout);
+ }
+
+ [Test]
+ public void TryReceives()
+ {
+ this.SendMessages(this.standardTimeout, this.standardTimeout);
+ this.ReceiveTryMessages(this.standardTimeout, this.standardTimeout);
+ }
+
+ [Test]
+ public void SmallTimeout()
+ {
+ // This code is commented out due to a bug in asynchronous channel open.
+ ////IChannelListener parentListener;
+ ////try
+ ////{
+ //// this.RetrieveAsyncChannel(new Uri("amqp:fake_queue_do_not_create"), TimeSpan.FromMilliseconds(10.0), out parentListener);
+ //// parentListener.Close();
+ //// Assert.Fail("Accepting the channel did not time out.");
+ ////}
+ ////catch (TimeoutException)
+ ////{
+ //// // Intended exception.
+ ////}
+
+ try
+ {
+ this.ReceiveNonTryMessages(this.standardTimeout, TimeSpan.FromMilliseconds(10.0));
+ Assert.Fail("Receiving a message did not time out.");
+ }
+ catch (TimeoutException)
+ {
+ // Intended exception.
+ }
+ }
+
+ private void SendMessages(TimeSpan channelTimeout, TimeSpan messageSendTimeout)
+ {
+ ChannelFactory<IOutputChannel> channelFactory =
+ new ChannelFactory<IOutputChannel>(Util.GetBinding(), Queue);
+ IOutputChannel proxy = channelFactory.CreateChannel();
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+
+ for (int i = 0; i < MessageCount; i++)
+ {
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, i);
+ resultArray[i] = proxy.BeginSend(toSend, messageSendTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ proxy.EndSend(resultArray[j]);
+ }
+
+ IAsyncResult iocCloseResult = proxy.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ proxy.EndClose(iocCloseResult);
+
+ IAsyncResult chanFactCloseResult = channelFactory.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ channelFactory.EndClose(chanFactCloseResult);
+ }
+
+ private void ReceiveNonTryMessages(TimeSpan channelTimeout, TimeSpan messageTimeout)
+ {
+ IChannelListener inputChannelParentListener;
+ IInputChannel inputChannel = this.RetrieveAsyncChannel(this.endpoint, channelTimeout, out inputChannelParentListener);
+
+ inputChannel.Open();
+
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+ try
+ {
+ for (int i = 0; i < MessageCount; i++)
+ {
+ resultArray[i] = inputChannel.BeginReceive(messageTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ inputChannel.EndReceive(resultArray[j]);
+ }
+ }
+ finally
+ {
+ IAsyncResult channelCloseResult = inputChannel.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ inputChannel.EndClose(channelCloseResult);
+
+ // Asynchronous listener close has not been implemented.
+ ////IAsyncResult listenerCloseResult = inputChannelParentListener.BeginClose(channelTimeout, null, null);
+ ////Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ ////inputChannelParentListener.EndClose(listenerCloseResult);
+
+ inputChannelParentListener.Close();
+ }
+ }
+
+ private void ReceiveTryMessages(TimeSpan channelAcceptTimeout, TimeSpan messageReceiveTimeout)
+ {
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(this.endpoint, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel inputChannel = listener.AcceptChannel(channelAcceptTimeout);
+ IAsyncResult channelResult = inputChannel.BeginOpen(channelAcceptTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0));
+ inputChannel.EndOpen(channelResult);
+
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+
+ for (int i = 0; i < MessageCount; i++)
+ {
+ resultArray[i] = inputChannel.BeginTryReceive(messageReceiveTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ Message tempMessage;
+ Assert.True(inputChannel.EndTryReceive(resultArray[j], out tempMessage), "Did not successfully receive message #{0}", j);
+ }
+
+ inputChannel.Close();
+ listener.Close();
+ }
+
+ private IInputChannel RetrieveAsyncChannel(Uri queue, TimeSpan timeout, out IChannelListener parentListener)
+ {
+ IChannelListener<IInputChannel> listener =
+ Util.GetBinding().BuildChannelListener<IInputChannel>(queue, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel inputChannel;
+
+ try
+ {
+ IAsyncResult acceptResult = listener.BeginAcceptChannel(timeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(300.0)); // Dummy work
+ inputChannel = listener.EndAcceptChannel(acceptResult);
+ }
+ catch (TimeoutException e)
+ {
+ listener.Close();
+ throw e;
+ }
+ finally
+ {
+ parentListener = listener;
+ }
+ return inputChannel;
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs
new file mode 100644
index 0000000000..45a926ce4d
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs
@@ -0,0 +1,77 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class CustomAmqpBindingTest
+ {
+ private MessageClient client;
+
+ [SetUp]
+ public void Setup()
+ {
+ // Create client
+ this.client = new MessageClient();
+ this.client.NumberOfMessages = 3;
+ this.client.NumberOfIterations = 3;
+
+ // Setup and start service
+ MessageService.EndpointAddress = "amqp:message_queue";
+ MessageService.ContractTypes = new List<Type>();
+ MessageService.ContractTypes.Add(typeof(IInteropService));
+ MessageService.CompletionHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
+ MessageService.IntendedInvocationCount = this.client.NumberOfIterations * this.client.NumberOfMessages * MessageService.ContractTypes.Count;
+ MessageService.StartService(Util.GetCustomBinding());
+ }
+
+ [Test]
+ public void Run()
+ {
+ // Create the WCF AMQP channel and send messages
+ MethodInfo runClientMethod = this.client.GetType().GetMethod("RunInteropClient");
+ EndpointAddress address = new EndpointAddress("amqp:amq.direct?routingkey=routing_key");
+ foreach (Type contractType in MessageService.ContractTypes)
+ {
+ MethodInfo runClientT = runClientMethod.MakeGenericMethod(contractType);
+ runClientT.Invoke(this.client, new object[] { address });
+ }
+
+ // Allow the WCF service to process all the messages before validation
+ MessageService.CompletionHandle.WaitOne(TimeSpan.FromSeconds(10.0), false);
+
+ // Validation
+ int expectedMethodCallCount = this.client.NumberOfIterations * this.client.NumberOfMessages * MessageService.ContractTypes.Count;
+ Assert.AreEqual(expectedMethodCallCount, MessageService.TotalMethodCallCount);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ MessageService.StopService();
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj
new file mode 100644
index 0000000000..b7f4ed5d0a
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E2D8C779-E417-40BA-BEE1-EE034268482F}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Test.Channel.Functional</RootNamespace>
+ <AssemblyName>Apache.Qpid.Test.Channel.Functional</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AsyncTest.cs" />
+ <Compile Include="CustomAmqpBindingTest.cs" />
+ <Compile Include="IGenericObjectService.cs" />
+ <Compile Include="IInteropService.cs" />
+ <Compile Include="IQueuedDatagramService1.cs" />
+ <Compile Include="IQueuedDatagramService2.cs" />
+ <Compile Include="IQueuedDatagramService3.cs" />
+ <Compile Include="MessageBodyTest.cs" />
+ <Compile Include="MessagePropertiesTest.cs" />
+ <Compile Include="MultipleEndpointsSameQueueTest.cs" />
+ <Compile Include="MessageClient.cs" />
+ <Compile Include="MessageService.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Util.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Channel\Channel.csproj">
+ <Project>{8AABAB30-7D1E-4539-B7D1-05450262BAD2}</Project>
+ <Name>Channel</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Interop\Interop.vcproj">
+ <Project>{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}</Project>
+ <Name>Interop</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs
new file mode 100644
index 0000000000..a1ffac50b3
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs
@@ -0,0 +1,30 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IGenericObjectService
+ {
+ [OperationContract(IsOneWay = true)]
+ void SendObject(object message);
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs
new file mode 100644
index 0000000000..25f7010a89
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs
@@ -0,0 +1,31 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract]
+ public interface IInteropService
+ {
+ [OperationContract(IsOneWay = true, Action = "*")]
+ void Hello(Message message);
+ }
+} \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs
new file mode 100644
index 0000000000..bdbbb82f7e
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService1
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs
new file mode 100644
index 0000000000..565f7aa27b
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService2
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs
new file mode 100644
index 0000000000..3ff2085557
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs
@@ -0,0 +1,33 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService3
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs
new file mode 100644
index 0000000000..3fad6b336d
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs
@@ -0,0 +1,135 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Runtime.Serialization;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MessageBodyTest
+ {
+ private const string Queue = "amqp:amq.direct?routingkey=routing_key";
+
+ [Test]
+ public void DateVariation()
+ {
+ DateTime rightNow = DateTime.UtcNow;
+ this.SendMessage(rightNow);
+ this.ReceiveMessage<DateTime>(rightNow);
+ }
+
+ [Test]
+ public void EmptyStringVariation()
+ {
+ const string TestString = "";
+ this.SendMessage(TestString);
+ this.ReceiveMessage<string>(TestString);
+ }
+
+ [Test]
+ public void IntPrimitiveVariation()
+ {
+ const int TheAnswer = 42;
+ this.SendMessage(TheAnswer);
+ this.ReceiveMessage<int>(TheAnswer);
+ }
+
+ [Test]
+ public void MultipleIntVariation()
+ {
+ const int NumberOfMessages = 20;
+ int[] listOfNumbers = new int[NumberOfMessages];
+
+ for (int i = 0; i < NumberOfMessages; i++)
+ {
+ this.SendMessage(i);
+ listOfNumbers[i] = i;
+ }
+
+ Assert.True(listOfNumbers[NumberOfMessages - 1] != 0, "Not all messages were sent.");
+
+ for (int j = 0; j < NumberOfMessages; j++)
+ {
+ int receivedNumber = this.ReceiveMessage<int>();
+ Assert.True(listOfNumbers[j].Equals(receivedNumber), "Received {0} - this number is unknown or has been received more than once.", receivedNumber);
+ }
+ }
+
+ [Test]
+ public void StringVariation()
+ {
+ const string TestString = "The darkest of dim, dreary days dost draw deathly deeds. どーも";
+ this.SendMessage(TestString);
+ this.ReceiveMessage<string>(TestString);
+ }
+
+ private void SendMessage(object objectToSend)
+ {
+ IChannelFactory<IOutputChannel> channelFactory =
+ Util.GetBinding().BuildChannelFactory<IOutputChannel>();
+ channelFactory.Open();
+ IOutputChannel proxy = channelFactory.CreateChannel(new EndpointAddress(Queue));
+ proxy.Open();
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, objectToSend);
+ proxy.Send(toSend);
+ toSend.Close();
+ channelFactory.Close();
+ }
+
+ private TObjectType ReceiveMessage<TObjectType>()
+ {
+ Uri endpoint = new Uri("amqp:message_queue");
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(endpoint, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel service = listener.AcceptChannel(TimeSpan.FromSeconds(10));
+ service.Open();
+ Message receivedMessage = service.Receive(TimeSpan.FromSeconds(10));
+ Assert.NotNull(receivedMessage, "Message was not received");
+ try
+ {
+ TObjectType receivedObject = receivedMessage.GetBody<TObjectType>();
+ return receivedObject;
+ }
+ catch (SerializationException)
+ {
+ Assert.Fail("Deserialized object not of correct type");
+ }
+ finally
+ {
+ receivedMessage.Close();
+ service.Close();
+ listener.Close();
+ }
+
+ return default(TObjectType);
+ }
+
+ private TObjectType ReceiveMessage<TObjectType>(TObjectType objectToMatch)
+ {
+ TObjectType receivedObject = this.ReceiveMessage<TObjectType>();
+ Assert.True(objectToMatch.Equals(receivedObject), "Original and deserialized objects do not match");
+ return receivedObject;
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs
new file mode 100644
index 0000000000..8f867551b1
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs
@@ -0,0 +1,101 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ public class MessageClient
+ {
+ public int NumberOfMessages
+ {
+ get;
+ set;
+ }
+
+ public int NumberOfIterations
+ {
+ get;
+ set;
+ }
+
+ public void RunClient<TServiceContract>(EndpointAddress address)
+ {
+ Binding amqpBinding = Util.GetBinding();
+ Type proxyType = typeof(TServiceContract);
+ MethodInfo helloMethod = proxyType.GetMethod("Hello");
+ MethodInfo goodbyeMethod = proxyType.GetMethod("Goodbye");
+
+ string[] messages = new string[this.NumberOfMessages];
+ for (int i = 0; i < this.NumberOfMessages; ++i)
+ {
+ messages[i] = "Message " + i;
+ }
+
+ for (int i = 0; i < this.NumberOfIterations; ++i)
+ {
+ this.CreateChannelAndSendMessages<TServiceContract>(address, amqpBinding, helloMethod, goodbyeMethod, messages);
+ }
+ }
+
+ public void RunInteropClient<TServiceContract>(EndpointAddress address)
+ {
+ Binding amqpBinding = Util.GetBinding();
+ Type proxyType = typeof(TServiceContract);
+ MethodInfo helloMethod = proxyType.GetMethod("Hello");
+
+ Message[] messages = new Message[this.NumberOfMessages];
+
+ for (int i = 0; i < this.NumberOfIterations; ++i)
+ {
+ this.CreateInteropChannelAndSendMessages<TServiceContract>(address, amqpBinding, helloMethod, this.NumberOfMessages);
+ }
+ }
+
+ private void CreateChannelAndSendMessages<TServiceContract>(EndpointAddress address, Binding amqpBinding, MethodInfo helloMethod, MethodInfo goodbyeMethod, object[] messages)
+ {
+ ChannelFactory<TServiceContract> channelFactory = new ChannelFactory<TServiceContract>(amqpBinding, address);
+ TServiceContract proxy = channelFactory.CreateChannel();
+
+ foreach (object message in messages)
+ {
+ helloMethod.Invoke(proxy, new object[] { message });
+ }
+
+ goodbyeMethod.Invoke(proxy, new object[0]);
+ channelFactory.Close();
+ }
+
+ private void CreateInteropChannelAndSendMessages<TServiceContract>(EndpointAddress address, Binding amqpBinding, MethodInfo helloMethod, int messageCount)
+ {
+ ChannelFactory<TServiceContract> channelFactory = new ChannelFactory<TServiceContract>(amqpBinding, address);
+ TServiceContract proxy = channelFactory.CreateChannel();
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ helloMethod.Invoke(proxy, new object[] { Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "*") });
+ }
+
+ channelFactory.Close();
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt
new file mode 100644
index 0000000000..bd6459ccb9
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt
@@ -0,0 +1,22 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+ContentType=Text
+Durable=true
+RoutingKey=routing_key
+TimeToLive=00:00:10 \ No newline at end of file
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs
new file mode 100644
index 0000000000..8e192e90f1
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs
@@ -0,0 +1,131 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.Runtime.Serialization;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.AmqpTypes;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MessagePropertiesTest
+ {
+ private const string RoutingKey = "routing_key";
+ private const string SendToUri = "amqp:amq.direct?routingkey=" + RoutingKey;
+
+ [Test]
+ public void DefaultAmqpProperties()
+ {
+ const string TestString = "Test Message";
+ AmqpProperties messageProperties = new AmqpProperties();
+
+ this.SendMessage(TestString, messageProperties);
+ this.ReceiveMessage<string>(TestString, messageProperties);
+ }
+
+ [Test]
+ public void NonDefaultAmqpProperties()
+ {
+ const string TestString = "Test Message";
+ AmqpProperties messageProperties = this.CreateMessageProperties();
+
+ this.SendMessage(TestString, messageProperties);
+ this.ReceiveMessage<string>(TestString, messageProperties);
+ }
+
+ private AmqpProperties CreateMessageProperties()
+ {
+ Dictionary<string, string> messageProperties = Util.GetProperties("..\\..\\MessageProperties.txt");
+
+ AmqpProperties amqpProperties = new AmqpProperties();
+ amqpProperties.ContentType = (string)messageProperties["ContentType"];
+ amqpProperties.Durable = Convert.ToBoolean((string)messageProperties["Durable"]);
+ amqpProperties.RoutingKey = (string)messageProperties["RoutingKey"];
+ amqpProperties.TimeToLive = TimeSpan.Parse((string)messageProperties["TimeToLive"]);
+
+ return amqpProperties;
+ }
+
+ private void SendMessage(object objectToSend, AmqpProperties propertiesToSend)
+ {
+ ChannelFactory<IOutputChannel> channelFactory =
+ new ChannelFactory<IOutputChannel>(Util.GetBinding(), SendToUri);
+ IOutputChannel proxy = channelFactory.CreateChannel();
+ proxy.Open();
+
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, objectToSend);
+ toSend.Properties["AmqpProperties"] = propertiesToSend;
+ proxy.Send(toSend);
+
+ toSend.Close();
+ proxy.Close();
+ channelFactory.Close();
+ }
+
+ private void ReceiveMessage<TObjectType>(TObjectType objectToMatch, AmqpProperties expectedProperties)
+ {
+ Uri receiveFromUri = new Uri("amqp:message_queue");
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(receiveFromUri, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel service = listener.AcceptChannel(TimeSpan.FromSeconds(10));
+ service.Open();
+ Message receivedMessage = service.Receive(TimeSpan.FromSeconds(10));
+ try
+ {
+ TObjectType receivedObject = receivedMessage.GetBody<TObjectType>();
+ Assert.True(receivedObject.Equals(objectToMatch), "Original and deserialized objects do not match");
+
+ AmqpProperties receivedProperties = (AmqpProperties)receivedMessage.Properties["AmqpProperties"];
+ PropertyInfo[] propInfo = typeof(AmqpProperties).GetProperties();
+
+ for (int i = 0; i < propInfo.Length; i++)
+ {
+ string propertyName = propInfo[i].Name;
+ if (propertyName.Equals("RoutingKey", StringComparison.InvariantCultureIgnoreCase))
+ {
+ Assert.AreEqual(RoutingKey, Convert.ToString(propInfo[i].GetValue(receivedProperties, null)));
+ }
+ else
+ {
+ Assert.AreEqual(Convert.ToString(propInfo[i].GetValue(expectedProperties, null)), Convert.ToString(propInfo[i].GetValue(receivedProperties, null)));
+ }
+ }
+ }
+ catch (NullReferenceException)
+ {
+ Assert.Fail("Message not received");
+ }
+ catch (SerializationException)
+ {
+ Assert.Fail("Deserialized object not of correct type");
+ }
+ finally
+ {
+ receivedMessage.Close();
+ service.Close();
+ listener.Close();
+ }
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs
new file mode 100644
index 0000000000..a473cad986
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs
@@ -0,0 +1,158 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+
+ public class MessageService : IQueuedDatagramService1, IQueuedDatagramService2, IQueuedDatagramService3, IInteropService
+ {
+ private static Dictionary<string, int> methodCallCount = new Dictionary<string, int>();
+ private static ServiceHost serviceHost;
+
+ public static EventWaitHandle CompletionHandle
+ {
+ get;
+ set;
+ }
+
+ public static int IntendedInvocationCount
+ {
+ get;
+ set;
+ }
+
+ public static int TotalMethodCallCount
+ {
+ get;
+ set;
+ }
+
+ // The test must set these paramters
+ public static List<Type> ContractTypes
+ {
+ get;
+ set;
+ }
+
+ public static string EndpointAddress
+ {
+ get;
+ set;
+ }
+
+ public static void DisplayCounts()
+ {
+ Console.WriteLine("Method calls:");
+ foreach (string key in methodCallCount.Keys)
+ {
+ Console.WriteLine(" {0}: {1}", key, methodCallCount[key]);
+ }
+
+ Console.WriteLine("Total: {0}", TotalMethodCallCount);
+ }
+
+ public static void StartService(Binding amqpBinding)
+ {
+ MessageService.methodCallCount.Clear();
+ MessageService.TotalMethodCallCount = 0;
+
+ serviceHost = new ServiceHost(typeof(MessageService));
+
+ foreach (Type contractType in ContractTypes)
+ {
+ serviceHost.AddServiceEndpoint(contractType, amqpBinding, EndpointAddress);
+ }
+
+ serviceHost.Open();
+ }
+
+ public static void StopService()
+ {
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+
+ public void UpdateCounts(string method)
+ {
+ lock (methodCallCount)
+ {
+ if (!methodCallCount.ContainsKey(method))
+ {
+ methodCallCount[method] = 0;
+ }
+
+ ++methodCallCount[method];
+ ++TotalMethodCallCount;
+ if (TotalMethodCallCount >= IntendedInvocationCount && CompletionHandle != null)
+ {
+ CompletionHandle.Set();
+ }
+ }
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService1.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService1.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService1.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService1.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService2.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService2.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService2.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService2.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService3.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService3.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService3.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService3.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IInteropService.Hello(Message message)
+ {
+ this.UpdateCounts("IInteropService.Hello");
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs
new file mode 100644
index 0000000000..d09832757a
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs
@@ -0,0 +1,83 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MultipleEndpointsSameQueueTest
+ {
+ private MessageClient client;
+
+ [SetUp]
+ public void Setup()
+ {
+ // Create client
+ this.client = new MessageClient();
+ this.client.NumberOfMessages = 3;
+ this.client.NumberOfIterations = 5;
+
+ // Setup and start service
+ MessageService.EndpointAddress = "amqp:message_queue";
+
+ MessageService.ContractTypes = new List<Type>();
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService1));
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService2));
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService3));
+ MessageService.CompletionHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
+ MessageService.IntendedInvocationCount = this.client.NumberOfIterations * (this.client.NumberOfMessages + 1) * MessageService.ContractTypes.Count;
+
+ MessageService.StartService(Util.GetBinding());
+ }
+
+ [Test]
+ public void Run()
+ {
+ // Create wcf amqpchannel and send messages
+ MethodInfo runClientMethod = this.client.GetType().GetMethod("RunClient");
+ EndpointAddress address = new EndpointAddress("amqp:amq.direct?routingkey=routing_key");
+
+ foreach (Type contractType in MessageService.ContractTypes)
+ {
+ MethodInfo runClientT = runClientMethod.MakeGenericMethod(contractType);
+ runClientT.Invoke(this.client, new object[] { address });
+ }
+
+ // Allow the wcf service to process all the messages before validation
+ MessageService.CompletionHandle.WaitOne(TimeSpan.FromSeconds(10.0), false);
+
+ // Validation
+ int expectedMethodCallCount = this.client.NumberOfIterations * (this.client.NumberOfMessages + 1) * MessageService.ContractTypes.Count;
+
+ Assert.AreEqual(expectedMethodCallCount, MessageService.TotalMethodCallCount);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ MessageService.StopService();
+ }
+ }
+}
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..b47a25494f
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Test.Channel.Functional")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("552dca74-b5a3-4ad3-a718-4a1dd03db039")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
new file mode 100755
index 0000000000..4b83993257
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
@@ -0,0 +1,34 @@
+@echo OFF
+
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+
+set nunit_exe=%programfiles%\NUnit 2.5.1\bin\net-2.0\nunit-console.exe
+set qpid_dll_location=..\..\..\..\..\..\..\cpp\build\src\Debug
+set configuration_name=bin\Debug
+set qcreate_location=..\..\..\..\..\..\tools\QCreate\Debug
+
+copy %qpid_dll_location%\qpidclient.dll %configuration_name%
+copy %qpid_dll_location%\qpidcommon.dll %configuration_name%
+
+copy %qpid_dll_location%\qpidclient.dll %qcreate_location%
+copy %qpid_dll_location%\qpidcommon.dll %qcreate_location%
+
+%qcreate_location%\QCreate.exe amq.direct routing_key message_queue
+
+"%nunit_exe%" %configuration_name%\Apache.Qpid.Test.Channel.Functional.dll
diff --git a/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs
new file mode 100644
index 0000000000..97be1fb925
--- /dev/null
+++ b/qpid/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs
@@ -0,0 +1,74 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 Apache.Qpid.Test.Channel.Functional
+{
+ using System.Collections.Generic;
+ using System.IO;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ internal class Util
+ {
+ public static Dictionary<string, string> GetProperties(string path)
+ {
+ string fileData = string.Empty;
+ using (StreamReader sr = new StreamReader(path))
+ {
+ fileData = sr.ReadToEnd().Replace("\r", string.Empty);
+ }
+
+ Dictionary<string, string> properties = new Dictionary<string, string>();
+ string[] kvp;
+ string[] records = fileData.Split("\n".ToCharArray());
+ foreach (string record in records)
+ {
+ if (record[0] == '/' || record[0] == '*')
+ {
+ continue;
+ }
+
+ kvp = record.Split("=".ToCharArray());
+ properties.Add(kvp[0], kvp[1]);
+ }
+
+ return properties;
+ }
+
+ public static Binding GetBinding()
+ {
+ return new AmqpBinding();
+ }
+
+ public static Binding GetCustomBinding()
+ {
+ AmqpTransportBindingElement transportElement = new AmqpTransportBindingElement();
+ RawMessageEncodingBindingElement encodingElement = new RawMessageEncodingBindingElement();
+ transportElement.BrokerHost = "127.0.0.1";
+ transportElement.TransferMode = TransferMode.Streamed;
+
+ CustomBinding brokerBinding = new CustomBinding();
+ brokerBinding.Elements.Add(encodingElement);
+ brokerBinding.Elements.Add(transportElement);
+
+ return brokerBinding;
+ }
+ }
+}
diff --git a/qpid/wcf/tools/QCreate/QCreate.cpp b/qpid/wcf/tools/QCreate/QCreate.cpp
new file mode 100644
index 0000000000..7b0231f339
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/QCreate.cpp
@@ -0,0 +1,65 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include "stdafx.h"
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+int main(int argc, char** argv) {
+
+ std::string exchange = argc>1 ? argv[1] : "amq.direct";
+ std::string bindingKey = argc>2 ? argv[2] : "routing_key";
+ std::string queue = argc>3 ? argv[3] : "message_queue";
+
+ const char* host = "127.0.0.1";
+ int port = 5672;
+ Connection connection;
+
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession();
+
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a queue and route all messages whose
+ // routing key is "routing_key" to this newly created queue.
+
+ session.queueDeclare(arg::queue=queue);
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=bindingKey);
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+
+}
+
diff --git a/qpid/wcf/tools/QCreate/QCreate.sln b/qpid/wcf/tools/QCreate/QCreate.sln
new file mode 100644
index 0000000000..c01675d53a
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/QCreate.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QCreate", "QCreate.vcproj", "{7CA88318-485A-4D95-A321-43DFBB6EA28B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Debug|Win32.Build.0 = Debug|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Release|Win32.ActiveCfg = Release|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/qpid/wcf/tools/QCreate/QCreate.vcproj b/qpid/wcf/tools/QCreate/QCreate.vcproj
new file mode 100644
index 0000000000..e58077d78c
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/QCreate.vcproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="QCreate"
+ ProjectGUID="{7CA88318-485A-4D95-A321-43DFBB6EA28B}"
+ RootNamespace="QCreate"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(BOOST_ROOT)\include\$(BOOST_VERSION)&quot;;&quot;$(BOOST_ROOT)\.&quot;;..\..\..\cpp\include;..\..\..\cpp\build\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=".;&quot;$(BOOST_ROOT)\lib&quot;;..\..\..\cpp\build\src\Debug"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\QCreate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\targetver.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/qpid/wcf/tools/QCreate/ReadMe.txt b/qpid/wcf/tools/QCreate/ReadMe.txt
new file mode 100644
index 0000000000..b3efb84503
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/ReadMe.txt
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+========================================================================
+ CONSOLE APPLICATION : QCreate Project Overview
+========================================================================
+
+AppWizard has created this QCreate application for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your QCreate application.
+
+
+QCreate.vcproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+QCreate.cpp
+ This is the main application source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named QCreate.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/qpid/wcf/tools/QCreate/stdafx.cpp b/qpid/wcf/tools/QCreate/stdafx.cpp
new file mode 100644
index 0000000000..568cd3b7d6
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/stdafx.cpp
@@ -0,0 +1,27 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// stdafx.cpp : source file that includes just the standard includes
+// QCreate.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/qpid/wcf/tools/QCreate/stdafx.h b/qpid/wcf/tools/QCreate/stdafx.h
new file mode 100644
index 0000000000..a516e19a10
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/stdafx.h
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <tchar.h>
+
+
+
+// TODO: reference additional headers your program requires here
diff --git a/qpid/wcf/tools/QCreate/targetver.h b/qpid/wcf/tools/QCreate/targetver.h
new file mode 100644
index 0000000000..9cfb78641b
--- /dev/null
+++ b/qpid/wcf/tools/QCreate/targetver.h
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+