summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/010ExcludeList6
-rw-r--r--java/010ExcludeList-store7
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java19
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java25
-rw-r--r--java/broker/src/main/grammar/SelectorParser.jj2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java8
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java575
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/Main.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java56
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java104
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java63
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java21
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java579
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java (renamed from java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java)53
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java32
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java26
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java651
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java40
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java50
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java339
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java439
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java295
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java613
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java54
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java63
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java141
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java14
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java31
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java126
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java332
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java322
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java62
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java77
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java79
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java76
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java185
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java105
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java288
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java129
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java27
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java240
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java1132
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java328
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java172
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java66
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java114
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java122
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java569
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java767
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java23
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java92
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java92
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java465
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java32
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java67
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java1005
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java52
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java1097
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java102
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java33
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java71
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java336
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java267
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java164
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java245
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java392
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java30
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java34
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java26
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java54
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java1671
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java178
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java680
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java34
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java274
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java66
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java26
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java74
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java192
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java8
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java29
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java28
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java (renamed from java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java)65
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java (renamed from java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java)24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java103
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java605
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java247
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java77
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java140
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java73
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java23
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java88
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java23
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java140
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java2
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java176
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java11
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/TestMinaProtocolSession.java2
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java110
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java83
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession.java27
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java37
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java19
-rw-r--r--java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/common/ClientProperties.java23
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java56
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java20
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java105
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Job.java24
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java30
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java432
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java27
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java24
-rw-r--r--java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java10
-rw-r--r--java/systests/pom.xml1
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java74
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java268
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java10
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java93
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/ConcurrencyTestDisabled.java265
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/DeliveryManagerTest.java177
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java21
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java5
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java176
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java17
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionManagerTest.java102
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionSetTest.java144
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java69
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java9
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java43
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java17
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java210
187 files changed, 13228 insertions, 9421 deletions
diff --git a/java/010ExcludeList b/java/010ExcludeList
index 59a4a0097c..442fac2ffe 100644
--- a/java/010ExcludeList
+++ b/java/010ExcludeList
@@ -46,4 +46,8 @@ org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFails
org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
// the 0.10 c++ broker does not implement forget
-org.apache.qpid.test.unit.xa.FaultTest#testForget \ No newline at end of file
+org.apache.qpid.test.unit.xa.FaultTest#testForget
+// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
+org.apache.qpid.server.queue.PriorityTest
+//this test checks explicitly for 0-8 flow control semantics
+org.apache.qpid.test.client.FlowControlTest
diff --git a/java/010ExcludeList-store b/java/010ExcludeList-store
index ccd47ce58b..1c62003474 100644
--- a/java/010ExcludeList-store
+++ b/java/010ExcludeList-store
@@ -41,4 +41,9 @@ org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFails
org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
// the 0.10 c++ broker does not implement forget
-org.apache.qpid.test.unit.xa.FaultTest#testForget \ No newline at end of file
+org.apache.qpid.test.unit.xa.FaultTest#testForget
+// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
+org.apache.qpid.server.queue.PriorityTest
+//this test checks explicitly for 0-8 flow control semantics
+org.apache.qpid.test.client.FlowControlTest
+
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
index 77cc12df7c..0b7e300cec 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
@@ -22,6 +22,8 @@ package org.apache.qpid.extras.exchanges.diagnostic;
import java.util.List;
import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
import javax.management.JMException;
import javax.management.openmbean.OpenDataException;
@@ -34,7 +36,7 @@ import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.exchange.AbstractExchange;
import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.junit.extensions.util.SizeOf;
@@ -191,7 +193,7 @@ public class DiagnosticExchange extends AbstractExchange
return false;
}
- public void route(AMQMessage payload) throws AMQException
+ public void route(IncomingMessage payload) throws AMQException
{
Long value = new Long(SizeOf.getUsedMemory());
@@ -201,17 +203,14 @@ public class DiagnosticExchange extends AbstractExchange
headers.put(key, value);
((BasicContentHeaderProperties)payload.getContentHeaderBody().properties).setHeaders(headers);
AMQQueue q = getQueueRegistry().getQueue(new AMQShortString("diagnosticqueue"));
-
- payload.enqueue(q);
+
+ Collection<AMQQueue> queues = new ArrayList<AMQQueue>();
+ queues.add(q);
+ payload.enqueue(queues);
}
- @Override
- public Map<AMQShortString, List<AMQQueue>> getBindings() {
- // TODO Auto-generated method stub
- return null;
- }
-
+
public boolean isBound(AMQShortString routingKey, FieldTable arguments,
AMQQueue queue) {
// TODO Auto-generated method stub
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
index d56a958044..067125de56 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
@@ -1,24 +1,3 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
package org.apache.qpid.extras.exchanges.example;
import java.util.List;
@@ -28,7 +7,7 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -102,7 +81,7 @@ public class TestExchange implements Exchange
{
}
- public void route(AMQMessage message) throws AMQException
+ public void route(IncomingMessage message) throws AMQException
{
}
diff --git a/java/broker/src/main/grammar/SelectorParser.jj b/java/broker/src/main/grammar/SelectorParser.jj
index eb4467f1cc..c9e01cd01f 100644
--- a/java/broker/src/main/grammar/SelectorParser.jj
+++ b/java/broker/src/main/grammar/SelectorParser.jj
@@ -94,7 +94,7 @@ public class SelectorParser {
return this.JmsSelector();
}
catch (Throwable e) {
- throw (AMQInvalidArgumentException)new AMQInvalidArgumentException(sql, e);
+ throw (AMQInvalidArgumentException)new AMQInvalidArgumentException(sql,e);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index 9335723bc5..88d5360f3e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -56,8 +56,9 @@ import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.MBeanDescription;
import org.apache.qpid.server.management.ManagedBroker;
import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -175,7 +176,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
ownerShortString = new AMQShortString(owner);
}
- queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost());
+ queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost(),
+ null);
if (queue.isDurable() && !queue.isAutoDelete())
{
_messageStore.createQueue(queue);
@@ -220,7 +222,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
try
{
queue.delete();
- _messageStore.removeQueue(new AMQShortString(queueName));
+ _messageStore.removeQueue(queue);
}
catch (AMQException ex)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 1314b2b715..847c8b8459 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -21,7 +21,6 @@
package org.apache.qpid.server;
import org.apache.log4j.Logger;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.configuration.Configured;
import org.apache.qpid.framing.AMQShortString;
@@ -30,14 +29,23 @@ import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.ack.UnacknowledgedMessage;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl;
import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.exchange.NoRouteException;
import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.NoRouteException;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.flow.Pre0_10CreditManager;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.IncomingMessage;
+import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
+import org.apache.qpid.server.subscription.RecordDeliveryMethod;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.txn.LocalTransactionalContext;
@@ -45,13 +53,13 @@ import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.txn.TransactionalContext;
import java.util.Collection;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
public class AMQChannel
{
@@ -61,13 +69,8 @@ public class AMQChannel
private final int _channelId;
- // private boolean _transactional;
-
- private long _prefetch_HighWaterMark;
- private long _prefetch_LowWaterMark;
-
- private long _prefetchSize;
+ private final Pre0_10CreditManager _creditManager = new Pre0_10CreditManager(0l,0l);
/**
* The delivery tag is unique per channel. This is pre-incremented before putting into the deliver frame so that
@@ -86,10 +89,11 @@ public class AMQChannel
* been received by this channel. As the frames are received the message gets updated and once all frames have been
* received the message can then be routed.
*/
- private AMQMessage _currentMessage;
+ private IncomingMessage _currentMessage;
+
+ /** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */
+ private final Map<AMQShortString, Subscription> _tag2SubscriptionMap = new HashMap<AMQShortString, Subscription>();
- /** Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. */
- private final Map<AMQShortString, AMQQueue> _consumerTag2QueueMap = new ConcurrentHashMap<AMQShortString, AMQQueue>();
private final MessageStore _messageStore;
@@ -97,7 +101,7 @@ public class AMQChannel
private final AtomicBoolean _suspended = new AtomicBoolean(false);
- private TransactionalContext _txnContext, _nonTransactedContext;
+ private TransactionalContext _txnContext;
/**
* A context used by the message store enabling it to track context for a given channel even across thread
@@ -109,8 +113,6 @@ public class AMQChannel
private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory();
- private Set<Long> _browsedAcks = new HashSet<Long>();
-
// Why do we need this reference ? - ritchiem
private final AMQProtocolSession _session;
private boolean _closing;
@@ -118,7 +120,7 @@ public class AMQChannel
@Configured(path = "advanced.enableJMSXUserID",
defaultValue = "false")
public boolean ENABLE_JMSXUserID;
-
+
public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore)
throws AMQException
@@ -129,8 +131,8 @@ public class AMQChannel
_session = session;
_channelId = channelId;
_storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId);
- _prefetch_HighWaterMark = DEFAULT_PREFETCH;
- _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2;
+
+
_messageStore = messageStore;
// by default the session is non-transactional
@@ -140,7 +142,7 @@ public class AMQChannel
/** Sets this channel to be part of a local transaction */
public void setLocalTransactional()
{
- _txnContext = new LocalTransactionalContext(_messageStore, _storeContext, _returnMessages);
+ _txnContext = new LocalTransactionalContext(this);
}
public boolean isTransactional()
@@ -156,55 +158,15 @@ public class AMQChannel
return _channelId;
}
- public long getPrefetchCount()
- {
- return _prefetch_HighWaterMark;
- }
-
- public void setPrefetchCount(long prefetchCount)
- {
- _prefetch_HighWaterMark = prefetchCount;
- }
-
- public long getPrefetchSize()
- {
- return _prefetchSize;
- }
-
- public void setPrefetchSize(long prefetchSize)
- {
- _prefetchSize = prefetchSize;
- }
-
- public long getPrefetchLowMarkCount()
- {
- return _prefetch_LowWaterMark;
- }
-
- public void setPrefetchLowMarkCount(long prefetchCount)
- {
- _prefetch_LowWaterMark = prefetchCount;
- }
-
- public long getPrefetchHighMarkCount()
- {
- return _prefetch_HighWaterMark;
- }
-
- public void setPrefetchHighMarkCount(long prefetchCount)
- {
- _prefetch_HighWaterMark = prefetchCount;
- }
-
- public void setPublishFrame(MessagePublishInfo info, AMQProtocolSession publisher, final Exchange e) throws AMQException
+ public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException
{
- _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), info, _txnContext);
- _currentMessage.setPublisher(publisher);
+ _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session);
+ _currentMessage.setMessageStore(_messageStore);
_currentMessage.setExchange(e);
}
- public void publishContentHeader(ContentHeaderBody contentHeaderBody, AMQProtocolSession protocolSession)
+ public void publishContentHeader(ContentHeaderBody contentHeaderBody)
throws AMQException
{
if (_currentMessage == null)
@@ -215,7 +177,7 @@ public class AMQChannel
{
if (_log.isDebugEnabled())
{
- _log.debug(debugIdentity() + "Content header received on channel " + _channelId);
+ _log.debug("Content header received on channel " + _channelId);
}
if (ENABLE_JMSXUserID)
@@ -225,25 +187,48 @@ public class AMQChannel
//fixme: fudge for QPID-677
properties.getHeaders().keySet();
- properties.setUserId(protocolSession.getAuthorizedID().getName());
+ properties.setUserId(_session.getAuthorizedID().getName());
}
_currentMessage.setContentHeaderBody(contentHeaderBody);
+
_currentMessage.setExpiration();
routeCurrentMessage();
- _currentMessage.routingComplete(_messageStore, _storeContext, _messageHandleFactory);
- // check and deliver if header says body length is zero
- if (contentHeaderBody.bodySize == 0)
+ _currentMessage.routingComplete(_messageStore, _messageHandleFactory);
+
+ deliverCurrentMessageIfComplete();
+
+ }
+ }
+
+ private void deliverCurrentMessageIfComplete()
+ throws AMQException
+ {
+ // check and deliver if header says body length is zero
+ if (_currentMessage.allContentReceived())
+ {
+ try
{
- _txnContext.messageProcessed(protocolSession);
+ _currentMessage.deliverToQueues();
+ }
+ catch (NoRouteException e)
+ {
+ _returnMessages.add(e);
+ }
+ finally
+ {
+ // callback to allow the context to do any post message processing
+ // primary use is to allow message return processing in the non-tx case
+ _txnContext.messageProcessed(_session);
_currentMessage = null;
}
}
+
}
- public void publishContentBody(ContentBody contentBody, AMQProtocolSession protocolSession) throws AMQException
+ public void publishContentBody(ContentBody contentBody) throws AMQException
{
if (_currentMessage == null)
{
@@ -260,15 +245,11 @@ public class AMQChannel
// returns true iff the message was delivered (i.e. if all data was
// received
- if (_currentMessage.addContentBodyFrame(_storeContext,
- protocolSession.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(
- contentBody)))
- {
- // callback to allow the context to do any post message processing
- // primary use is to allow message return processing in the non-tx case
- _txnContext.messageProcessed(protocolSession);
- _currentMessage = null;
- }
+ _currentMessage.addContentBodyFrame(
+ _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(
+ contentBody));
+
+ deliverCurrentMessageIfComplete();
}
catch (AMQException e)
{
@@ -287,6 +268,7 @@ public class AMQChannel
}
catch (NoRouteException e)
{
+ //_currentMessage.incrementReference();
_returnMessages.add(e);
}
}
@@ -307,18 +289,17 @@ public class AMQChannel
*
* @param tag the tag chosen by the client (if null, server will generate one)
* @param queue the queue to subscribe to
- * @param session the protocol session of the subscriber
- * @param noLocal Flag stopping own messages being receivied.
- * @param exclusive Flag requesting exclusive access to the queue
* @param acks Are acks enabled for this subscriber
* @param filters Filters to apply to this subscriber
*
+ * @param noLocal Flag stopping own messages being receivied.
+ * @param exclusive Flag requesting exclusive access to the queue
* @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests
*
* @throws ConsumerTagNotUniqueException if the tag is not unique
* @throws AMQException if something goes wrong
*/
- public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, AMQProtocolSession session, boolean acks,
+ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks,
FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException
{
if (tag == null)
@@ -326,77 +307,65 @@ public class AMQChannel
tag = new AMQShortString("sgen_" + getNextConsumerTag());
}
- if (_consumerTag2QueueMap.containsKey(tag))
+ if (_tag2SubscriptionMap.containsKey(tag))
{
throw new ConsumerTagNotUniqueException();
}
+ Subscription subscription =
+ SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager);
+
+
+ // So to keep things straight we put before the call and catch all exceptions from the register and tidy up.
// We add before we register as the Async Delivery process may AutoClose the subscriber
// so calling _cT2QM.remove before we have done put which was after the register succeeded.
// So to keep things straight we put before the call and catch all exceptions from the register and tidy up.
- _consumerTag2QueueMap.put(tag, queue);
+
+ _tag2SubscriptionMap.put(tag, subscription);
try
{
- queue.registerProtocolSession(session, _channelId, tag, acks, filters, noLocal, exclusive);
+ queue.registerSubscription(subscription, exclusive);
}
catch (AMQException e)
{
- _consumerTag2QueueMap.remove(tag);
+ _tag2SubscriptionMap.remove(tag);
throw e;
}
-
return tag;
}
/**
* Unsubscribe a consumer from a queue.
- * @param session
* @param consumerTag
* @return true if the consumerTag had a mapped queue that could be unregistered.
* @throws AMQException
*/
- public boolean unsubscribeConsumer(AMQProtocolSession session, AMQShortString consumerTag) throws AMQException
+ public boolean unsubscribeConsumer(AMQShortString consumerTag) throws AMQException
{
- if (_log.isDebugEnabled())
- {
- _log.debug("Unacked Map Dump size:" + _unacknowledgedMessageMap.size());
- _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
- {
-
- public boolean callback(UnacknowledgedMessage message) throws AMQException
- {
- _log.debug(message);
-
- return true;
- }
- public void visitComplete()
- {
- }
- });
- }
-
- AMQQueue q = _consumerTag2QueueMap.remove(consumerTag);
- if (q != null)
+ Subscription sub = _tag2SubscriptionMap.remove(consumerTag);
+ if (sub != null)
{
- q.unregisterProtocolSession(session, _channelId, consumerTag);
+ sub.getQueue().unregisterSubscription(sub);
return true;
}
+ else
+ {
+ _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered.");
+ }
return false;
}
/**
* Called from the protocol session to close this channel and clean up. T
*
- * @param session The session to close
- *
* @throws AMQException if there is an error during closure
*/
- public void close(AMQProtocolSession session) throws AMQException
+ public void close() throws AMQException
{
_txnContext.rollback();
- unsubscribeAllConsumers(session);
+ unsubscribeAllConsumers();
try
{
requeue();
@@ -414,11 +383,11 @@ public class AMQChannel
_closing = closing;
}
- private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException
+ private void unsubscribeAllConsumers() throws AMQException
{
if (_log.isInfoEnabled())
{
- if (!_consumerTag2QueueMap.isEmpty())
+ if (!_tag2SubscriptionMap.isEmpty())
{
_log.info("Unsubscribing all consumers on channel " + toString());
}
@@ -428,17 +397,19 @@ public class AMQChannel
}
}
- for (Map.Entry<AMQShortString, AMQQueue> me : _consumerTag2QueueMap.entrySet())
+ for (Map.Entry<AMQShortString, Subscription> me : _tag2SubscriptionMap.entrySet())
{
if (_log.isInfoEnabled())
{
_log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString());
}
- me.getValue().unregisterProtocolSession(session, _channelId, me.getKey());
+ Subscription sub = me.getValue();
+
+ sub.getQueue().unregisterSubscription(sub);
}
- _consumerTag2QueueMap.clear();
+ _tag2SubscriptionMap.clear();
}
/**
@@ -447,9 +418,9 @@ public class AMQChannel
* @param entry the record of the message on the queue that was delivered
* @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the
* delivery tag)
- * @param consumerTag The tag for the consumer that is to acknowledge this message.
+ * @param subscription The consumer that is to acknowledge this message.
*/
- public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, AMQShortString consumerTag)
+ public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription)
{
if (_log.isDebugEnabled())
{
@@ -462,16 +433,13 @@ public class AMQChannel
if (_log.isDebugEnabled())
{
_log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag
- + ") with a queue(" + entry.getQueue() + ") for " + consumerTag);
+ + ") with a queue(" + entry.getQueue() + ") for " + subscription);
}
}
}
- synchronized (_unacknowledgedMessageMap.getLock())
- {
- _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(entry, consumerTag, deliveryTag,_unacknowledgedMessageMap));
- checkSuspension();
- }
+ _unacknowledgedMessageMap.add(deliveryTag, entry);
+
}
private final String id = "(" + System.identityHashCode(this) + ")";
@@ -490,7 +458,7 @@ public class AMQChannel
public void requeue() throws AMQException
{
// we must create a new map since all the messages will get a new delivery tag when they are redelivered
- Collection<UnacknowledgedMessage> messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages();
+ Collection<QueueEntry> messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages();
// Deliver these messages out of the transaction as their delivery was never
// part of the transaction only the receive.
@@ -505,13 +473,9 @@ public class AMQChannel
if (!(_txnContext instanceof NonTransactionalContext))
{
- // if (_nonTransactedContext == null)
- {
- _nonTransactedContext =
- new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
- }
- deliveryContext = _nonTransactedContext;
+ deliveryContext =
+ new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
}
else
{
@@ -519,22 +483,23 @@ public class AMQChannel
}
}
- for (UnacknowledgedMessage unacked : messagesToBeDelivered)
+ for (QueueEntry unacked : messagesToBeDelivered)
{
if (!unacked.isQueueDeleted())
{
- // Ensure message is released for redelivery
- unacked.entry.release();
-
// Mark message redelivered
unacked.getMessage().setRedelivered(true);
+ // Ensure message is released for redelivery
+ unacked.release();
+
// Deliver Message
- deliveryContext.deliver(unacked.entry, false);
+ deliveryContext.requeue(unacked);
- // Should we allow access To the DM to directy deliver the message?
- // As we don't need to check for Consumers or worry about incrementing the message count?
- // unacked.queue.getDeliveryManager().deliver(_storeContext, unacked.queue.getName(), unacked.message, false);
+ }
+ else
+ {
+ unacked.discard(_storeContext);
}
}
@@ -549,32 +514,29 @@ public class AMQChannel
*/
public void requeue(long deliveryTag) throws AMQException
{
- UnacknowledgedMessage unacked = _unacknowledgedMessageMap.remove(deliveryTag);
+ QueueEntry unacked = _unacknowledgedMessageMap.remove(deliveryTag);
if (unacked != null)
{
+ // Mark message redelivered
+ unacked.getMessage().setRedelivered(true);
// Ensure message is released for redelivery
if (!unacked.isQueueDeleted())
{
- unacked.entry.release();
+ unacked.release();
}
- // Mark message redelivered
- unacked.getMessage().setRedelivered(true);
// Deliver these messages out of the transaction as their delivery was never
// part of the transaction only the receive.
TransactionalContext deliveryContext;
if (!(_txnContext instanceof NonTransactionalContext))
{
- // if (_nonTransactedContext == null)
- {
- _nonTransactedContext =
+
+ deliveryContext =
new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
- }
- deliveryContext = _nonTransactedContext;
}
else
{
@@ -584,7 +546,7 @@ public class AMQChannel
if (!unacked.isQueueDeleted())
{
// Redeliver the messages to the front of the queue
- deliveryContext.deliver(unacked.entry, true);
+ deliveryContext.requeue(unacked);
// Deliver increments the message count but we have already deliverted this once so don't increment it again
// this was because deliver did an increment changed this.
}
@@ -592,11 +554,8 @@ public class AMQChannel
{
_log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity()
+ "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message.");
- // _log.error("Requested requeue of message:" + deliveryTag +
- // " but no queue defined using DeadLetter queue:" + getDeadLetterQueue());
- //
- // deliveryContext.deliver(unacked.message, getDeadLetterQueue(), false);
- //
+
+ unacked.discard(_storeContext);
}
}
else
@@ -604,25 +563,6 @@ public class AMQChannel
_log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists."
+ _unacknowledgedMessageMap.size());
- if (_log.isDebugEnabled())
- {
- _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
- {
- int count = 0;
-
- public boolean callback(UnacknowledgedMessage message) throws AMQException
- {
- _log.debug(
- (count++) + ": (" + message.getMessage().debugIdentity() + ")" + "[" + message.deliveryTag + "]");
-
- return false; // Continue
- }
-
- public void visitComplete()
- {
- }
- });
- }
}
}
@@ -636,8 +576,10 @@ public class AMQChannel
*/
public void resend(final boolean requeue) throws AMQException
{
- final List<UnacknowledgedMessage> msgToRequeue = new LinkedList<UnacknowledgedMessage>();
- final List<UnacknowledgedMessage> msgToResend = new LinkedList<UnacknowledgedMessage>();
+
+
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
if (_log.isDebugEnabled())
{
@@ -647,23 +589,25 @@ public class AMQChannel
// Process the Unacked-Map.
// Marking messages who still have a consumer for to be resent
// and those that don't to be requeued.
+
_unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
{
- public boolean callback(UnacknowledgedMessage message) throws AMQException
+ public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException
{
- AMQShortString consumerTag = message.consumerTag;
+
AMQMessage msg = message.getMessage();
msg.setRedelivered(true);
- if (consumerTag != null)
+ final Subscription subscription = message.getDeliveredSubscription();
+ if (subscription != null)
{
// Consumer exists
- if (_consumerTag2QueueMap.containsKey(consumerTag))
+ if (!subscription.isClosed())
{
- msgToResend.add(message);
+ msgToResend.put(deliveryTag, message);
}
else // consumer has gone
{
- msgToRequeue.add(message);
+ msgToRequeue.put(deliveryTag, message);
}
}
else
@@ -675,7 +619,7 @@ public class AMQChannel
{
if (requeue)
{
- msgToRequeue.add(message);
+ msgToRequeue.put(deliveryTag, message);
}
else
{
@@ -684,7 +628,8 @@ public class AMQChannel
}
else
{
- _log.info("Message.queue is null and no DeadLetter Queue so dropping message:" + message);
+ message.discard(_storeContext);
+ _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message);
}
}
@@ -697,6 +642,8 @@ public class AMQChannel
}
});
+ _unacknowledgedMessageMap.clear();
+
// Process Messages to Resend
if (_log.isDebugEnabled())
{
@@ -710,9 +657,15 @@ public class AMQChannel
}
}
- for (UnacknowledgedMessage message : msgToResend)
+ for (Map.Entry<Long, QueueEntry> entry : msgToResend.entrySet())
{
+ QueueEntry message = entry.getValue();
+ long deliveryTag = entry.getKey();
+
+
+
AMQMessage msg = message.getMessage();
+ AMQQueue queue = message.getQueue();
// Our Java Client will always suspend the channel when resending!
// If the client has requested the messages be resent then it is
@@ -727,46 +680,20 @@ public class AMQChannel
// else
// {
// release to allow it to be delivered
- message.entry.release();
// Without any details from the client about what has been processed we have to mark
// all messages in the unacked map as redelivered.
msg.setRedelivered(true);
- Subscription sub = message.entry.getDeliveredSubscription();
+ Subscription sub = message.getDeliveredSubscription();
if (sub != null)
{
- // Get the lock so we can tell if the sub scription has closed.
- // will stop delivery to this subscription until the lock is released.
- // note: this approach would allow the use of a single queue if the
- // PreDeliveryQueue would allow head additions.
- // In the Java Qpid client we are suspended whilst doing this so it is all rather Mute..
- // needs guidance from AMQP WG Model SIG
- synchronized (sub.getSendLock())
+
+ if(!queue.resend(message, sub))
{
- if (sub.isClosed())
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Subscription(" + System.identityHashCode(sub)
- + ") closed during resend so requeuing message");
- }
- // move this message to requeue
- msgToRequeue.add(message);
- }
- else
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Requeuing " + msg.debugIdentity() + " for resend via sub:"
- + System.identityHashCode(sub));
- }
-
- sub.addToResendQueue(message.entry);
- _unacknowledgedMessageMap.remove(message.deliveryTag);
- }
- } // sync(sub.getSendLock)
+ msgToRequeue.put(deliveryTag, message);
+ }
}
else
{
@@ -777,7 +704,7 @@ public class AMQChannel
+ ")to prevent loss");
}
// move this message to requeue
- msgToRequeue.add(message);
+ msgToRequeue.put(deliveryTag, message);
}
} // for all messages
// } else !isSuspend
@@ -795,13 +722,9 @@ public class AMQChannel
TransactionalContext deliveryContext;
if (!(_txnContext instanceof NonTransactionalContext))
{
- if (_nonTransactedContext == null)
- {
- _nonTransactedContext =
- new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
- }
- deliveryContext = _nonTransactedContext;
+ deliveryContext =
+ new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
}
else
{
@@ -809,14 +732,17 @@ public class AMQChannel
}
// Process Messages to Requeue at the front of the queue
- for (UnacknowledgedMessage message : msgToRequeue)
+ for (Map.Entry<Long, QueueEntry> entry : msgToRequeue.entrySet())
{
- message.entry.release();
- message.entry.setRedelivered(true);
+ QueueEntry message = entry.getValue();
+ long deliveryTag = entry.getKey();
+
+ message.release();
+ message.setRedelivered(true);
- deliveryContext.deliver(message.entry, true);
+ deliveryContext.requeue(message);
- _unacknowledgedMessageMap.remove(message.deliveryTag);
+ _unacknowledgedMessageMap.remove(deliveryTag);
}
}
@@ -827,38 +753,47 @@ public class AMQChannel
*
* @param queue the queue that has been deleted
*
- * @throws org.apache.qpid.AMQException if there is an error processing the unacked messages
*/
- public void queueDeleted(final AMQQueue queue) throws AMQException
+ /* public void queueDeleted(final AMQQueue queue)
{
- _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
+ try
{
- public boolean callback(UnacknowledgedMessage message) throws AMQException
+ _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
{
- if (message.getQueue() == queue)
+ public boolean callback(UnacknowledgedMessage message)
{
- try
+ if (message.getQueue() == queue)
{
- message.discard(_storeContext);
- message.setQueueDeleted(true);
+ try
+ {
+ message.discard(_storeContext);
+ message.setQueueDeleted(true);
+ }
+ catch (AMQException e)
+ {
+ _log.error(
+ "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e);
+ throw new RuntimeException(e);
+ }
}
- catch (AMQException e)
- {
- _log.error(
- "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e);
- }
+
+ return false;
}
- return false;
- }
+ public void visitComplete()
+ {
+ }
+ });
+ }
+ catch (AMQException e)
+ {
+ _log.error("Unexpected Error while handling deletion of queue", e);
+ throw new RuntimeException(e);
+ }
- public void visitComplete()
- {
- }
- });
}
-
+*/
/**
* Acknowledge one or more messages.
*
@@ -870,23 +805,7 @@ public class AMQChannel
*/
public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException
{
- synchronized (_unacknowledgedMessageMap.getLock())
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Unacked (PreAck) Size:" + _unacknowledgedMessageMap.size());
- }
-
- _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext);
-
- if (_log.isDebugEnabled())
- {
- _log.debug("Unacked (PostAck) Size:" + _unacknowledgedMessageMap.size());
- }
-
- }
-
- checkSuspension();
+ _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext);
}
/**
@@ -899,43 +818,22 @@ public class AMQChannel
return _unacknowledgedMessageMap;
}
- private void checkSuspension()
- {
- boolean suspend;
-
- suspend =
- ((_prefetch_HighWaterMark != 0) && (_unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark))
- || ((_prefetchSize != 0) && (_prefetchSize < _unacknowledgedMessageMap.getUnacknowledgeBytes()));
-
- setSuspended(suspend);
- }
public void setSuspended(boolean suspended)
{
- boolean isSuspended = _suspended.get();
- if (isSuspended && !suspended)
- {
- // Continue being suspended if we are above the _prefetch_LowWaterMark
- suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark;
- }
boolean wasSuspended = _suspended.getAndSet(suspended);
if (wasSuspended != suspended)
{
if (wasSuspended)
{
- _log.debug("Unsuspending channel " + this);
// may need to deliver queued messages
- for (AMQQueue q : _consumerTag2QueueMap.values())
+ for (Subscription s : _tag2SubscriptionMap.values())
{
- q.deliverAsync();
+ s.getQueue().deliverAsync(s);
}
}
- else
- {
- _log.debug("Suspending channel " + this);
- }
}
}
@@ -961,12 +859,7 @@ public class AMQChannel
public String toString()
{
- StringBuilder sb = new StringBuilder(30);
- sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(isTransactional());
- sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark);
- sb.append("/").append(_prefetch_HighWaterMark);
-
- return sb.toString();
+ return "["+_session.toString()+":"+_channelId+"]";
}
public void setDefaultQueue(AMQQueue queue)
@@ -984,14 +877,14 @@ public class AMQChannel
return _storeContext;
}
- public void processReturns(AMQProtocolSession session) throws AMQException
+ public void processReturns() throws AMQException
{
if (!_returnMessages.isEmpty())
{
for (RequiredDeliveryException bouncedMessage : _returnMessages)
{
AMQMessage message = bouncedMessage.getAMQMessage();
- session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(),
+ _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(),
new AMQShortString(bouncedMessage.getMessage()));
message.decrementReference(_storeContext);
@@ -1001,40 +894,68 @@ public class AMQChannel
}
}
- public boolean wouldSuspend(AMQMessage msg)
+
+ public TransactionalContext getTransactionalContext()
{
- if (isSuspended())
- {
- return true;
- }
- else
- {
- boolean willSuspend =
- ((_prefetch_HighWaterMark != 0) && ((_unacknowledgedMessageMap.size() + 1) > _prefetch_HighWaterMark));
- if (!willSuspend)
- {
- final long unackedSize = _unacknowledgedMessageMap.getUnacknowledgeBytes();
+ return _txnContext;
+ }
- willSuspend = (_prefetchSize != 0) && (unackedSize != 0) && (_prefetchSize < (msg.getSize() + unackedSize));
- }
+ public boolean isClosing()
+ {
+ return _closing;
+ }
- if (willSuspend)
- {
- setSuspended(true);
- }
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _session;
+ }
- return willSuspend;
- }
+ public FlowCreditManager getCreditManager()
+ {
+ return _creditManager;
+ }
+ public void setCredit(final long prefetchSize, final int prefetchCount)
+ {
+ _creditManager.setCreditLimits(prefetchSize, prefetchCount);
}
- public TransactionalContext getTransactionalContext()
+ public List<RequiredDeliveryException> getReturnMessages()
{
- return _txnContext;
+ return _returnMessages;
}
- public boolean isClosing()
+ public MessageStore getMessageStore()
{
- return _closing;
+ return _messageStore;
+ }
+
+ private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod()
+ {
+
+ public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ throws AMQException
+ {
+ getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag());
+ }
+ };
+
+ public ClientDeliveryMethod getClientDeliveryMethod()
+ {
+ return _clientDeliveryMethod;
+ }
+
+ private final RecordDeliveryMethod _recordDeliveryMethod = new RecordDeliveryMethod()
+ {
+
+ public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ {
+ addUnacknowledgedMessage(entry, deliveryTag, sub);
+ }
+ };
+
+ public RecordDeliveryMethod getRecordDeliveryMethod()
+ {
+ return _recordDeliveryMethod;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/Main.java b/java/broker/src/main/java/org/apache/qpid/server/Main.java
index d8a8cfb6d1..41d7f6c067 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/Main.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/Main.java
@@ -279,6 +279,12 @@ public class Main
ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator());
}
+
+ if(connectorConfig.useBiasedWrites)
+ {
+ System.setProperty("org.apache.qpid.use_write_biased_pool","true");
+ }
+
int port = connectorConfig.port;
String portStr = commandLine.getOptionValue("p");
diff --git a/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java
index d61bb8916a..3f1947d65a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java
@@ -39,19 +39,30 @@ import org.apache.qpid.server.queue.AMQMessage;
*/
public abstract class RequiredDeliveryException extends AMQException
{
- private final AMQMessage _amqMessage;
+ private AMQMessage _amqMessage;
public RequiredDeliveryException(String message, AMQMessage payload)
{
super(message);
+ setMessage(payload);
+ }
+
+
+ public RequiredDeliveryException(String message)
+ {
+ super(message);
+ }
+
+ public void setMessage(final AMQMessage payload)
+ {
+
// Increment the reference as this message is in the routing phase
// and so will have the ref decremented as routing fails.
// we need to keep this message around so we can return it in the
// handler. So increment here.
_amqMessage = payload.takeReference();
- // payload.incrementReference();
}
public AMQMessage getAMQMessage()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java
index 6ad704a5d8..caf34f13bd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java
@@ -22,11 +22,14 @@ package org.apache.qpid.server.ack;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
import java.util.ArrayList;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.txn.TxnOp;
+import org.apache.qpid.server.queue.QueueEntry;
/**
* A TxnOp implementation for handling accumulated acks
@@ -34,7 +37,7 @@ import org.apache.qpid.server.txn.TxnOp;
public class TxAck implements TxnOp
{
private final UnacknowledgedMessageMap _map;
- private final List <UnacknowledgedMessage> _unacked = new ArrayList<UnacknowledgedMessage>();
+ private final Map<Long, QueueEntry> _unacked = new HashMap<Long,QueueEntry>();
private List<Long> _individual;
private long _deliveryTag;
private boolean _multiple;
@@ -46,11 +49,12 @@ public class TxAck implements TxnOp
public void update(long deliveryTag, boolean multiple)
{
+ _unacked.clear();
if (!multiple)
{
if(_individual == null)
{
- _individual = new ArrayList<Long>();
+ _individual = new ArrayList<Long>();
}
//have acked a single message that is not part of
//the previously acked region so record
@@ -64,36 +68,29 @@ public class TxAck implements TxnOp
_deliveryTag = deliveryTag;
_multiple = true;
}
- _unacked.clear();
}
public void consolidate()
{
if(_unacked.isEmpty())
{
- consolidate(_unacked);
- }
-
- }
-
- private void consolidate(List<UnacknowledgedMessage> unacked)
- {
- //lookup all the unacked messages that have been acked in this transaction
- if (_multiple)
- {
- //get all the unacked messages for the accumulated
- //multiple acks
- _map.collect(_deliveryTag, true, unacked);
- }
- //get any unacked messages for individual acks outside the
- //range covered by multiple acks
- if(_individual != null)
- {
- for (Long tag : _individual)
+ //lookup all the unacked messages that have been acked in this transaction
+ if (_multiple)
{
- if(_deliveryTag < tag)
+ //get all the unacked messages for the accumulated
+ //multiple acks
+ _map.collect(_deliveryTag, true, _unacked);
+ }
+ if(_individual != null)
+ {
+ //get any unacked messages for individual acks outside the
+ //range covered by multiple acks
+ for (long tag : _individual)
{
- _map.collect(tag, false, unacked);
+ if(_deliveryTag < tag)
+ {
+ _map.collect(tag, false, _unacked);
+ }
}
}
}
@@ -101,12 +98,10 @@ public class TxAck implements TxnOp
public boolean checkPersistent() throws AMQException
{
-
-
consolidate();
//if any of the messages in unacked are persistent the txn
//buffer must be marked as persistent:
- for (UnacknowledgedMessage msg : _unacked)
+ for (QueueEntry msg : _unacked.values())
{
if (msg.getMessage().isPersistent())
{
@@ -119,8 +114,9 @@ public class TxAck implements TxnOp
public void prepare(StoreContext storeContext) throws AMQException
{
//make persistent changes, i.e. dequeue and decrementReference
- for (UnacknowledgedMessage msg : _unacked)
+ for (QueueEntry msg : _unacked.values())
{
+ msg.restoreCredit();
//Message has been ack so discard it. This will dequeue and decrement the reference.
msg.discard(storeContext);
@@ -133,7 +129,7 @@ public class TxAck implements TxnOp
//in memory counter) so if we failed in prepare for full
//txn, this op will have to compensate by fixing the count
//in memory (persistent changes will be rolled back by store)
- for (UnacknowledgedMessage msg : _unacked)
+ for (QueueEntry msg : _unacked.values())
{
msg.getMessage().takeReference();
}
@@ -142,7 +138,7 @@ public class TxAck implements TxnOp
public void commit(StoreContext storeContext)
{
//remove the unacked messages from the channels map
- _map.remove(_unacked);
+ _map.remove(_unacked);
}
public void rollback(StoreContext storeContext)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java
deleted file mode 100644
index 0112d3b388..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.ack;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.StoreContext;
-
-public class UnacknowledgedMessage
-{
- public final QueueEntry entry;
- public final AMQShortString consumerTag;
- public final long deliveryTag;
-
- private boolean _queueDeleted;
- private final UnacknowledgedMessageMap _unacknowledgeMessageMap;
-
-
- public UnacknowledgedMessage(QueueEntry entry,
- AMQShortString consumerTag,
- long deliveryTag,
- final UnacknowledgedMessageMap unacknowledgedMessageMap)
- {
- this.entry = entry;
- this.consumerTag = consumerTag;
- this.deliveryTag = deliveryTag;
- _unacknowledgeMessageMap = unacknowledgedMessageMap;
- }
-
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
- sb.append("Q:");
- sb.append(entry.getQueue());
- sb.append(" M:");
- sb.append(entry.getMessage());
- sb.append(" CT:");
- sb.append(consumerTag);
- sb.append(" DT:");
- sb.append(deliveryTag);
-
- return sb.toString();
- }
-
- public void discard(StoreContext storeContext) throws AMQException
- {
- synchronized(_unacknowledgeMessageMap)
- {
- if(_unacknowledgeMessageMap.contains(deliveryTag))
- {
-
- if (entry.getQueue() != null)
- {
- entry.getQueue().dequeue(storeContext, entry);
- }
- //if the queue is null then the message is waiting to be acked, but has been removed.
- entry.getMessage().decrementReference(storeContext);
- }
- }
-
- }
-
- public AMQMessage getMessage()
- {
- return entry.getMessage();
- }
-
- public AMQQueue getQueue()
- {
- return entry.getQueue();
- }
-
- public void setQueueDeleted(boolean queueDeleted)
- {
- _queueDeleted = queueDeleted;
- }
-
- public boolean isQueueDeleted()
- {
- return _queueDeleted;
- }
-}
-
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
index 5b0f3cf5eb..8e5b631f96 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
@@ -23,41 +23,41 @@ package org.apache.qpid.server.ack;
import java.util.Collection;
import java.util.List;
import java.util.Set;
+import java.util.Map;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.queue.QueueEntry;
public interface UnacknowledgedMessageMap
{
public interface Visitor
{
/**
- * @param message the message being iterated over
- * @return true to stop iteration, false to continue
+ * @param deliveryTag
+ *@param message the message being iterated over @return true to stop iteration, false to continue
* @throws AMQException
*/
- boolean callback(UnacknowledgedMessage message) throws AMQException;
+ boolean callback(final long deliveryTag, QueueEntry message) throws AMQException;
void visitComplete();
}
void visit(Visitor visitor) throws AMQException;
- Object getLock();
+ void add(long deliveryTag, QueueEntry message);
- void add(long deliveryTag, UnacknowledgedMessage message);
-
- void collect(Long deliveryTag, boolean multiple, List<UnacknowledgedMessage> msgs);
+ void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs);
boolean contains(long deliveryTag) throws AMQException;
- void remove(List<UnacknowledgedMessage> msgs);
+ void remove(Map<Long,QueueEntry> msgs);
- UnacknowledgedMessage remove(long deliveryTag);
+ QueueEntry remove(long deliveryTag);
- void drainTo(Collection<UnacknowledgedMessage> destination, long deliveryTag) throws AMQException;
+ void drainTo(Collection<QueueEntry> destination, long deliveryTag) throws AMQException;
- Collection<UnacknowledgedMessage> cancelAllMessages();
+ Collection<QueueEntry> cancelAllMessages();
void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException;
@@ -65,7 +65,7 @@ public interface UnacknowledgedMessageMap
void clear();
- UnacknowledgedMessage get(long deliveryTag);
+ QueueEntry get(long deliveryTag);
/**
* Get the set of delivery tags that are outstanding.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
index 5204f13e81..79208ab426 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
@@ -28,6 +28,10 @@ import java.util.Map;
import java.util.Set;
import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.txn.TransactionalContext;
public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
@@ -36,7 +40,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
private long _unackedSize;
- private Map<Long, UnacknowledgedMessage> _map;
+ private Map<Long, QueueEntry> _map;
private long _lastDeliveryTag;
@@ -45,10 +49,10 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
public UnacknowledgedMessageMapImpl(int prefetchLimit)
{
_prefetchLimit = prefetchLimit;
- _map = new LinkedHashMap<Long, UnacknowledgedMessage>(prefetchLimit);
+ _map = new LinkedHashMap<Long, QueueEntry>(prefetchLimit);
}
- public void collect(Long deliveryTag, boolean multiple, List<UnacknowledgedMessage> msgs)
+ public void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs)
{
if (multiple)
{
@@ -56,7 +60,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
else
{
- msgs.add(get(deliveryTag));
+ msgs.put(deliveryTag, get(deliveryTag));
}
}
@@ -69,26 +73,27 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public void remove(List<UnacknowledgedMessage> msgs)
+ public void remove(Map<Long,QueueEntry> msgs)
{
synchronized (_lock)
{
- for (UnacknowledgedMessage msg : msgs)
+ for (Long deliveryTag : msgs.keySet())
{
- remove(msg.deliveryTag);
+ remove(deliveryTag);
}
}
}
- public UnacknowledgedMessage remove(long deliveryTag)
+ public QueueEntry remove(long deliveryTag)
{
synchronized (_lock)
{
- UnacknowledgedMessage message = _map.remove(deliveryTag);
+ QueueEntry message = _map.remove(deliveryTag);
if(message != null)
{
_unackedSize -= message.getMessage().getSize();
+ message.restoreCredit();
}
return message;
@@ -99,21 +104,16 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
{
synchronized (_lock)
{
- Collection<UnacknowledgedMessage> currentEntries = _map.values();
- for (UnacknowledgedMessage msg : currentEntries)
+ Set<Map.Entry<Long, QueueEntry>> currentEntries = _map.entrySet();
+ for (Map.Entry<Long, QueueEntry> entry : currentEntries)
{
- visitor.callback(msg);
+ visitor.callback(entry.getKey().longValue(), entry.getValue());
}
visitor.visitComplete();
}
}
- public Object getLock()
- {
- return _lock;
- }
-
- public void add(long deliveryTag, UnacknowledgedMessage message)
+ public void add(long deliveryTag, QueueEntry message)
{
synchronized (_lock)
{
@@ -123,12 +123,12 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public Collection<UnacknowledgedMessage> cancelAllMessages()
+ public Collection<QueueEntry> cancelAllMessages()
{
synchronized (_lock)
{
- Collection<UnacknowledgedMessage> currentEntries = _map.values();
- _map = new LinkedHashMap<Long, UnacknowledgedMessage>(_prefetchLimit);
+ Collection<QueueEntry> currentEntries = _map.values();
+ _map = new LinkedHashMap<Long, QueueEntry>(_prefetchLimit);
_unackedSize = 0l;
return currentEntries;
}
@@ -160,14 +160,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public void drainTo(Collection<UnacknowledgedMessage> destination, long deliveryTag) throws AMQException
+ public void drainTo(Collection<QueueEntry> destination, long deliveryTag) throws AMQException
{
synchronized (_lock)
{
- Iterator<Map.Entry<Long, UnacknowledgedMessage>> it = _map.entrySet().iterator();
+ Iterator<Map.Entry<Long, QueueEntry>> it = _map.entrySet().iterator();
while (it.hasNext())
{
- Map.Entry<Long, UnacknowledgedMessage> unacked = it.next();
+ Map.Entry<Long, QueueEntry> unacked = it.next();
if (unacked.getKey() > deliveryTag)
{
@@ -175,10 +175,13 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() +
" When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString());
}
-
it.remove();
+
_unackedSize -= unacked.getValue().getMessage().getSize();
+ unacked.getValue().restoreCredit();
+
+
destination.add(unacked.getValue());
if (unacked.getKey() == deliveryTag)
{
@@ -188,7 +191,7 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public UnacknowledgedMessage get(long key)
+ public QueueEntry get(long key)
{
synchronized (_lock)
{
@@ -204,14 +207,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- private void collect(Long key, List<UnacknowledgedMessage> msgs)
+ private void collect(long key, Map<Long, QueueEntry> msgs)
{
synchronized (_lock)
{
- for (Map.Entry<Long, UnacknowledgedMessage> entry : _map.entrySet())
+ for (Map.Entry<Long, QueueEntry> entry : _map.entrySet())
{
- msgs.add(entry.getValue());
- if (entry.getKey().equals(key))
+ msgs.put(entry.getKey(),entry.getValue());
+ if (entry.getKey() == key)
{
break;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
index 8573902af4..bd3e5b1f72 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
@@ -30,11 +30,13 @@ import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.exchange.ExchangeFactory;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -176,11 +178,22 @@ public class VirtualHostConfiguration
boolean durable = queueConfiguration.getBoolean("durable" ,false);
boolean autodelete = queueConfiguration.getBoolean("autodelete", false);
String owner = queueConfiguration.getString("owner", null);
+ FieldTable arguments = null;
+ Integer priorities = queueConfiguration.getInteger("priorities", null);
+ if(priorities != null && priorities.intValue() > 1)
+ {
+ if(arguments == null)
+ {
+ arguments = new FieldTable();
+ }
+ arguments.put(new AMQShortString("x-qpid-priorities"), priorities);
+ }
+
- queue = new AMQQueue(queueName,
+ queue = AMQQueueFactory.createAMQQueueImpl(queueName,
durable,
owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */,
- autodelete /* Therefore autodelete makes no sence */, virtualHost);
+ autodelete /* Therefore autodelete makes no sence */, virtualHost, arguments);
if (queue.isDurable())
{
@@ -221,7 +234,7 @@ public class VirtualHostConfiguration
AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj));
- queue.bind(routingKey, null, exchange);
+ queue.bind(exchange, routingKey, null);
_logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'");
@@ -229,7 +242,7 @@ public class VirtualHostConfiguration
if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange())
{
- queue.bind(queue.getName(), null, virtualHost.getExchangeRegistry().getDefaultExchange());
+ queue.bind(virtualHost.getExchangeRegistry().getDefaultExchange(), queue.getName(), null);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
index 9ebb893362..8d24626b73 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
@@ -191,9 +191,7 @@ public abstract class AbstractExchange implements Exchange, Managable
{
_exchangeMbean.unregister();
}
- }
-
- abstract public Map<AMQShortString, List<AMQQueue>> getBindings();
+ }
public String toString()
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 636aa7eb03..9d4c090971 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -43,8 +43,8 @@ public class DefaultExchangeFactory implements ExchangeFactory
public DefaultExchangeFactory(VirtualHost host)
{
_host = host;
- registerExchangeType(DestNameExchange.TYPE);
- registerExchangeType(DestWildExchange.TYPE);
+ registerExchangeType(DirectExchange.TYPE);
+ registerExchangeType(TopicExchange.TYPE);
registerExchangeType(HeadersExchange.TYPE);
registerExchangeType(FanoutExchange.TYPE);
}
@@ -67,7 +67,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
if (exchType == null)
{
- throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null);
+ throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null);
}
Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete);
return e;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
index 98abf7977a..0ab8208d88 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
@@ -25,6 +25,7 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.protocol.ExchangeInitialiser;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -121,9 +122,9 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
* @param payload
* @throws AMQException if something goes wrong delivering data
*/
- public void routeContent(AMQMessage payload) throws AMQException
+ public void routeContent(IncomingMessage payload) throws AMQException
{
- final AMQShortString exchange = payload.getMessagePublishInfo().getExchange();
+ final AMQShortString exchange = payload.getExchange();
final Exchange exch = getExchange(exchange);
// there is a small window of opportunity for the exchange to be deleted in between
// the BasicPublish being received (where the exchange is validated) and the final
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java
deleted file mode 100644
index 6fa3686152..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.exchange;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.AMQShortStringTokenizer;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-import javax.management.JMException;
-import javax.management.MBeanException;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class DestWildExchange extends AbstractExchange
-{
-
- public static final ExchangeType<DestWildExchange> TYPE = new ExchangeType<DestWildExchange>()
- {
-
- public AMQShortString getName()
- {
- return ExchangeDefaults.TOPIC_EXCHANGE_CLASS;
- }
-
- public Class<DestWildExchange> getExchangeClass()
- {
- return DestWildExchange.class;
- }
-
- public DestWildExchange newInstance(VirtualHost host,
- AMQShortString name,
- boolean durable,
- int ticket,
- boolean autoDelete) throws AMQException
- {
- DestWildExchange exch = new DestWildExchange();
- exch.initialise(host, name, durable, ticket, autoDelete);
- return exch;
- }
-
- public AMQShortString getDefaultExchangeName()
- {
- return ExchangeDefaults.TOPIC_EXCHANGE_NAME;
- }
- };
-
-
- private static final Logger _logger = Logger.getLogger(DestWildExchange.class);
-
- private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _bindingKey2queues =
- new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
- private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _simpleBindingKey2queues =
- new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
- private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _wildCardBindingKey2queues =
- new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
-
- private static final byte TOPIC_SEPARATOR = (byte)'.';
- private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString(".");
- private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*");
- private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#");
- private ConcurrentHashMap<AMQShortString, AMQShortString[]> _bindingKey2Tokenized =
- new ConcurrentHashMap<AMQShortString, AMQShortString[]>();
- private static final byte HASH_BYTE = (byte)'#';
- private static final byte STAR_BYTE = (byte)'*';
-
- /** DestWildExchangeMBean class implements the management interface for the Topic exchanges. */
- @MBeanDescription("Management Bean for Topic Exchange")
- private final class DestWildExchangeMBean extends ExchangeMBean
- {
- @MBeanConstructor("Creates an MBean for AMQ topic exchange")
- public DestWildExchangeMBean() throws JMException
- {
- super();
- _exchangeType = "topic";
- init();
- }
-
- /** returns exchange bindings in tabular form */
- public TabularData bindings() throws OpenDataException
- {
- _bindingList = new TabularDataSupport(_bindinglistDataType);
- for (Map.Entry<AMQShortString, List<AMQQueue>> entry : _bindingKey2queues.entrySet())
- {
- AMQShortString key = entry.getKey();
- List<String> queueList = new ArrayList<String>();
-
- List<AMQQueue> queues = getMatchedQueues(key);
- for (AMQQueue q : queues)
- {
- queueList.add(q.getName().toString());
- }
-
- Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])};
- CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
- _bindingList.put(bindingData);
- }
-
- return _bindingList;
- }
-
- public void createNewBinding(String queueName, String binding) throws JMException
- {
- AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName));
- if (queue == null)
- {
- throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange.");
- }
-
- try
- {
- queue.bind(new AMQShortString(binding), null, DestWildExchange.this);
- }
- catch (AMQException ex)
- {
- throw new MBeanException(ex);
- }
- }
-
- } // End of MBean class
-
- public AMQShortString getType()
- {
- return ExchangeDefaults.TOPIC_EXCHANGE_CLASS;
- }
-
- public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException
- {
- assert queue != null;
- assert rKey != null;
-
- _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey);
-
- // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition
- List<AMQQueue> queueList = _bindingKey2queues.putIfAbsent(rKey, new CopyOnWriteArrayList<AMQQueue>());
-
-
-
-
-
-
-
- // if we got null back, no previous value was associated with the specified routing key hence
- // we need to read back the new value just put into the map
- if (queueList == null)
- {
- queueList = _bindingKey2queues.get(rKey);
- }
-
-
-
- if (!queueList.contains(queue))
- {
- queueList.add(queue);
-
-
- if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE))
- {
- AMQShortString routingKey = normalize(rKey);
- List<AMQQueue> queueList2 = _wildCardBindingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList<AMQQueue>());
-
- if(queueList2 == null)
- {
- queueList2 = _wildCardBindingKey2queues.get(routingKey);
- AMQShortStringTokenizer keyTok = routingKey.tokenize(TOPIC_SEPARATOR);
-
- ArrayList<AMQShortString> keyTokList = new ArrayList<AMQShortString>(keyTok.countTokens());
-
- while (keyTok.hasMoreTokens())
- {
- keyTokList.add(keyTok.nextToken());
- }
-
- _bindingKey2Tokenized.put(routingKey, keyTokList.toArray(new AMQShortString[keyTokList.size()]));
- }
- queueList2.add(queue);
-
- }
- else
- {
- List<AMQQueue> queueList2 = _simpleBindingKey2queues.putIfAbsent(rKey, new CopyOnWriteArrayList<AMQQueue>());
- if(queueList2 == null)
- {
- queueList2 = _simpleBindingKey2queues.get(rKey);
- }
- queueList2.add(queue);
-
- }
-
-
-
-
- }
- else if (_logger.isDebugEnabled())
- {
- _logger.debug("Queue " + queue + " is already registered with routing key " + rKey);
- }
-
-
-
- }
-
- private AMQShortString normalize(AMQShortString routingKey)
- {
- if(routingKey == null)
- {
- routingKey = AMQShortString.EMPTY_STRING;
- }
-
- AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR);
-
- List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>();
-
- while (routingTokens.hasMoreTokens())
- {
- subscriptionList.add(routingTokens.nextToken());
- }
-
- int size = subscriptionList.size();
-
- for (int index = 0; index < size; index++)
- {
- // if there are more levels
- if ((index + 1) < size)
- {
- if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN))
- {
- if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN))
- {
- // we don't need #.# delete this one
- subscriptionList.remove(index);
- size--;
- // redo this normalisation
- index--;
- }
-
- if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN))
- {
- // we don't want #.* swap to *.#
- // remove it and put it in at index + 1
- subscriptionList.add(index + 1, subscriptionList.remove(index));
- }
- }
- } // if we have more levels
- }
-
-
-
- AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING);
-
- return normalizedString;
- }
-
- public void route(AMQMessage payload) throws AMQException
- {
- MessagePublishInfo info = payload.getMessagePublishInfo();
-
- final AMQShortString routingKey = info.getRoutingKey();
-
- List<AMQQueue> queues = getMatchedQueues(routingKey);
- // if we have no registered queues we have nothing to do
- // TODO: add support for the immediate flag
- if ((queues == null) || queues.isEmpty())
- {
- if (info.isMandatory() || info.isImmediate())
- {
- String msg = "Topic " + routingKey + " is not known to " + this;
- throw new NoRouteException(msg, payload);
- }
- else
- {
- _logger.warn("No queues found for routing key " + routingKey);
- _logger.warn("Routing map contains: " + _bindingKey2queues);
-
- return;
- }
- }
-
- payload.enqueue(queues);
-
- }
-
- public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
- {
- return isBound(routingKey, queue);
- }
-
- public boolean isBound(AMQShortString routingKey, AMQQueue queue)
- {
- List<AMQQueue> queues = _bindingKey2queues.get(normalize(routingKey));
-
- return (queues != null) && queues.contains(queue);
- }
-
- public boolean isBound(AMQShortString routingKey)
- {
- List<AMQQueue> queues = _bindingKey2queues.get(normalize(routingKey));
-
- return (queues != null) && !queues.isEmpty();
- }
-
- public boolean isBound(AMQQueue queue)
- {
- for (List<AMQQueue> queues : _bindingKey2queues.values())
- {
- if (queues.contains(queue))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public boolean hasBindings()
- {
- return !_bindingKey2queues.isEmpty();
- }
-
- public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException
- {
- assert queue != null;
- assert rKey != null;
-
- List<AMQQueue> queues = _bindingKey2queues.get(rKey);
- if (queues == null)
- {
- throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName()
- + " with routing key " + rKey + ". No queue was registered with that _routing key");
-
- }
-
- boolean removedQ = queues.remove(queue);
- if (!removedQ)
- {
- throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName()
- + " with routing key " + rKey);
- }
-
-
- if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE))
- {
- AMQShortString bindingKey = normalize(rKey);
- List<AMQQueue> queues2 = _wildCardBindingKey2queues.get(bindingKey);
- queues2.remove(queue);
- if(queues2.isEmpty())
- {
- _wildCardBindingKey2queues.remove(bindingKey);
- _bindingKey2Tokenized.remove(bindingKey);
- }
-
- }
- else
- {
- List<AMQQueue> queues2 = _simpleBindingKey2queues.get(rKey);
- queues2.remove(queue);
- if(queues2.isEmpty())
- {
- _simpleBindingKey2queues.remove(rKey);
- }
-
- }
-
-
-
-
- if (queues.isEmpty())
- {
- _bindingKey2queues.remove(rKey);
- }
- }
-
- protected ExchangeMBean createMBean() throws AMQException
- {
- try
- {
- return new DestWildExchangeMBean();
- }
- catch (JMException ex)
- {
- _logger.error("Exception occured in creating the topic exchenge mbean", ex);
- throw new AMQException("Exception occured in creating the topic exchenge mbean", ex);
- }
- }
-
- public Map<AMQShortString, List<AMQQueue>> getBindings()
- {
- return _bindingKey2queues;
- }
-
- private List<AMQQueue> getMatchedQueues(AMQShortString routingKey)
- {
-
- List<AMQQueue> list = null;
-
- if(!_wildCardBindingKey2queues.isEmpty())
- {
-
-
- AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR);
-
- final int routingTokensCount = routingTokens.countTokens();
-
-
- AMQShortString[] routingkeyTokens = new AMQShortString[routingTokensCount];
-
- if(routingTokensCount == 1)
- {
- routingkeyTokens[0] =routingKey;
- }
- else
- {
-
-
- int token = 0;
- while (routingTokens.hasMoreTokens())
- {
-
- AMQShortString next = routingTokens.nextToken();
-
- routingkeyTokens[token++] = next;
- }
- }
- for (AMQShortString bindingKey : _wildCardBindingKey2queues.keySet())
- {
-
- AMQShortString[] bindingKeyTokens = _bindingKey2Tokenized.get(bindingKey);
-
-
- boolean matching = true;
- boolean done = false;
-
- int depthPlusRoutingSkip = 0;
- int depthPlusQueueSkip = 0;
-
- final int bindingKeyTokensCount = bindingKeyTokens.length;
-
- while (matching && !done)
- {
-
- if ((bindingKeyTokensCount == depthPlusQueueSkip) || (routingTokensCount == depthPlusRoutingSkip))
- {
- done = true;
-
- // if it was the routing key that ran out of digits
- if (routingTokensCount == depthPlusRoutingSkip)
- {
- if (bindingKeyTokensCount > depthPlusQueueSkip)
- { // a hash and it is the last entry
- matching =
- bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN)
- && (bindingKeyTokensCount == (depthPlusQueueSkip + 1));
- }
- }
- else if (routingTokensCount > depthPlusRoutingSkip)
- {
- // There is still more routing key to check
- matching = false;
- }
-
- continue;
- }
-
- // if the values on the two topics don't match
- if (!bindingKeyTokens[depthPlusQueueSkip].equals(routingkeyTokens[depthPlusRoutingSkip]))
- {
- if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_STAR_TOKEN))
- {
- depthPlusQueueSkip++;
- depthPlusRoutingSkip++;
-
- continue;
- }
- else if (bindingKeyTokens[depthPlusQueueSkip].equals(AMQP_HASH_TOKEN))
- {
- // Is this a # at the end
- if (bindingKeyTokensCount == (depthPlusQueueSkip + 1))
- {
- done = true;
-
- continue;
- }
-
- // otherwise # in the middle
- while (routingTokensCount > depthPlusRoutingSkip)
- {
- if (routingkeyTokens[depthPlusRoutingSkip].equals(bindingKeyTokens[depthPlusQueueSkip + 1]))
- {
- depthPlusQueueSkip += 2;
- depthPlusRoutingSkip++;
-
- break;
- }
-
- depthPlusRoutingSkip++;
- }
-
- continue;
- }
-
- matching = false;
- }
-
- depthPlusQueueSkip++;
- depthPlusRoutingSkip++;
- }
-
- if (matching)
- {
- if(list == null)
- {
- list = new ArrayList<AMQQueue>(_wildCardBindingKey2queues.get(bindingKey));
- }
- else
- {
- list.addAll(_wildCardBindingKey2queues.get(bindingKey));
- }
- }
- }
-
- }
- if(!_simpleBindingKey2queues.isEmpty())
- {
- List<AMQQueue> queues = _simpleBindingKey2queues.get(routingKey);
- if(list == null)
- {
- if(queues == null)
- {
- list = Collections.EMPTY_LIST;
- }
- else
- {
- list = new ArrayList<AMQQueue>(queues);
- }
- }
- else if(queues != null)
- {
- list.addAll(queues);
- }
-
- }
-
- return list;
-
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
index 12347c0278..5dcc2cf143 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
@@ -38,23 +38,22 @@ import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
-public class DestNameExchange extends AbstractExchange
+public class DirectExchange extends AbstractExchange
{
- private static final Logger _logger = Logger.getLogger(DestNameExchange.class);
+ private static final Logger _logger = Logger.getLogger(DirectExchange.class);
/**
* Maps from queue name to queue instances
*/
private final Index _index = new Index();
- public static final ExchangeType<DestNameExchange> TYPE = new ExchangeType<DestNameExchange>()
+ public static final ExchangeType<DirectExchange> TYPE = new ExchangeType<DirectExchange>()
{
public AMQShortString getName()
@@ -62,18 +61,18 @@ public class DestNameExchange extends AbstractExchange
return ExchangeDefaults.DIRECT_EXCHANGE_CLASS;
}
- public Class<DestNameExchange> getExchangeClass()
+ public Class<DirectExchange> getExchangeClass()
{
- return DestNameExchange.class;
+ return DirectExchange.class;
}
- public DestNameExchange newInstance(VirtualHost host,
+ public DirectExchange newInstance(VirtualHost host,
AMQShortString name,
boolean durable,
int ticket,
boolean autoDelete) throws AMQException
{
- DestNameExchange exch = new DestNameExchange();
+ DirectExchange exch = new DirectExchange();
exch.initialise(host,name,durable,ticket,autoDelete);
return exch;
}
@@ -88,10 +87,10 @@ public class DestNameExchange extends AbstractExchange
* MBean class implementing the management interfaces.
*/
@MBeanDescription("Management Bean for Direct Exchange")
- private final class DestNameExchangeMBean extends ExchangeMBean
+ private final class DirectExchangeMBean extends ExchangeMBean
{
@MBeanConstructor("Creates an MBean for AMQ direct exchange")
- public DestNameExchangeMBean() throws JMException
+ public DirectExchangeMBean() throws JMException
{
super();
_exchangeType = "direct";
@@ -132,7 +131,7 @@ public class DestNameExchange extends AbstractExchange
try
{
- queue.bind(new AMQShortString(binding), null, DestNameExchange.this);
+ queue.bind(DirectExchange.this, new AMQShortString(binding), null);
}
catch (AMQException ex)
{
@@ -147,7 +146,7 @@ public class DestNameExchange extends AbstractExchange
{
try
{
- return new DestNameExchangeMBean();
+ return new DirectExchangeMBean();
}
catch (JMException ex)
{
@@ -187,35 +186,21 @@ public class DestNameExchange extends AbstractExchange
}
}
- public void route(AMQMessage payload) throws AMQException
+ public void route(IncomingMessage payload) throws AMQException
{
- final MessagePublishInfo info = payload.getMessagePublishInfo();
- final AMQShortString routingKey = info.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : info.getRoutingKey();
+
+ final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey();
+
final List<AMQQueue> queues = (routingKey == null) ? null : _index.get(routingKey);
- if (queues == null || queues.isEmpty())
+
+ if (_logger.isDebugEnabled())
{
- String msg = "Routing key " + routingKey + " is not known to " + this;
- if (info.isMandatory() || info.isImmediate())
- {
- throw new NoRouteException(msg, payload);
- }
- else
- {
- _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue");
- _logger.warn(msg);
- }
+ _logger.debug("Publishing message to queue " + queues);
}
- else
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Publishing message to queue " + queues);
- }
payload.enqueue(queues);
- }
}
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
index 37cd85a8f8..06209c5458 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
@@ -23,7 +23,8 @@ package org.apache.qpid.server.exchange;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.queue.AMQMessage;
+
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -53,7 +54,7 @@ public interface Exchange
void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
- void route(AMQMessage message) throws AMQException;
+ void route(IncomingMessage message) throws AMQException;
/**
@@ -92,6 +93,6 @@ public interface Exchange
*/
boolean hasBindings();
- Map<AMQShortString, List<AMQQueue>> getBindings();
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
index f1b383eac9..e9fd4d548b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
@@ -26,10 +26,9 @@ import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -95,7 +94,7 @@ public class FanoutExchange extends AbstractExchange
try
{
- queue.bind(new AMQShortString(binding), null, FanoutExchange.this);
+ queue.bind(FanoutExchange.this, new AMQShortString(binding), null);
}
catch (AMQException ex)
{
@@ -183,32 +182,17 @@ public class FanoutExchange extends AbstractExchange
}
}
- public void route(AMQMessage payload) throws AMQException
+ public void route(IncomingMessage payload) throws AMQException
{
- final MessagePublishInfo publishInfo = payload.getMessagePublishInfo();
- final AMQShortString routingKey = publishInfo.getRoutingKey();
- if ((_queues == null) || _queues.isEmpty())
+
+
+ if (_logger.isDebugEnabled())
{
- String msg = "No queues bound to " + this;
- if (publishInfo.isMandatory() || publishInfo.isImmediate())
- {
- throw new NoRouteException(msg, payload);
- }
- else
- {
- _logger.warn(msg);
- }
+ _logger.debug("Publishing message to queue " + _queues);
}
- else
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Publishing message to queue " + _queues);
- }
- payload.enqueue(new ArrayList(_queues));
+ payload.enqueue(new ArrayList(_queues));
- }
}
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
index 68ad88c4cb..d1bea3410b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
@@ -31,7 +31,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -50,6 +50,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -240,7 +241,7 @@ public class HeadersExchange extends AbstractExchange
}
}
- public void route(AMQMessage payload) throws AMQException
+ public void route(IncomingMessage payload) throws AMQException
{
FieldTable headers = getHeaders(payload.getContentHeaderBody());
if (_logger.isDebugEnabled())
@@ -248,8 +249,10 @@ public class HeadersExchange extends AbstractExchange
_logger.debug("Exchange " + getName() + ": routing message with headers " + headers);
}
boolean routed = false;
+ Collection<AMQQueue> queues = new ArrayList<AMQQueue>();
for (Registration e : _bindings)
{
+
if (e.binding.matches(headers))
{
if (_logger.isDebugEnabled())
@@ -257,25 +260,12 @@ public class HeadersExchange extends AbstractExchange
_logger.debug("Exchange " + getName() + ": delivering message with headers " +
headers + " to " + e.queue.getName());
}
- payload.enqueue(e.queue);
- routed = true;
- }
- }
- if (!routed)
- {
-
- String msg = "Exchange " + getName() + ": message not routable.";
+ queues.add(e.queue);
- if (payload.getMessagePublishInfo().isMandatory() || payload.getMessagePublishInfo().isImmediate())
- {
- throw new NoRouteException(msg, payload);
- }
- else
- {
- _logger.warn(msg);
+ routed = true;
}
-
}
+ payload.enqueue(queues);
}
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
index eacdad8a8e..4f1f550e94 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
@@ -32,7 +32,7 @@ import org.apache.qpid.server.queue.AMQQueue;
/**
* An index of queues against routing key. Allows multiple queues to be stored
- * against the same key. Used in the DestNameExchange.
+ * against the same key. Used in the DirectExchange.
*/
class Index
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
index 7508e80f7f..db9beb6da7 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.exchange;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
/**
* Separated out from the ExchangeRegistry interface to allow components
@@ -36,5 +37,5 @@ public interface MessageRouter
*
* @throws org.apache.qpid.AMQException if something goes wrong delivering data
*/
- void routeContent(AMQMessage message) throws AMQException;
+ void routeContent(IncomingMessage message) throws AMQException;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java
index 1d6ab3842d..d18ad7ab14 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.RequiredDeliveryException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.IncomingMessage;
/**
* NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message
@@ -36,9 +37,9 @@ import org.apache.qpid.server.queue.AMQMessage;
*/
public class NoRouteException extends RequiredDeliveryException
{
- public NoRouteException(String msg, AMQMessage message)
+ public NoRouteException(String msg, AMQMessage amqMessage)
{
- super(msg, message);
+ super(msg, amqMessage);
}
public AMQConstant getReplyCode()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
new file mode 100644
index 0000000000..d07501a188
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
@@ -0,0 +1,651 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.AMQShortStringTokenizer;
+import org.apache.qpid.server.management.MBeanConstructor;
+import org.apache.qpid.server.management.MBeanDescription;
+import org.apache.qpid.server.queue.IncomingMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.exchange.topic.TopicParser;
+import org.apache.qpid.server.exchange.topic.TopicMatcherResult;
+import org.apache.qpid.server.filter.MessageFilter;
+import org.apache.qpid.server.filter.JMSSelectorFilter;
+
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.lang.ref.WeakReference;
+
+public class TopicExchange extends AbstractExchange
+{
+
+ public static final ExchangeType<TopicExchange> TYPE = new ExchangeType<TopicExchange>()
+ {
+
+ public AMQShortString getName()
+ {
+ return ExchangeDefaults.TOPIC_EXCHANGE_CLASS;
+ }
+
+ public Class<TopicExchange> getExchangeClass()
+ {
+ return TopicExchange.class;
+ }
+
+ public TopicExchange newInstance(VirtualHost host,
+ AMQShortString name,
+ boolean durable,
+ int ticket,
+ boolean autoDelete) throws AMQException
+ {
+ TopicExchange exch = new TopicExchange();
+ exch.initialise(host, name, durable, ticket, autoDelete);
+ return exch;
+ }
+
+ public AMQShortString getDefaultExchangeName()
+ {
+ return ExchangeDefaults.TOPIC_EXCHANGE_NAME;
+ }
+ };
+
+
+ private static final Logger _logger = Logger.getLogger(TopicExchange.class);
+
+/*
+ private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _bindingKey2queues =
+ new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
+ private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _simpleBindingKey2queues =
+ new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
+ private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _wildCardBindingKey2queues =
+ new ConcurrentHashMap<AMQShortString, List<AMQQueue>>();
+*/
+ // private ConcurrentHashMap<AMQShortString, AMQQueue> _routingKey2queue = new ConcurrentHashMap<AMQShortString, AMQQueue>();
+ private static final byte TOPIC_SEPARATOR = (byte)'.';
+ private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString(".");
+ private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*");
+ private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#");
+
+ private static final byte HASH_BYTE = (byte)'#';
+ private static final byte STAR_BYTE = (byte)'*';
+
+ private final TopicParser _parser = new TopicParser();
+
+ private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults =
+ new ConcurrentHashMap<AMQShortString, TopicExchangeResult>();
+
+ private final Map<Binding, FieldTable> _bindings = new HashMap<Binding, FieldTable>();
+
+ private final Map<String, WeakReference<JMSSelectorFilter<RuntimeException>>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter<RuntimeException>>>();
+
+ public static class Binding
+ {
+ private final AMQShortString _bindingKey;
+ private final AMQQueue _queue;
+
+ public Binding(AMQShortString bindingKey, AMQQueue queue)
+ {
+ _bindingKey = bindingKey;
+ _queue = queue;
+ }
+
+ public AMQShortString getBindingKey()
+ {
+ return _bindingKey;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ public int hashCode()
+ {
+ return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 + _queue.hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if(this == o)
+ {
+ return true;
+ }
+ if(o instanceof Binding)
+ {
+ Binding other = (Binding) o;
+ return (_queue == other._queue)
+ && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey));
+ }
+ return false;
+ }
+ }
+
+
+
+ private final class TopicExchangeResult implements TopicMatcherResult
+ {
+ private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>();
+ private final ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>>();
+
+ public void addUnfilteredQueue(AMQQueue queue)
+ {
+ Integer instances = _unfilteredQueues.get(queue);
+ if(instances == null)
+ {
+ _unfilteredQueues.put(queue, 1);
+ }
+ else
+ {
+ _unfilteredQueues.put(queue, instances + 1);
+ }
+ }
+
+ public void removeUnfilteredQueue(AMQQueue queue)
+ {
+ Integer instances = _unfilteredQueues.get(queue);
+ if(instances == 1)
+ {
+ _unfilteredQueues.remove(queue);
+ }
+ else
+ {
+ _unfilteredQueues.put(queue,instances - 1);
+ }
+
+ }
+
+
+ public void addFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter)
+ {
+ Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
+ if(filters == null)
+ {
+ filters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>();
+ _filteredQueues.put(queue, filters);
+ }
+ Integer instances = filters.get(filter);
+ if(instances == null)
+ {
+ filters.put(filter,1);
+ }
+ else
+ {
+ filters.put(filter, instances + 1);
+ }
+
+ }
+
+ public void removeFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter)
+ {
+ Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
+ if(filters != null)
+ {
+ Integer instances = filters.get(filter);
+ if(instances == 1)
+ {
+ filters.remove(filter);
+ if(filters.isEmpty())
+ {
+ _filteredQueues.remove(queue);
+ }
+ }
+ else if(instances != null)
+ {
+ filters.put(filter, instances - 1);
+ }
+
+ }
+
+ }
+
+ public void replaceQueueFilter(AMQQueue queue,
+ MessageFilter<RuntimeException> oldFilter,
+ MessageFilter<RuntimeException> newFilter)
+ {
+ Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
+ Map<MessageFilter<RuntimeException>,Integer> newFilters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>(filters);
+ Integer oldFilterInstances = filters.get(oldFilter);
+ if(oldFilterInstances == 1)
+ {
+ newFilters.remove(oldFilter);
+ }
+ else
+ {
+ newFilters.put(oldFilter, oldFilterInstances-1);
+ }
+ Integer newFilterInstances = filters.get(newFilter);
+ if(newFilterInstances == null)
+ {
+ newFilters.put(newFilter, 1);
+ }
+ else
+ {
+ newFilters.put(newFilter, newFilterInstances+1);
+ }
+ _filteredQueues.put(queue,newFilters);
+ }
+
+ public Collection<AMQQueue> processMessage(IncomingMessage msg, Collection<AMQQueue> queues)
+ {
+ if(queues == null)
+ {
+ if(_filteredQueues.isEmpty())
+ {
+ return new ArrayList<AMQQueue>(_unfilteredQueues.keySet());
+ }
+ else
+ {
+ queues = new HashSet<AMQQueue>();
+ }
+ }
+ else if(!(queues instanceof Set))
+ {
+ queues = new HashSet<AMQQueue>(queues);
+ }
+
+ queues.addAll(_unfilteredQueues.keySet());
+ if(!_filteredQueues.isEmpty())
+ {
+ for(Map.Entry<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>> entry : _filteredQueues.entrySet())
+ {
+ if(!queues.contains(entry.getKey()))
+ {
+ for(MessageFilter<RuntimeException> filter : entry.getValue().keySet())
+ {
+ if(filter.matches(msg))
+ {
+ queues.add(entry.getKey());
+ }
+ }
+ }
+ }
+ }
+ return queues;
+ }
+
+ }
+
+
+ /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */
+ @MBeanDescription("Management Bean for Topic Exchange")
+ private final class TopicExchangeMBean extends ExchangeMBean
+ {
+ @MBeanConstructor("Creates an MBean for AMQ topic exchange")
+ public TopicExchangeMBean() throws JMException
+ {
+ super();
+ _exchangeType = "topic";
+ init();
+ }
+
+ /** returns exchange bindings in tabular form */
+ public TabularData bindings() throws OpenDataException
+ {
+ _bindingList = new TabularDataSupport(_bindinglistDataType);
+ Map<String, List<String>> bindingData = new HashMap<String, List<String>>();
+ for (Binding binding : _bindings.keySet())
+ {
+ String key = binding.getBindingKey().toString();
+ List<String> queueNames = bindingData.get(key);
+ if(queueNames == null)
+ {
+ queueNames = new ArrayList<String>();
+ bindingData.put(key, queueNames);
+ }
+ queueNames.add(binding.getQueue().getName().toString());
+
+ }
+ for(Map.Entry<String, List<String>> entry : bindingData.entrySet())
+ {
+ Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) };
+ CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
+ _bindingList.put(bindingCompositeData);
+ }
+
+ return _bindingList;
+ }
+
+ public void createNewBinding(String queueName, String binding) throws JMException
+ {
+ AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName));
+ if (queue == null)
+ {
+ throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange.");
+ }
+
+ try
+ {
+ queue.bind(TopicExchange.this, new AMQShortString(binding), null);
+ }
+ catch (AMQException ex)
+ {
+ throw new MBeanException(ex);
+ }
+ }
+
+ } // End of MBean class
+
+ public AMQShortString getType()
+ {
+ return ExchangeDefaults.TOPIC_EXCHANGE_CLASS;
+ }
+
+ public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ assert queue != null;
+ assert rKey != null;
+
+ _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey);
+
+
+ AMQShortString routingKey;
+
+ if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE))
+ {
+ routingKey = normalize(rKey);
+ }
+ else
+ {
+ routingKey = rKey;
+ }
+
+ Binding binding = new Binding(rKey, queue);
+
+ if(_bindings.containsKey(binding))
+ {
+ FieldTable oldArgs = _bindings.get(binding);
+ TopicExchangeResult result = _topicExchangeResults.get(routingKey);
+
+ if(argumentsContainSelector(args))
+ {
+ if(argumentsContainSelector(oldArgs))
+ {
+ result.replaceQueueFilter(queue,createSelectorFilter(oldArgs), createSelectorFilter(args));
+ }
+ else
+ {
+ result.addFilteredQueue(queue,createSelectorFilter(args));
+ result.removeUnfilteredQueue(queue);
+ }
+ }
+ else
+ {
+ if(argumentsContainSelector(oldArgs))
+ {
+ result.addUnfilteredQueue(queue);
+ result.removeFilteredQueue(queue, createSelectorFilter(oldArgs));
+ }
+ else
+ {
+ // TODO - fix control flow
+ return;
+ }
+ }
+
+ }
+ else
+ {
+
+ TopicExchangeResult result = _topicExchangeResults.get(routingKey);
+ if(result == null)
+ {
+ result = new TopicExchangeResult();
+ if(argumentsContainSelector(args))
+ {
+ result.addFilteredQueue(queue, createSelectorFilter(args));
+ }
+ else
+ {
+ result.addUnfilteredQueue(queue);
+ }
+ _parser.addBinding(routingKey, result);
+ _topicExchangeResults.put(routingKey,result);
+ }
+ else
+ {
+ if(argumentsContainSelector(args))
+ {
+ result.addFilteredQueue(queue, createSelectorFilter(args));
+ }
+ else
+ {
+ result.addUnfilteredQueue(queue);
+ }
+ }
+ _bindings.put(binding, args);
+ }
+
+
+ }
+
+ private JMSSelectorFilter<RuntimeException> createSelectorFilter(final FieldTable args)
+ throws AMQException
+ {
+
+ final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue());
+ WeakReference<JMSSelectorFilter<RuntimeException>> selectorRef = _selectorCache.get(selectorString);
+ JMSSelectorFilter selector = null;
+
+ if(selectorRef == null || (selector = selectorRef.get())==null)
+ {
+ selector = new JMSSelectorFilter<RuntimeException>(selectorString);
+ _selectorCache.put(selectorString, new WeakReference<JMSSelectorFilter<RuntimeException>>(selector));
+ }
+ return selector;
+ }
+
+ private static boolean argumentsContainSelector(final FieldTable args)
+ {
+ return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0;
+ }
+
+ private AMQShortString normalize(AMQShortString routingKey)
+ {
+ if(routingKey == null)
+ {
+ routingKey = AMQShortString.EMPTY_STRING;
+ }
+
+ AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR);
+
+ List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>();
+
+ while (routingTokens.hasMoreTokens())
+ {
+ subscriptionList.add(routingTokens.nextToken());
+ }
+
+ int size = subscriptionList.size();
+
+ for (int index = 0; index < size; index++)
+ {
+ // if there are more levels
+ if ((index + 1) < size)
+ {
+ if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN))
+ {
+ if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN))
+ {
+ // we don't need #.# delete this one
+ subscriptionList.remove(index);
+ size--;
+ // redo this normalisation
+ index--;
+ }
+
+ if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN))
+ {
+ // we don't want #.* swap to *.#
+ // remove it and put it in at index + 1
+ subscriptionList.add(index + 1, subscriptionList.remove(index));
+ }
+ }
+ } // if we have more levels
+ }
+
+
+
+ AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING);
+
+ return normalizedString;
+ }
+
+ public void route(IncomingMessage payload) throws AMQException
+ {
+
+ final AMQShortString routingKey = payload.getRoutingKey();
+
+ Collection<AMQQueue> queues = getMatchedQueues(payload, routingKey);
+
+ if(queues == null || queues.isEmpty())
+ {
+ _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes.");
+ }
+
+ payload.enqueue(queues);
+
+ }
+
+ public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
+ {
+ return isBound(routingKey, queue);
+ }
+
+ public boolean isBound(AMQShortString routingKey, AMQQueue queue)
+ {
+ Binding binding = new Binding(routingKey, queue);
+
+ return _bindings.containsKey(binding);
+ }
+
+ public boolean isBound(AMQShortString routingKey)
+ {
+ for(Binding b : _bindings.keySet())
+ {
+ if(b.getBindingKey().equals(routingKey))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isBound(AMQQueue queue)
+ {
+ for(Binding b : _bindings.keySet())
+ {
+ if(b.getQueue().equals(queue))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean hasBindings()
+ {
+ return !_bindings.isEmpty();
+ }
+
+ public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ assert queue != null;
+ assert rKey != null;
+
+ Binding binding = new Binding(rKey, queue);
+
+
+ if (!_bindings.containsKey(binding))
+ {
+ throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName()
+ + " with routing key " + rKey + ".");
+ }
+
+ FieldTable bindingArgs = _bindings.remove(binding);
+ AMQShortString bindingKey = normalize(rKey);
+ TopicExchangeResult result = _topicExchangeResults.get(bindingKey);
+ if(argumentsContainSelector(bindingArgs))
+ {
+ result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs));
+ }
+ else
+ {
+ result.removeUnfilteredQueue(queue);
+ }
+
+ }
+
+ protected ExchangeMBean createMBean() throws AMQException
+ {
+ try
+ {
+ return new TopicExchangeMBean();
+ }
+ catch (JMException ex)
+ {
+ _logger.error("Exception occured in creating the topic exchenge mbean", ex);
+ throw new AMQException("Exception occured in creating the topic exchenge mbean", ex);
+ }
+ }
+
+ private Collection<AMQQueue> getMatchedQueues(IncomingMessage message, AMQShortString routingKey)
+ {
+
+ Collection<TopicMatcherResult> results = _parser.parse(routingKey);
+ if(results.isEmpty())
+ {
+ return Collections.EMPTY_SET;
+ }
+ else
+ {
+ Collection<AMQQueue> queues = results.size() == 1 ? null : new HashSet<AMQQueue>();
+ for(TopicMatcherResult result : results)
+ {
+
+ queues = ((TopicExchangeResult)result).processMessage(message, queues);
+ }
+ return queues;
+ }
+
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java
new file mode 100644
index 0000000000..8fdb91cbef
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKey.java
@@ -0,0 +1,40 @@
+package org.apache.qpid.server.exchange.headers;
+
+import org.apache.qpid.framing.AMQShortString;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class HeaderKey
+{
+ public static final HeaderKey UNKNOWN = new HeaderKey(new AMQShortString("<< UNKNOWN >>"));
+ private AMQShortString _key;
+
+ public HeaderKey(final AMQShortString key)
+ {
+ _key = key;
+ }
+
+ public String toString()
+ {
+ return _key.toString();
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java
new file mode 100644
index 0000000000..7be99a88c9
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderKeyDictionary.java
@@ -0,0 +1,50 @@
+package org.apache.qpid.server.exchange.headers;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class HeaderKeyDictionary
+{
+
+ private final Map<AMQShortString, HeaderKey> _dictionary = new HashMap<AMQShortString, HeaderKey>();
+
+
+ public HeaderKey get(final AMQShortString key)
+ {
+ HeaderKey headerKey = _dictionary.get(key);
+ return headerKey == null ? HeaderKey.UNKNOWN : headerKey;
+ }
+
+ public HeaderKey getOrCreate(final AMQShortString key)
+ {
+ HeaderKey headerKey = _dictionary.get(key);
+ if(headerKey == null)
+ {
+ headerKey = new HeaderKey(key);
+ _dictionary.put(key, headerKey);
+ }
+ return headerKey;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java
new file mode 100644
index 0000000000..518064bb29
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeaderMatcherResult.java
@@ -0,0 +1,25 @@
+package org.apache.qpid.server.exchange.headers;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class HeaderMatcherResult
+{
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java
new file mode 100644
index 0000000000..9da93d483a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersMatcherDFAState.java
@@ -0,0 +1,339 @@
+package org.apache.qpid.server.exchange.headers;
+
+import org.apache.qpid.framing.AMQTypedValue;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.exchange.topic.TopicMatcherDFAState;
+import org.apache.qpid.server.exchange.topic.TopicWord;
+import org.apache.qpid.server.exchange.topic.TopicMatcherResult;
+
+import java.util.*;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class HeadersMatcherDFAState
+{
+
+
+ private final Collection<HeaderMatcherResult> _results;
+ private final Map<HeaderKey, Map<AMQTypedValue,HeadersMatcherDFAState>> _nextStateMap;
+ private final HeaderKeyDictionary _dictionary;
+
+ public HeadersMatcherDFAState(Map<HeaderKey, Map<AMQTypedValue,HeadersMatcherDFAState>> nextStateMap,
+ Collection<HeaderMatcherResult> results,
+ HeaderKeyDictionary dictionary)
+ {
+ _nextStateMap = nextStateMap;
+ _results = results;
+ _dictionary = dictionary;
+ }
+
+
+ public Collection<HeaderMatcherResult> match(final FieldTable table)
+ {
+ return match(table.iterator());
+ }
+
+
+
+ public Collection<HeaderMatcherResult> match(Iterator<Map.Entry<AMQShortString,AMQTypedValue>> fieldTableIterator)
+ {
+
+ if(_nextStateMap.isEmpty())
+ {
+ return _results;
+ }
+
+ while(fieldTableIterator.hasNext())
+ {
+
+ Map.Entry<AMQShortString, AMQTypedValue> fieldTableEntry = fieldTableIterator.next();
+ HeaderKey key = _dictionary.get(fieldTableEntry.getKey());
+ if(key != HeaderKey.UNKNOWN)
+ {
+ Map<AMQTypedValue, HeadersMatcherDFAState> valueToStateMap = _nextStateMap.get(key);
+
+ if(valueToStateMap != null)
+ {
+ HeadersMatcherDFAState nextState = valueToStateMap.get(fieldTableEntry.getValue());
+
+ if(nextState == null)
+ {
+ nextState = valueToStateMap.get(null);
+ }
+ if(nextState != null && nextState != this)
+ {
+ return nextState.match(fieldTableIterator);
+ }
+ }
+
+ }
+ }
+
+ return _results;
+
+ }
+
+
+ HeadersMatcherDFAState mergeStateMachines(HeadersMatcherDFAState otherStateMachine)
+ {
+
+ assert(otherStateMachine._dictionary == _dictionary);
+
+ Map<Set<HeadersMatcherDFAState>, HeadersMatcherDFAState> newStateMap= new HashMap<Set<HeadersMatcherDFAState>, HeadersMatcherDFAState>();
+
+ Collection<HeaderMatcherResult> results;
+
+ if(_results.isEmpty())
+ {
+ results = otherStateMachine._results;
+ }
+ else if(otherStateMachine._results.isEmpty())
+ {
+ results = _results;
+ }
+ else
+ {
+ results = new HashSet<HeaderMatcherResult>(_results);
+ results.addAll(otherStateMachine._results);
+ }
+
+
+ final Map<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> newNextStateMap = new HashMap<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>>();
+
+ HeadersMatcherDFAState newState = new HeadersMatcherDFAState(newNextStateMap, results, _dictionary);
+
+
+ Set<HeadersMatcherDFAState> oldStates = new HashSet<HeadersMatcherDFAState>();
+ oldStates.add(this);
+ oldStates.add(otherStateMachine);
+
+ newStateMap.put(oldStates, newState);
+
+ mergeStateMachines(oldStates, newNextStateMap, newStateMap);
+
+ return newState;
+
+
+ }
+
+ private void mergeStateMachines(final Set<HeadersMatcherDFAState> oldStates,
+ final Map<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> newNextStateMap,
+ final Map<Set<HeadersMatcherDFAState>, HeadersMatcherDFAState> newStateMap)
+ {
+ Map<HeaderKey, Map<AMQTypedValue, Set<HeadersMatcherDFAState>>> nfaMap = new HashMap<HeaderKey, Map<AMQTypedValue, Set<HeadersMatcherDFAState>>>();
+
+ Set<HeaderKey> distinctKeys = new HashSet<HeaderKey>();
+
+ for(HeadersMatcherDFAState state : oldStates)
+ {
+ Map<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> map = state._nextStateMap;
+
+ for(Map.Entry<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> entry : map.entrySet())
+ {
+ Map<AMQTypedValue, Set<HeadersMatcherDFAState>> valueToStatesMap = nfaMap.get(entry.getKey());
+
+ if(valueToStatesMap == null)
+ {
+ valueToStatesMap = new HashMap<AMQTypedValue, Set<HeadersMatcherDFAState>>();
+ nfaMap.put(entry.getKey(), valueToStatesMap);
+ }
+
+ for(Map.Entry<AMQTypedValue, HeadersMatcherDFAState> valueToStateEntry : entry.getValue().entrySet())
+ {
+ Set<HeadersMatcherDFAState> states = valueToStatesMap.get(valueToStateEntry.getKey());
+ if(states == null)
+ {
+ states = new HashSet<HeadersMatcherDFAState>();
+ valueToStatesMap.put(valueToStateEntry.getKey(),states);
+ }
+ states.add(valueToStateEntry.getValue());
+ }
+
+ distinctKeys.add(entry.getKey());
+ }
+ }
+
+ Map<HeaderKey, Set<HeadersMatcherDFAState>> anyValueStates = new HashMap<HeaderKey, Set<HeadersMatcherDFAState>>();
+
+ for(HeaderKey distinctKey : distinctKeys)
+ {
+ Map<AMQTypedValue, Set<HeadersMatcherDFAState>> valueToStateMap = nfaMap.get(distinctKey);
+ if(valueToStateMap != null)
+ {
+ Set<HeadersMatcherDFAState> statesForKeyDefault = valueToStateMap.get(null);
+ if(statesForKeyDefault != null)
+ {
+ anyValueStates.put(distinctKey, statesForKeyDefault);
+ }
+ }
+ }
+
+ // add the defaults for "null" to all other specified values of a given header key
+
+ for( Map.Entry<HeaderKey,Map<AMQTypedValue,Set<HeadersMatcherDFAState>>> entry : nfaMap.entrySet())
+ {
+ Map<AMQTypedValue, Set<HeadersMatcherDFAState>> valueToStatesMap = entry.getValue();
+ for(Map.Entry<AMQTypedValue, Set<HeadersMatcherDFAState>> valueToStates : valueToStatesMap.entrySet())
+ {
+ if(valueToStates.getKey() != null)
+ {
+
+
+ Set<HeadersMatcherDFAState> defaults = anyValueStates.get(entry.getKey());
+ if(defaults != null)
+ {
+ valueToStates.getValue().addAll(defaults);
+ }
+ }
+ }
+ }
+
+ // if a given header key is not mentioned in the map of a machine; then that machine would stay at the same state
+ // for that key.
+ for(HeaderKey distinctKey : distinctKeys)
+ {
+ Map<AMQTypedValue, Set<HeadersMatcherDFAState>> valueToStatesMap = nfaMap.get(distinctKey);
+ for(HeadersMatcherDFAState oldState : oldStates)
+ {
+ if(!oldState._nextStateMap.containsKey(distinctKey))
+ {
+ for(Set<HeadersMatcherDFAState> endStates : valueToStatesMap.values())
+ {
+ endStates.add(oldState);
+ }
+ }
+ }
+ }
+
+
+
+
+ for(Map.Entry<HeaderKey,Map<AMQTypedValue,Set<HeadersMatcherDFAState>>> transitionClass : nfaMap.entrySet())
+ {
+ Map<AMQTypedValue, HeadersMatcherDFAState> valueToDFAState = newNextStateMap.get(transitionClass.getKey());
+ if(valueToDFAState == null)
+ {
+ valueToDFAState = new HashMap<AMQTypedValue, HeadersMatcherDFAState>();
+ newNextStateMap.put(transitionClass.getKey(), valueToDFAState);
+ }
+
+ for(Map.Entry<AMQTypedValue,Set<HeadersMatcherDFAState>> transition : transitionClass.getValue().entrySet())
+ {
+ Set<HeadersMatcherDFAState> destinations = transition.getValue();
+
+
+ HeadersMatcherDFAState nextState = newStateMap.get(destinations);
+
+ if(nextState == null)
+ {
+
+ if(destinations.size() == 1)
+ {
+ nextState = destinations.iterator().next();
+ newStateMap.put(destinations, nextState);
+ }
+ else
+ {
+ Collection<HeaderMatcherResult> results;
+
+ Set<Collection<HeaderMatcherResult>> resultSets = new HashSet<Collection<HeaderMatcherResult>>();
+ for(HeadersMatcherDFAState destination : destinations)
+ {
+ resultSets.add(destination._results);
+ }
+ resultSets.remove(Collections.EMPTY_SET);
+ if(resultSets.size() == 0)
+ {
+ results = Collections.EMPTY_SET;
+ }
+ else if(resultSets.size() == 1)
+ {
+ results = resultSets.iterator().next();
+ }
+ else
+ {
+ results = new HashSet<HeaderMatcherResult>();
+ for(Collection<HeaderMatcherResult> oldResult : resultSets)
+ {
+ results.addAll(oldResult);
+ }
+ }
+
+ final Map<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> nextStateMap = new HashMap<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>>();
+
+ nextState = new HeadersMatcherDFAState(nextStateMap, results, _dictionary);
+ newStateMap.put(destinations, nextState);
+
+ mergeStateMachines(
+ destinations,
+ nextStateMap,
+ newStateMap);
+
+
+ }
+
+
+ }
+ valueToDFAState.put(transition.getKey(),nextState);
+ }
+ }
+
+
+
+ final ArrayList<HeaderKey> removeKeyList = new ArrayList<HeaderKey>();
+
+ for(Map.Entry<HeaderKey,Map<AMQTypedValue,HeadersMatcherDFAState>> entry : _nextStateMap.entrySet())
+ {
+ final ArrayList<AMQTypedValue> removeValueList = new ArrayList<AMQTypedValue>();
+
+ for(Map.Entry<AMQTypedValue,HeadersMatcherDFAState> valueToDFAState : entry.getValue().entrySet())
+ {
+ if(valueToDFAState.getValue() == this)
+ {
+ HeadersMatcherDFAState defaultState = entry.getValue().get(null);
+ if(defaultState == null || defaultState == this)
+ {
+ removeValueList.add(valueToDFAState.getKey());
+ }
+ }
+ }
+
+ for(AMQTypedValue removeValue : removeValueList)
+ {
+ entry.getValue().remove(removeValue);
+ }
+
+ if(entry.getValue().isEmpty())
+ {
+ removeKeyList.add(entry.getKey());
+ }
+
+ }
+
+ for(HeaderKey removeKey : removeKeyList)
+ {
+ _nextStateMap.remove(removeKey);
+ }
+
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java
new file mode 100644
index 0000000000..85e74122c3
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/headers/HeadersParser.java
@@ -0,0 +1,439 @@
+package org.apache.qpid.server.exchange.headers;
+
+import org.apache.qpid.framing.*;
+
+import java.util.*;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class HeadersParser
+{
+
+ private final HeaderKeyDictionary _dictionary = new HeaderKeyDictionary();
+ private static final AMQShortString MATCHING_TYPE_KEY = new AMQShortString("x-match");
+ private static final String ANY_MATCHING = "any";
+ private static final AMQShortString RESERVED_KEY_PREFIX = new AMQShortString("x-");
+
+
+ HeadersMatcherDFAState createStateMachine(FieldTable bindingArguments, HeaderMatcherResult result)
+ {
+ String matchingType = bindingArguments.getString(MATCHING_TYPE_KEY);
+ boolean matchAny = matchingType.equalsIgnoreCase(ANY_MATCHING);
+ if(matchAny)
+ {
+ return createStateMachineForAnyMatch(bindingArguments, result);
+ }
+ else
+ {
+ return createStateMachineForAllMatch(bindingArguments, result);
+ }
+
+
+ }
+
+
+ private HeadersMatcherDFAState createStateMachineForAnyMatch(final FieldTable bindingArguments,
+ final HeaderMatcherResult result)
+ {
+
+ // DFAs for "any" matches have only two states, "not-matched" and "matched"... they start in the former
+ // and upon meeting any of the criteria they move to the latter
+
+ //noinspection unchecked
+ final HeadersMatcherDFAState successState =
+ new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary);
+
+ Map<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>> nextStateMap =
+ new HashMap<HeaderKey, Map<AMQTypedValue, HeadersMatcherDFAState>>();
+
+ Set<AMQShortString> seenKeys = new HashSet<AMQShortString>();
+
+ Iterator<Map.Entry<AMQShortString, AMQTypedValue>> tableIterator = bindingArguments.iterator();
+
+ while(tableIterator.hasNext())
+ {
+ final Map.Entry<AMQShortString, AMQTypedValue> entry = tableIterator.next();
+ final AMQShortString key = entry.getKey();
+ final AMQTypedValue value = entry.getValue();
+
+
+ if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX))
+ {
+ final AMQType type = value.getType();
+
+ final HeaderKey headerKey = _dictionary.getOrCreate(key);
+ final Map<AMQTypedValue, HeadersMatcherDFAState> valueMap;
+
+ if(type == AMQType.VOID ||
+ ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0))
+ {
+ valueMap = Collections.singletonMap(null,successState);
+
+ }
+ else
+ {
+ valueMap = Collections.singletonMap(value,successState);
+ }
+ nextStateMap.put(headerKey,valueMap);
+
+ }
+
+ }
+
+ if(seenKeys.size() == 0)
+ {
+ return successState;
+ }
+ else
+ {
+ return new HeadersMatcherDFAState(nextStateMap,Collections.EMPTY_SET,_dictionary);
+ }
+
+
+ }
+
+
+ private HeadersMatcherDFAState createStateMachineForAllMatch(final FieldTable bindingArguments,
+ final HeaderMatcherResult result)
+ {
+ // DFAs for "all" matches have a "success" state, a "fail" state, and states for every subset of
+ // matches which are possible, starting with the empty subset. For example if we have a binding
+ // { x-match="all"
+ // a=1
+ // b=1
+ // c=1
+ // d=1 }
+ // Then we would have the following states
+ // (1) Seen none of a, b, c, or d
+ // (2) Seen a=1 ; none of b,c, or d
+ // (3) Seen b=1 ; none of a,c, or d
+ // (4) Seen c=1 ; none of a,b, or d
+ // (5) Seen d=1 ; none of a,b, or c
+ // (6) Seen a=1,b=1 ; none of c,d
+ // (7) Seen a=1,c=1 ; none of b,d
+ // (8) Seen a=1,d=1 ; none of b,c
+ // (9) Seen b=1,c=1 ; none of a,d
+ //(10) Seen b=1,d=1 ; none of c,d
+ //(11) Seen c=1,d=1 ; none of a,b
+ //(12) Seen a=1,b=1,c=1 ; not d
+ //(13) Seen a=1,b=1,d=1 ; not c
+ //(14) Seen a=1,c=1,d=1 ; not b
+ //(15) Seen b=1,c=1,d=1 ; not a
+ //(16) success
+ //(17) fail
+ //
+ // All states but (16) can transition to (17); additionally:
+ // (1) can transition to (2),(3),(4),(5)
+ // (2) can transition to (6),(7),(8)
+ // (3) can transition to (6),(9),(10)
+ // (4) can transition to (7),(9),(11)
+ // (5) can transition to (8),(10),(11)
+ // (6) can transition to (12),(13)
+ // (7) can transition to (12),(14)
+ // (8) can transition to (13),(14)
+ // (9) can transition to (12),(15)
+ //(10) can transition to (13),(15)
+ //(11) can transition to (14),(15)
+ //(12)-(15) can transition to (16)
+
+ Set<AMQShortString> seenKeys = new HashSet<AMQShortString>();
+ List<KeyValuePair> requiredTerms = new ArrayList<KeyValuePair>(bindingArguments.size());
+
+ Iterator<Map.Entry<AMQShortString, AMQTypedValue>> tableIterator = bindingArguments.iterator();
+
+
+
+ while(tableIterator.hasNext())
+ {
+ final Map.Entry<AMQShortString, AMQTypedValue> entry = tableIterator.next();
+ final AMQShortString key = entry.getKey();
+ final AMQTypedValue value = entry.getValue();
+
+
+ if(seenKeys.add(key) && !key.startsWith(RESERVED_KEY_PREFIX))
+ {
+ final AMQType type = value.getType();
+
+ if(type == AMQType.VOID ||
+ ((type == AMQType.ASCII_STRING || type == AMQType.WIDE_STRING) && ((CharSequence)value.getValue()).length() == 0))
+ {
+ requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),null));
+ }
+ else
+ {
+ requiredTerms.add(new KeyValuePair(_dictionary.getOrCreate(key),value));
+ }
+ }
+
+ }
+
+ final HeadersMatcherDFAState successState =
+ new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.singleton(result),_dictionary);
+
+ final HeadersMatcherDFAState failState =
+ new HeadersMatcherDFAState(Collections.EMPTY_MAP,Collections.EMPTY_SET,_dictionary);
+
+ Map<Set<KeyValuePair>, HeadersMatcherDFAState> notSeenTermsToStateMap =
+ new HashMap<Set<KeyValuePair>, HeadersMatcherDFAState>();
+
+ notSeenTermsToStateMap.put(Collections.EMPTY_SET, successState);
+
+
+ final int numberOfTerms = requiredTerms.size();
+
+ for(int numMissingTerms = 1; numMissingTerms <= numberOfTerms; numMissingTerms++)
+ {
+ int[] pos = new int[numMissingTerms];
+ for(int i = 0; i < numMissingTerms; i++)
+ {
+ pos[i] = i;
+ }
+
+ final int maxTermValue = (numberOfTerms - (numMissingTerms - 1));
+
+ while(pos[0] < maxTermValue)
+ {
+
+ Set<KeyValuePair> stateSet = new HashSet<KeyValuePair>();
+ for(int posIndex = 0; posIndex < pos.length; posIndex++)
+ {
+ stateSet.add(requiredTerms.get(pos[posIndex]));
+ }
+
+ final Map<HeaderKey, Map<AMQTypedValue,HeadersMatcherDFAState>> nextStateMap =
+ new HashMap<HeaderKey, Map<AMQTypedValue,HeadersMatcherDFAState>>();
+
+
+ for(int posIndex = 0; posIndex < pos.length; posIndex++)
+ {
+ KeyValuePair nextTerm = requiredTerms.get(pos[posIndex]);
+ HashSet<KeyValuePair> nextStateSet =
+ new HashSet<KeyValuePair>(stateSet);
+ nextStateSet.remove(nextTerm);
+
+ Map<AMQTypedValue, HeadersMatcherDFAState> valueToStateMap =
+ new HashMap<AMQTypedValue, HeadersMatcherDFAState>();
+ nextStateMap.put(nextTerm._key, valueToStateMap);
+
+ valueToStateMap.put( nextTerm._value,notSeenTermsToStateMap.get(nextStateSet));
+ if(nextTerm._value != null)
+ {
+ valueToStateMap.put(null, failState);
+ }
+
+
+ }
+
+
+ HeadersMatcherDFAState newState = new HeadersMatcherDFAState(nextStateMap, Collections.EMPTY_SET, _dictionary);
+
+ notSeenTermsToStateMap.put(stateSet, newState);
+
+ int i = numMissingTerms;
+ while(i-- != 0)
+ {
+ if(++pos[i] <= numberOfTerms -(numMissingTerms-i))
+ {
+ int k = pos[i];
+ for(int j = i+1; j < numMissingTerms; j++)
+ {
+ pos[j] = ++k;
+ }
+ break;
+ }
+ }
+ }
+
+
+
+
+ }
+
+
+ return notSeenTermsToStateMap.get(new HashSet<KeyValuePair>(requiredTerms));
+
+
+
+ }
+
+ public static void main(String[] args) throws AMQFrameDecodingException
+ {
+
+ FieldTable bindingTable = new FieldTable();
+
+ bindingTable.setString(new AMQShortString("x-match"),"all");
+ bindingTable.setInteger("a",1);
+ bindingTable.setVoid(new AMQShortString("b"));
+ bindingTable.setString("c","");
+ bindingTable.setInteger("d",4);
+ bindingTable.setInteger("e",1);
+
+
+
+ FieldTable bindingTable2 = new FieldTable();
+ bindingTable2.setString(new AMQShortString("x-match"),"all");
+ bindingTable2.setInteger("a",1);
+ bindingTable2.setVoid(new AMQShortString("b"));
+ bindingTable2.setString("c","");
+ bindingTable2.setInteger("d",4);
+ bindingTable2.setInteger("e",1);
+ bindingTable2.setInteger("f",1);
+
+
+ FieldTable table = new FieldTable();
+ table.setInteger("a",1);
+ table.setInteger("b",2);
+ table.setString("c","");
+ table.setInteger("d",4);
+ table.setInteger("e",1);
+ table.setInteger("f",1);
+ table.setInteger("h",1);
+ table.setInteger("i",1);
+ table.setInteger("j",1);
+ table.setInteger("k",1);
+ table.setInteger("l",1);
+
+ org.apache.mina.common.ByteBuffer buffer = org.apache.mina.common.ByteBuffer.allocate( (int) table.getEncodedSize());
+ EncodingUtils.writeFieldTableBytes(buffer, table);
+ buffer.flip();
+
+ FieldTable table2 = EncodingUtils.readFieldTable(buffer);
+
+
+
+ FieldTable bindingTable3 = new FieldTable();
+ bindingTable3.setString(new AMQShortString("x-match"),"any");
+ bindingTable3.setInteger("a",1);
+ bindingTable3.setInteger("b",3);
+
+
+ FieldTable bindingTable4 = new FieldTable();
+ bindingTable4.setString(new AMQShortString("x-match"),"any");
+ bindingTable4.setVoid(new AMQShortString("a"));
+
+
+ FieldTable bindingTable5 = new FieldTable();
+ bindingTable5.setString(new AMQShortString("x-match"),"all");
+ bindingTable5.setString(new AMQShortString("h"),"hello");
+
+ for(int i = 0; i < 100; i++)
+ {
+ printMatches(new FieldTable[] {bindingTable5} , table2);
+ }
+
+
+
+ }
+
+
+
+ private static void printMatches(final FieldTable[] bindingKeys, final FieldTable routingKey)
+ {
+ HeadersMatcherDFAState sm = null;
+ Map<HeaderMatcherResult, String> resultMap = new HashMap<HeaderMatcherResult, String>();
+
+ HeadersParser parser = new HeadersParser();
+
+ for(int i = 0; i < bindingKeys.length; i++)
+ {
+ HeaderMatcherResult r = new HeaderMatcherResult();
+ resultMap.put(r, bindingKeys[i].toString());
+
+
+ if(i==0)
+ {
+ sm = parser.createStateMachine(bindingKeys[i], r);
+ }
+ else
+ {
+ sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeys[i], r));
+ }
+ }
+
+ Collection<HeaderMatcherResult> results = null;
+ long beforeTime = System.currentTimeMillis();
+ for(int i = 0; i < 1000000; i++)
+ {
+ routingKey.size();
+
+ assert sm != null;
+ results = sm.match(routingKey);
+
+ }
+ long elapsed = System.currentTimeMillis() - beforeTime;
+ System.out.println("1000000 Iterations took: " + elapsed);
+ Collection<String> resultStrings = new ArrayList<String>();
+
+ assert results != null;
+ for(HeaderMatcherResult result : results)
+ {
+ resultStrings.add(resultMap.get(result));
+ }
+
+ final ArrayList<String> nonMatches = new ArrayList<String>();
+ for(FieldTable key : bindingKeys)
+ {
+ nonMatches.add(key.toString());
+ }
+ nonMatches.removeAll(resultStrings);
+ System.out.println("\""+routingKey+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches);
+
+
+ }
+
+
+ public final static class KeyValuePair
+ {
+ public final HeaderKey _key;
+ public final AMQTypedValue _value;
+ private final int _hashCode;
+
+ public KeyValuePair(final HeaderKey key, final AMQTypedValue value)
+ {
+ _key = key;
+ _value = value;
+ int hash = (1 + 31 * _key.hashCode());
+ if(_value != null)
+ {
+ hash+=_value.hashCode();
+ }
+ _hashCode = hash;
+ }
+
+ public int hashCode()
+ {
+ return _hashCode;
+ }
+
+ public boolean equals(Object o)
+ {
+ KeyValuePair other = (KeyValuePair)o;
+ return (_key == other._key) && (_value == null ? other._value == null : _value.equals(other._value));
+ }
+
+
+ public String toString()
+ {
+ return "{" + _key + " -> " + _value + "}";
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java
new file mode 100644
index 0000000000..36076cf75b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java
@@ -0,0 +1,295 @@
+package org.apache.qpid.server.exchange.topic;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.AMQShortStringTokenizer;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class TopicMatcherDFAState
+{
+ private static final AtomicInteger stateId = new AtomicInteger();
+
+ private final int _id = stateId.incrementAndGet();
+
+ private final Collection<TopicMatcherResult> _results;
+ private final Map<TopicWord, TopicMatcherDFAState> _nextStateMap;
+ private static final byte TOPIC_DELIMITTER = (byte)'.';
+
+
+ public TopicMatcherDFAState(Map<TopicWord, TopicMatcherDFAState> nextStateMap,
+ Collection<TopicMatcherResult> results )
+ {
+ _nextStateMap = nextStateMap;
+ _results = results;
+ }
+
+
+ public TopicMatcherDFAState nextState(TopicWord word)
+ {
+ final TopicMatcherDFAState nextState = _nextStateMap.get(word);
+ return nextState == null ? _nextStateMap.get(TopicWord.ANY_WORD) : nextState;
+ }
+
+ public Collection<TopicMatcherResult> terminate()
+ {
+ return _results;
+ }
+
+
+ public Collection<TopicMatcherResult> parse(TopicWordDictionary dictionary, AMQShortString routingKey)
+ {
+ return parse(dictionary, routingKey.tokenize(TOPIC_DELIMITTER));
+ }
+
+ private Collection<TopicMatcherResult> parse(final TopicWordDictionary dictionary,
+ final AMQShortStringTokenizer tokens)
+ {
+ if(!tokens.hasMoreTokens())
+ {
+ return _results;
+ }
+ TopicWord word = dictionary.getWord(tokens.nextToken());
+ TopicMatcherDFAState nextState = _nextStateMap.get(word);
+ if(nextState == null && word != TopicWord.ANY_WORD)
+ {
+ nextState = _nextStateMap.get(TopicWord.ANY_WORD);
+ }
+ if(nextState == null)
+ {
+ return Collections.EMPTY_SET;
+ }
+ // Shortcut if we are at a looping terminal state
+ if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD))
+ {
+ return _results;
+ }
+
+ return nextState.parse(dictionary, tokens);
+
+ }
+
+
+ public TopicMatcherDFAState mergeStateMachines(TopicMatcherDFAState otherStateMachine)
+ {
+ Map<Set<TopicMatcherDFAState>, TopicMatcherDFAState> newStateMap= new HashMap<Set<TopicMatcherDFAState>, TopicMatcherDFAState>();
+
+ Collection<TopicMatcherResult> results;
+
+ if(_results.isEmpty())
+ {
+ results = otherStateMachine._results;
+ }
+ else if(otherStateMachine._results.isEmpty())
+ {
+ results = _results;
+ }
+ else
+ {
+ results = new HashSet<TopicMatcherResult>(_results);
+ results.addAll(otherStateMachine._results);
+ }
+
+
+ final Map<TopicWord, TopicMatcherDFAState> newNextStateMap = new HashMap<TopicWord, TopicMatcherDFAState>();
+
+ TopicMatcherDFAState newState = new TopicMatcherDFAState(newNextStateMap, results);
+
+
+ Set<TopicMatcherDFAState> oldStates = new HashSet<TopicMatcherDFAState>();
+ oldStates.add(this);
+ oldStates.add(otherStateMachine);
+
+ newStateMap.put(oldStates, newState);
+
+ mergeStateMachines(oldStates, newNextStateMap, newStateMap);
+
+ return newState;
+
+ }
+
+ private static void mergeStateMachines(
+ final Set<TopicMatcherDFAState> oldStates,
+ final Map<TopicWord, TopicMatcherDFAState> newNextStateMap,
+ final Map<Set<TopicMatcherDFAState>, TopicMatcherDFAState> newStateMap)
+ {
+ Map<TopicWord, Set<TopicMatcherDFAState>> nfaMap = new HashMap<TopicWord, Set<TopicMatcherDFAState>>();
+
+ for(TopicMatcherDFAState state : oldStates)
+ {
+ Map<TopicWord, TopicMatcherDFAState> map = state._nextStateMap;
+ for(Map.Entry<TopicWord, TopicMatcherDFAState> entry : map.entrySet())
+ {
+ Set<TopicMatcherDFAState> states = nfaMap.get(entry.getKey());
+ if(states == null)
+ {
+ states = new HashSet<TopicMatcherDFAState>();
+ nfaMap.put(entry.getKey(), states);
+ }
+ states.add(entry.getValue());
+ }
+ }
+
+ Set<TopicMatcherDFAState> anyWordStates = nfaMap.get(TopicWord.ANY_WORD);
+
+ for(Map.Entry<TopicWord, Set<TopicMatcherDFAState>> transition : nfaMap.entrySet())
+ {
+ Set<TopicMatcherDFAState> destinations = transition.getValue();
+
+ if(anyWordStates != null)
+ {
+ destinations.addAll(anyWordStates);
+ }
+
+ TopicMatcherDFAState nextState = newStateMap.get(destinations);
+ if(nextState == null)
+ {
+
+ if(destinations.size() == 1)
+ {
+ nextState = destinations.iterator().next();
+ newStateMap.put(destinations, nextState);
+ }
+ else
+ {
+ Collection<TopicMatcherResult> results;
+
+ Set<Collection<TopicMatcherResult>> resultSets = new HashSet<Collection<TopicMatcherResult>>();
+ for(TopicMatcherDFAState destination : destinations)
+ {
+ resultSets.add(destination._results);
+ }
+ resultSets.remove(Collections.EMPTY_SET);
+ if(resultSets.size() == 0)
+ {
+ results = Collections.EMPTY_SET;
+ }
+ else if(resultSets.size() == 1)
+ {
+ results = resultSets.iterator().next();
+ }
+ else
+ {
+ results = new HashSet<TopicMatcherResult>();
+ for(Collection<TopicMatcherResult> oldResult : resultSets)
+ {
+ results.addAll(oldResult);
+ }
+ }
+
+ final Map<TopicWord, TopicMatcherDFAState> nextStateMap = new HashMap<TopicWord, TopicMatcherDFAState>();
+
+ nextState = new TopicMatcherDFAState(nextStateMap, results);
+ newStateMap.put(destinations, nextState);
+
+ mergeStateMachines(
+ destinations,
+ nextStateMap,
+ newStateMap);
+
+
+ }
+
+
+ }
+ newNextStateMap.put(transition.getKey(),nextState);
+ }
+
+ // Remove redundant transitions where defined tokenWord has same action as ANY_WORD
+ TopicMatcherDFAState anyWordState = newNextStateMap.get(TopicWord.ANY_WORD);
+ if(anyWordState != null)
+ {
+ List<TopicWord> removeList = new ArrayList<TopicWord>();
+ for(Map.Entry<TopicWord,TopicMatcherDFAState> entry : newNextStateMap.entrySet())
+ {
+ if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD)
+ {
+ removeList.add(entry.getKey());
+ }
+ }
+ for(TopicWord removeKey : removeList)
+ {
+ newNextStateMap.remove(removeKey);
+ }
+ }
+
+
+
+ }
+
+
+ public String toString()
+ {
+ StringBuilder transitions = new StringBuilder();
+ for(Map.Entry<TopicWord, TopicMatcherDFAState> entry : _nextStateMap.entrySet())
+ {
+ transitions.append("[ ");
+ transitions.append(entry.getKey());
+ transitions.append("\t ->\t ");
+ transitions.append(entry.getValue()._id);
+ transitions.append(" ]\n");
+ }
+
+
+ return "[ State " + _id + " ]\n" + transitions + "\n";
+
+ }
+
+ public String reachableStates()
+ {
+ StringBuilder result = new StringBuilder("Start state: " + _id + "\n");
+
+ SortedSet<TopicMatcherDFAState> reachableStates =
+ new TreeSet<TopicMatcherDFAState>(new Comparator<TopicMatcherDFAState>()
+ {
+ public int compare(final TopicMatcherDFAState o1, final TopicMatcherDFAState o2)
+ {
+ return o1._id - o2._id;
+ }
+ });
+ reachableStates.add(this);
+
+ int count;
+
+ do
+ {
+ count = reachableStates.size();
+ Collection<TopicMatcherDFAState> originalStates = new ArrayList<TopicMatcherDFAState>(reachableStates);
+ for(TopicMatcherDFAState state : originalStates)
+ {
+ reachableStates.addAll(state._nextStateMap.values());
+ }
+ }
+ while(reachableStates.size() != count);
+
+
+
+ for(TopicMatcherDFAState state : reachableStates)
+ {
+ result.append(state.toString());
+ }
+
+ return result.toString();
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java
new file mode 100644
index 0000000000..71d30adfac
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherResult.java
@@ -0,0 +1,25 @@
+package org.apache.qpid.server.exchange.topic;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public interface TopicMatcherResult
+{
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java
new file mode 100644
index 0000000000..3e9facf412
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicParser.java
@@ -0,0 +1,613 @@
+package org.apache.qpid.server.exchange.topic;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.AMQShortStringTokenizer;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.io.IOException;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class TopicParser
+{
+ private static final byte TOPIC_DELIMITER = (byte)'.';
+
+ private final TopicWordDictionary _dictionary = new TopicWordDictionary();
+ private final AtomicReference<TopicMatcherDFAState> _stateMachine = new AtomicReference<TopicMatcherDFAState>();
+
+ private static class Position
+ {
+ private final TopicWord _word;
+ private final boolean _selfTransition;
+ private final int _position;
+ private final boolean _endState;
+ private boolean _followedByAnyLoop;
+
+
+ public Position(final int position, final TopicWord word, final boolean selfTransition, final boolean endState)
+ {
+ _position = position;
+ _word = word;
+ _selfTransition = selfTransition;
+ _endState = endState;
+ }
+
+
+ }
+
+ private static final Position ERROR_POSITION = new Position(Integer.MAX_VALUE,null, true, false);
+
+ private static class SimpleState
+ {
+ Set<Position> _positions;
+ Map<TopicWord, SimpleState> _nextState;
+ }
+
+
+ public void addBinding(AMQShortString bindingKey, TopicMatcherResult result)
+ {
+
+ TopicMatcherDFAState startingStateMachine;
+ TopicMatcherDFAState newStateMachine;
+
+ do
+ {
+ startingStateMachine = _stateMachine.get();
+ if(startingStateMachine == null)
+ {
+ newStateMachine = createStateMachine(bindingKey, result);
+ }
+ else
+ {
+ newStateMachine = startingStateMachine.mergeStateMachines(createStateMachine(bindingKey, result));
+ }
+
+ }
+ while(!_stateMachine.compareAndSet(startingStateMachine,newStateMachine));
+
+ }
+
+ public Collection<TopicMatcherResult> parse(AMQShortString routingKey)
+ {
+ TopicMatcherDFAState stateMachine = _stateMachine.get();
+ if(stateMachine == null)
+ {
+ return Collections.EMPTY_SET;
+ }
+ else
+ {
+ return stateMachine.parse(_dictionary,routingKey);
+ }
+ }
+
+
+ TopicMatcherDFAState createStateMachine(AMQShortString bindingKey, TopicMatcherResult result)
+ {
+ List<TopicWord> wordList = createTopicWordList(bindingKey);
+ int wildCards = 0;
+ for(TopicWord word : wordList)
+ {
+ if(word == TopicWord.WILDCARD_WORD)
+ {
+ wildCards++;
+ }
+ }
+ if(wildCards == 0)
+ {
+ TopicMatcherDFAState[] states = new TopicMatcherDFAState[wordList.size()+1];
+ states[states.length-1] = new TopicMatcherDFAState(Collections.EMPTY_MAP, Collections.singleton(result));
+ for(int i = states.length-2; i >= 0; i--)
+ {
+ states[i] = new TopicMatcherDFAState(Collections.singletonMap(wordList.get(i),states[i+1]),Collections.EMPTY_SET);
+
+ }
+ return states[0];
+ }
+ else if(wildCards == wordList.size())
+ {
+ Map<TopicWord,TopicMatcherDFAState> stateMap = new HashMap<TopicWord,TopicMatcherDFAState>();
+ TopicMatcherDFAState state = new TopicMatcherDFAState(stateMap, Collections.singleton(result));
+ stateMap.put(TopicWord.ANY_WORD, state);
+ return state;
+ }
+
+
+ int positionCount = wordList.size() - wildCards;
+
+ Position[] positions = new Position[positionCount+1];
+
+ int lastWord;
+
+ if(wordList.get(wordList.size()-1)== TopicWord.WILDCARD_WORD)
+ {
+ lastWord = wordList.size()-1;
+ positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, true, true);
+ }
+ else
+ {
+ lastWord = wordList.size();
+ positions[positionCount] = new Position(positionCount, TopicWord.ANY_WORD, false, true);
+ }
+
+
+ int pos = 0;
+ int wordPos = 0;
+
+
+ while(wordPos < lastWord)
+ {
+ TopicWord word = wordList.get(wordPos++);
+
+ if(word == TopicWord.WILDCARD_WORD)
+ {
+ int nextWordPos = wordPos++;
+ word = wordList.get(nextWordPos);
+
+ positions[pos] = new Position(pos++,word,true,false);
+ }
+ else
+ {
+ positions[pos] = new Position(pos++,word,false,false);
+ }
+
+ }
+
+
+ for(int p = 0; p<positionCount; p++)
+ {
+ boolean followedByWildcards = true;
+
+ int n = p;
+ while(followedByWildcards && n<(positionCount+1))
+ {
+
+ if(positions[n]._selfTransition)
+ {
+ break;
+ }
+ else if(positions[n]._word!=TopicWord.ANY_WORD)
+ {
+ followedByWildcards = false;
+ }
+ n++;
+ }
+
+
+ positions[p]._followedByAnyLoop = followedByWildcards && (n!= positionCount+1);
+ }
+
+
+ // from each position you transition to a set of other positions.
+ // we approach this by examining steps of increasing length - so we
+ // look how far we can go from the start position in 1 word, 2 words, etc...
+
+ Map<Set<Position>,SimpleState> stateMap = new HashMap<Set<Position>,SimpleState>();
+
+
+ SimpleState state = new SimpleState();
+ state._positions = Collections.singleton( positions[0] );
+ stateMap.put(state._positions, state);
+
+ calculateNextStates(state, stateMap, positions);
+
+ SimpleState[] simpleStates = stateMap.values().toArray(new SimpleState[stateMap.size()]);
+ HashMap<TopicWord, TopicMatcherDFAState>[] dfaStateMaps = new HashMap[simpleStates.length];
+ Map<SimpleState, TopicMatcherDFAState> simple2DFAMap = new HashMap<SimpleState, TopicMatcherDFAState>();
+
+ for(int i = 0; i < simpleStates.length; i++)
+ {
+
+ Collection<TopicMatcherResult> results;
+ boolean endState = false;
+
+ for(Position p : simpleStates[i]._positions)
+ {
+ if(p._endState)
+ {
+ endState = true;
+ break;
+ }
+ }
+
+ if(endState)
+ {
+ results = Collections.singleton(result);
+ }
+ else
+ {
+ results = Collections.EMPTY_SET;
+ }
+
+ dfaStateMaps[i] = new HashMap<TopicWord, TopicMatcherDFAState>();
+ simple2DFAMap.put(simpleStates[i], new TopicMatcherDFAState(dfaStateMaps[i],results));
+
+ }
+ for(int i = 0; i < simpleStates.length; i++)
+ {
+ SimpleState simpleState = simpleStates[i];
+
+ Map<TopicWord, SimpleState> nextSimpleStateMap = simpleState._nextState;
+ for(Map.Entry<TopicWord, SimpleState> stateMapEntry : nextSimpleStateMap.entrySet())
+ {
+ dfaStateMaps[i].put(stateMapEntry.getKey(), simple2DFAMap.get(stateMapEntry.getValue()));
+ }
+
+ }
+
+ return simple2DFAMap.get(state);
+
+ }
+
+
+
+ private void calculateNextStates(final SimpleState state,
+ final Map<Set<Position>, SimpleState> stateMap,
+ final Position[] positions)
+ {
+ Map<TopicWord, Set<Position>> transitions = new HashMap<TopicWord,Set<Position>>();
+
+ for(Position pos : state._positions)
+ {
+ if(pos._selfTransition)
+ {
+ Set<Position> dest = transitions.get(TopicWord.ANY_WORD);
+ if(dest == null)
+ {
+ dest = new HashSet<Position>();
+ transitions.put(TopicWord.ANY_WORD,dest);
+ }
+ dest.add(pos);
+ }
+
+ final int nextPos = pos._position + 1;
+ Position nextPosition = nextPos == positions.length ? ERROR_POSITION : positions[nextPos];
+
+ Set<Position> dest = transitions.get(pos._word);
+ if(dest == null)
+ {
+ dest = new HashSet<Position>();
+ transitions.put(pos._word,dest);
+ }
+ dest.add(nextPosition);
+
+ }
+
+ Set<Position> anyWordTransitions = transitions.get(TopicWord.ANY_WORD);
+ if(anyWordTransitions != null)
+ {
+ for(Set<Position> dest : transitions.values())
+ {
+ dest.addAll(anyWordTransitions);
+ }
+ }
+
+ state._nextState = new HashMap<TopicWord, SimpleState>();
+
+ for(Map.Entry<TopicWord,Set<Position>> dest : transitions.entrySet())
+ {
+
+ if(dest.getValue().size()>1)
+ {
+ dest.getValue().remove(ERROR_POSITION);
+ }
+ Position loopingTerminal = null;
+ for(Position destPos : dest.getValue())
+ {
+ if(destPos._selfTransition && destPos._endState)
+ {
+ loopingTerminal = destPos;
+ break;
+ }
+ }
+
+ if(loopingTerminal!=null)
+ {
+ dest.setValue(Collections.singleton(loopingTerminal));
+ }
+ else
+ {
+ Position anyLoop = null;
+ for(Position destPos : dest.getValue())
+ {
+ if(destPos._followedByAnyLoop)
+ {
+ if(anyLoop == null || anyLoop._position<destPos._position)
+ {
+ anyLoop = destPos;
+ }
+ }
+ }
+ if(anyLoop != null)
+ {
+ Collection<Position> removals = new ArrayList<Position>();
+ for(Position destPos : dest.getValue())
+ {
+ if(destPos._position < anyLoop._position)
+ {
+ removals.add(destPos);
+ }
+ }
+ dest.getValue().removeAll(removals);
+ }
+ }
+
+ SimpleState stateForEntry = stateMap.get(dest.getValue());
+ if(stateForEntry == null)
+ {
+ stateForEntry = new SimpleState();
+ stateForEntry._positions = dest.getValue();
+ stateMap.put(dest.getValue(),stateForEntry);
+ calculateNextStates(stateForEntry,
+ stateMap,
+ positions);
+ }
+ state._nextState.put(dest.getKey(),stateForEntry);
+
+
+
+ }
+
+ // remove redundant transitions
+ SimpleState anyWordState = state._nextState.get(TopicWord.ANY_WORD);
+ if(anyWordState != null)
+ {
+ List<TopicWord> removeList = new ArrayList<TopicWord>();
+ for(Map.Entry<TopicWord,SimpleState> entry : state._nextState.entrySet())
+ {
+ if(entry.getValue() == anyWordState && entry.getKey() != TopicWord.ANY_WORD)
+ {
+ removeList.add(entry.getKey());
+ }
+ }
+ for(TopicWord removeKey : removeList)
+ {
+ state._nextState.remove(removeKey);
+ }
+ }
+
+
+ }
+
+ private List<TopicWord> createTopicWordList(final AMQShortString bindingKey)
+ {
+ AMQShortStringTokenizer tokens = bindingKey.tokenize(TOPIC_DELIMITER);
+ TopicWord previousWord = null;
+
+ List<TopicWord> wordList = new ArrayList<TopicWord>();
+
+ while(tokens.hasMoreTokens())
+ {
+ TopicWord nextWord = _dictionary.getOrCreateWord(tokens.nextToken());
+ if(previousWord == TopicWord.WILDCARD_WORD)
+ {
+
+ if(nextWord == TopicWord.WILDCARD_WORD)
+ {
+ // consecutive wildcards can be merged
+ // i.e. subsequent wildcards can be discarded
+ continue;
+ }
+ else if(nextWord == TopicWord.ANY_WORD)
+ {
+ // wildcard and anyword can be reordered to always put anyword first
+ wordList.set(wordList.size()-1,TopicWord.ANY_WORD);
+ nextWord = TopicWord.WILDCARD_WORD;
+ }
+ }
+ wordList.add(nextWord);
+ previousWord = nextWord;
+
+ }
+ return wordList;
+ }
+
+
+ public static void main(String[] args)
+ {
+
+ printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.*.q.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z");
+ printMatches(new String[]{
+ "#.a.#",
+ "#.b.#",
+ "#.c.#",
+ "#.d.#",
+ "#.e.#",
+ "#.f.#",
+ "#.g.#",
+ "#.h.#",
+ "#.i.#",
+ "#.j.#",
+ "#.k.#",
+ "#.l.#",
+ "#.m.#",
+ "#.n.#",
+ "#.o.#",
+ "#.p.#",
+ "#.q.#"
+
+ }, "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z");
+/*
+ printMatches(new String[]{
+ "#.a.#",
+ "#.b.#",
+ "#.c.#",
+ "#.d.#",
+ "#.e.#",
+ "#.f.#",
+ "#.g.#",
+ "#.h.#",
+ "#.i.#",
+ "#.j.#",
+ "#.k.#",
+ "#.l.#",
+ "#.m.#",
+ "#.n.#",
+ "#.o.#",
+ "#.p.#",
+ "#.q.#",
+ "#.r.#",
+ "#.s.#",
+ "#.t.#",
+ "#.u.#",
+ "#.v.#",
+ "#.w.#",
+ "#.x.#",
+ "#.y.#",
+ "#.z.#"
+
+
+ },"a.b");
+
+ printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z");
+ printMatches("#.b.*.*.*.*.*.h.#.j.*.*.*.*.*.p.#.r.*.*.*.*.*.*.*.*","a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z");
+ printMatches("a.#.b.#","a.b.b.b.b.b.b.b.c");
+
+*/
+
+ printMatches("","");
+ printMatches("a","a");
+ printMatches("a","");
+ printMatches("","a");
+ printMatches("a.b","a.b");
+ printMatches("a","a.b");
+ printMatches("a.b","a");
+ printMatches("*","a");
+ printMatches("*.b","a.b");
+ printMatches("*.*","a.b");
+ printMatches("a.*","a.b");
+ printMatches("a.*.#","a.b");
+ printMatches("a.#.b","a.b");
+
+ printMatches("#.b","a");
+ printMatches("#.b","a.b");
+ printMatches("#.a.b","a.b");
+
+
+ printMatches("#","");
+ printMatches("#","a");
+ printMatches("#","a.b");
+ printMatches("#.#","a.b");
+ printMatches("#.*","a.b");
+
+ printMatches("#.a.b","a.b");
+ printMatches("a.b.#","a.b");
+ printMatches("a.#","a.b");
+ printMatches("#.*.#","a.b");
+ printMatches("#.*.b.#","a.b");
+ printMatches("#.a.*.#","a.b");
+ printMatches("#.a.#.b.#","a.b");
+ printMatches("#.*.#.*.#","a.b");
+ printMatches("*.#.*.#","a.b");
+ printMatches("#.*.#.*","a.b");
+
+
+ printMatches(new String[]{"a.#.b.#","a.*.#.b.#"},"a.b.b.b.b.b.b.b.c");
+
+
+ printMatches(new String[]{"a.b", "a.c"},"a.b");
+ printMatches(new String[]{"a.#", "a.c", "#.b"},"a.b");
+ printMatches(new String[]{"a.#", "a.c", "#.b", "#", "*.*"},"a.b");
+
+ printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.e");
+ printMatches(new String[]{"a.b.c.d.e.#", "a.b.c.d.#", "a.b.c.d.*", "a.b.c.#", "#.e", "a.*.c.d.e","#.c.*.#.*.*"},"a.b.c.d.f.g");
+
+
+
+
+ }
+
+ private static void printMatches(final String[] bindingKeys, final String routingKey)
+ {
+ TopicMatcherDFAState sm = null;
+ Map<TopicMatcherResult, String> resultMap = new HashMap<TopicMatcherResult, String>();
+
+ TopicParser parser = new TopicParser();
+
+ long start = System.currentTimeMillis();
+ for(int i = 0; i < bindingKeys.length; i++)
+ {
+ System.out.println((System.currentTimeMillis() - start) + ":\t" + bindingKeys[i]);
+ TopicMatcherResult r = new TopicMatcherResult(){};
+ resultMap.put(r, bindingKeys[i]);
+ AMQShortString bindingKeyShortString = new AMQShortString(bindingKeys[i]);
+
+ System.err.println("=====================================================");
+ System.err.println("Adding binding key: " + bindingKeyShortString);
+ System.err.println("-----------------------------------------------------");
+
+
+ if(i==0)
+ {
+ sm = parser.createStateMachine(bindingKeyShortString, r);
+ }
+ else
+ {
+ sm = sm.mergeStateMachines(parser.createStateMachine(bindingKeyShortString, r));
+ }
+ System.err.println(sm.reachableStates());
+ System.err.println("=====================================================");
+ try
+ {
+ System.in.read();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ AMQShortString routingKeyShortString = new AMQShortString(routingKey);
+
+ Collection<TopicMatcherResult> results = sm.parse(parser._dictionary, routingKeyShortString);
+ Collection<String> resultStrings = new ArrayList<String>();
+
+ for(TopicMatcherResult result : results)
+ {
+ resultStrings.add(resultMap.get(result));
+ }
+
+ final ArrayList<String> nonMatches = new ArrayList<String>(Arrays.asList(bindingKeys));
+ nonMatches.removeAll(resultStrings);
+ System.out.println("\""+routingKeyShortString+"\" matched with " + resultStrings + " DID NOT MATCH with " + nonMatches);
+
+
+ }
+
+ private static void printMatches(String bindingKey, String routingKey)
+ {
+ printMatches(new String[] { bindingKey }, routingKey);
+ }
+
+
+ private static boolean matches(String bindingKey, String routingKey)
+ {
+ AMQShortString bindingKeyShortString = new AMQShortString(bindingKey);
+ AMQShortString routingKeyShortString = new AMQShortString(routingKey);
+ TopicParser parser = new TopicParser();
+
+ final TopicMatcherResult result = new TopicMatcherResult(){};
+
+ TopicMatcherDFAState sm = parser.createStateMachine(bindingKeyShortString, result);
+ return !sm.parse(parser._dictionary,routingKeyShortString).isEmpty();
+
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java
new file mode 100644
index 0000000000..f14d70f8a1
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWord.java
@@ -0,0 +1,54 @@
+package org.apache.qpid.server.exchange.topic;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public final class TopicWord
+{
+ public static final TopicWord ANY_WORD = new TopicWord("*");
+ public static final TopicWord WILDCARD_WORD = new TopicWord("#");
+ private String _word;
+
+ public TopicWord()
+ {
+
+ }
+
+ public TopicWord(String s)
+ {
+ _word = s;
+ }
+
+ public TopicWord(final AMQShortString name)
+ {
+ _word = name.toString();
+ }
+
+ public String toString()
+ {
+ return _word;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java
new file mode 100644
index 0000000000..65a0cd3107
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicWordDictionary.java
@@ -0,0 +1,63 @@
+package org.apache.qpid.server.exchange.topic;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class TopicWordDictionary
+{
+ private final ConcurrentHashMap<AMQShortString,TopicWord> _dictionary =
+ new ConcurrentHashMap<AMQShortString,TopicWord>();
+
+
+
+ public TopicWordDictionary()
+ {
+ _dictionary.put(new AMQShortString("*"), TopicWord.ANY_WORD);
+ _dictionary.put(new AMQShortString("#"), TopicWord.WILDCARD_WORD);
+ }
+
+
+
+
+ public TopicWord getOrCreateWord(AMQShortString name)
+ {
+ TopicWord word = _dictionary.putIfAbsent(name, new TopicWord(name));
+ if(word == null)
+ {
+ word = _dictionary.get(name);
+ }
+ return word;
+ }
+
+
+ public TopicWord getWord(AMQShortString name)
+ {
+ TopicWord word = _dictionary.get(name);
+ if(word == null)
+ {
+ word = TopicWord.ANY_WORD;
+ }
+ return word;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
index fb5220f4da..a964bce306 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
@@ -21,12 +21,12 @@ package org.apache.qpid.server.filter;
//
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* An expression which performs an operation on two expression values
*/
-public abstract class ArithmeticExpression extends BinaryExpression
+public abstract class ArithmeticExpression<E extends Exception> extends BinaryExpression<E>
{
protected static final int INTEGER = 1;
@@ -248,7 +248,7 @@ public abstract class ArithmeticExpression extends BinaryExpression
}
}
- public Object evaluate(AMQMessage message) throws AMQException
+ public Object evaluate(Filterable<E> message) throws E
{
Object lvalue = left.evaluate(message);
if (lvalue == null)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
index 024257bea9..7308de80d6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
@@ -23,23 +23,23 @@ package org.apache.qpid.server.filter;
/**
* An expression which performs an operation on two expression values.
*/
-public abstract class BinaryExpression implements Expression
+public abstract class BinaryExpression<E extends Exception> implements Expression<E>
{
- protected Expression left;
- protected Expression right;
+ protected Expression<E> left;
+ protected Expression<E> right;
- public BinaryExpression(Expression left, Expression right)
+ public BinaryExpression(Expression<E> left, Expression<E> right)
{
this.left = left;
this.right = right;
}
- public Expression getLeft()
+ public Expression<E> getLeft()
{
return left;
}
- public Expression getRight()
+ public Expression<E> getRight()
{
return right;
}
@@ -90,7 +90,7 @@ public abstract class BinaryExpression implements Expression
/**
* @param expression
*/
- public void setRight(Expression expression)
+ public void setRight(Expression<E> expression)
{
right = expression;
}
@@ -98,7 +98,7 @@ public abstract class BinaryExpression implements Expression
/**
* @param expression
*/
- public void setLeft(Expression expression)
+ public void setLeft(Expression<E> expression)
{
left = expression;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
index e28ff79820..9beb9798d0 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
@@ -22,19 +22,20 @@ package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* A BooleanExpression is an expression that always
* produces a Boolean result.
*/
-public interface BooleanExpression extends Expression
+public interface BooleanExpression<E extends Exception> extends Expression<E>
{
/**
* @param message
* @return true if the expression evaluates to Boolean.TRUE.
- * @throws AMQException
+ * @throws E
*/
- public boolean matches(AMQMessage message) throws AMQException;
+ public boolean matches(Filterable<E> message) throws E;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
index 44281a3aae..921005c462 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
@@ -28,21 +28,21 @@ import java.util.List;
import java.util.regex.Pattern;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* A filter performing a comparison of two objects
*/
-public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression
+public abstract class ComparisonExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E>
{
- public static BooleanExpression createBetween(Expression value, Expression left, Expression right)
+ public static<E extends Exception> BooleanExpression<E> createBetween(Expression<E> value, Expression left, Expression<E> right)
{
return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
}
- public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right)
+ public static<E extends Exception> BooleanExpression<E> createNotBetween(Expression<E> value, Expression<E> left, Expression<E> right)
{
return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
}
@@ -73,7 +73,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
REGEXP_CONTROL_CHARS.add(new Character('!'));
}
- static class LikeExpression extends UnaryExpression implements BooleanExpression
+ static class LikeExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E>
{
Pattern likePattern;
@@ -81,7 +81,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
/**
* @param right
*/
- public LikeExpression(Expression right, String like, int escape)
+ public LikeExpression(Expression<E> right, String like, int escape)
{
super(right);
@@ -138,7 +138,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
/**
* org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext)
*/
- public Object evaluate(AMQMessage message) throws AMQException
+ public Object evaluate(Filterable<E> message) throws E
{
Object rv = this.getRight().evaluate(message);
@@ -148,11 +148,6 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
return null;
}
- if(rv instanceof AMQShortString)
- {
- rv = rv.toString();
- }
-
if (!(rv instanceof String))
{
return
@@ -163,7 +158,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE;
}
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable<E> message) throws E
{
Object object = evaluate(message);
@@ -241,45 +236,9 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
return doCreateEqual(left, right);
}
- private static BooleanExpression doCreateEqual(Expression left, Expression right)
+ private static<E extends Exception> BooleanExpression<E> doCreateEqual(Expression<E> left, Expression<E> right)
{
- return new ComparisonExpression(left, right)
- {
-
- public Object evaluate(AMQMessage message) throws AMQException
- {
- Object lv = left.evaluate(message);
- Object rv = right.evaluate(message);
-
- // Iff one of the values is null
- if ((lv == null) ^ (rv == null))
- {
- return Boolean.FALSE;
- }
-
- if ((lv == rv) || lv.equals(rv))
- {
- return Boolean.TRUE;
- }
-
- if ((lv instanceof Comparable) && (rv instanceof Comparable))
- {
- return compare((Comparable) lv, (Comparable) rv);
- }
-
- return Boolean.FALSE;
- }
-
- protected boolean asBoolean(int answer)
- {
- return answer == 0;
- }
-
- public String getExpressionSymbol()
- {
- return "=";
- }
- };
+ return new EqualExpression(left, right);
}
public static BooleanExpression createGreaterThan(final Expression left, final Expression right)
@@ -429,7 +388,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
super(left, right);
}
- public Object evaluate(AMQMessage message) throws AMQException
+ public Object evaluate(Filterable<E> message) throws E
{
Comparable lv = (Comparable) left.evaluate(message);
if (lv == null)
@@ -454,40 +413,7 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
// try to convert up to allow the comparison.
if (lc != rc)
{
- if(lc == AMQShortString.class)
- {
- if(rc == String.class)
- {
- rv = new AMQShortString((String) rv);
-
- if(right instanceof ConstantExpression)
- {
- ((ConstantExpression)right).setValue(rv);
- }
- }
- else
- {
- return Boolean.FALSE;
- }
- }
- else if(lc == String.class)
- {
- if(rc == AMQShortString.class)
- {
- lv = new AMQShortString((String) lv);
-
- if(left instanceof ConstantExpression)
- {
- ((ConstantExpression)left).setValue(lv);
- }
- }
- else
- {
- return Boolean.FALSE;
- }
-
- }
- else if (lc == Byte.class)
+ if (lc == Byte.class)
{
if (rc == Short.class)
{
@@ -624,11 +550,52 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
protected abstract boolean asBoolean(int answer);
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable<E> message) throws E
{
Object object = evaluate(message);
return (object != null) && (object == Boolean.TRUE);
}
+ private static class EqualExpression<E extends Exception> extends ComparisonExpression<E>
+ {
+ public EqualExpression(final Expression<E> left, final Expression<E> right)
+ {
+ super(left, right);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ Object lv = left.evaluate(message);
+ Object rv = right.evaluate(message);
+
+ // Iff one of the values is null
+ if ((lv == null) ^ (rv == null))
+ {
+ return Boolean.FALSE;
+ }
+
+ if ((lv == rv) || lv.equals(rv))
+ {
+ return Boolean.TRUE;
+ }
+
+ if ((lv instanceof Comparable) && (rv instanceof Comparable))
+ {
+ return compare((Comparable) lv, (Comparable) rv);
+ }
+
+ return Boolean.FALSE;
+ }
+
+ protected boolean asBoolean(int answer)
+ {
+ return answer == 0;
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "=";
+ }
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
index 73c4c66ad7..3ed2286f2e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
@@ -26,23 +26,23 @@ package org.apache.qpid.server.filter;
import java.math.BigDecimal;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* Represents a constant expression
*/
-public class ConstantExpression implements Expression
+public class ConstantExpression<E extends Exception> implements Expression<E>
{
- static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression
+ static class BooleanConstantExpression<E extends Exception> extends ConstantExpression<E> implements BooleanExpression<E>
{
public BooleanConstantExpression(Object value)
{
super(value);
}
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable<E> message) throws E
{
Object object = evaluate(message);
@@ -121,7 +121,7 @@ public class ConstantExpression implements Expression
this.value = value;
}
- public Object evaluate(AMQMessage message) throws AMQException
+ public Object evaluate(Filterable<E> message) throws E
{
return value;
}
@@ -131,12 +131,6 @@ public class ConstantExpression implements Expression
return value;
}
- public void setValue(final Object value)
- {
- this.value = value;
- }
-
-
/**
* @see java.lang.Object#toString()
*/
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
index 5f646c15db..f2ebe41d26 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
@@ -22,16 +22,17 @@ package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* Represents an expression
*/
-public interface Expression
+public interface Expression<E extends Exception>
{
/**
* @return the value of this expression
*/
- public Object evaluate(AMQMessage message) throws AMQException;
+ public Object evaluate(Filterable<E> message) throws E;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
index c82de9fa15..dd3c126ee5 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
@@ -24,14 +24,16 @@ package org.apache.qpid.server.filter;
//
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
+import org.apache.qpid.AMQException;
-public interface FilterManager
+public interface FilterManager<E extends Exception>
{
- void add(MessageFilter filter);
+ void add(MessageFilter<E> filter);
- void remove(MessageFilter filter);
+ void remove(MessageFilter<E> filter);
- boolean allAllow(AMQMessage msg);
+ boolean allAllow(Filterable<E> msg);
boolean hasFilters();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java
index 311f0680ec..a7f49d0566 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java
@@ -39,7 +39,7 @@ public class FilterManagerFactory
if (filters != null)
{
- manager = new SimpleFilterManager();
+
if(filters.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()))
{
@@ -47,23 +47,13 @@ public class FilterManagerFactory
if (selector != null && !selector.equals(""))
{
+ manager = new SimpleFilterManager();
manager.add(new JMSSelectorFilter(selector));
}
}
- if (filters.containsKey(AMQPFilterTypes.NO_CONSUME.getValue()))
- {
- manager.add(new NoConsumerFilter());
- }
-
-
- //If we added no filters don't bear the overhead of having an filter manager
- if (!manager.hasFilters())
- {
- manager = null;
- }
}
else
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
index 48b6602bda..96c9353872 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
@@ -23,45 +23,30 @@ package org.apache.qpid.server.filter;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.filter.jms.selector.SelectorParser;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
-
-public class JMSSelectorFilter implements MessageFilter
+public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E>
{
private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class);
private String _selector;
- private BooleanExpression _matcher;
+ private BooleanExpression<E> _matcher;
public JMSSelectorFilter(String selector) throws AMQException
{
_selector = selector;
- _logger.info("Created JMSSelectorFilter with selector:" + _selector);
-
-
_matcher = new SelectorParser().parse(selector);
-
-
}
- public boolean matches(AMQMessage message)
+ public boolean matches(Filterable<E> message) throws E
{
- try
- {
- boolean match = _matcher.matches(message);
- if(_logger.isDebugEnabled())
- {
- _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector);
- }
- return match;
- }
- catch (AMQException e)
+ boolean match = _matcher.matches(message);
+ if(_logger.isDebugEnabled())
{
- //fixme this needs to be sorted.. it shouldn't happen
- e.printStackTrace();
+ _logger.debug(message + " match(" + match + ") selector(" + System.identityHashCode(_selector) + "):" + _selector);
}
- return false;
+ return match;
}
public String getSelector()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
index c8cbdb2125..094363ed9a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
@@ -22,71 +22,22 @@ package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* A filter performing a comparison of two objects
*/
-public abstract class LogicExpression extends BinaryExpression implements BooleanExpression
+public abstract class LogicExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E>
{
- public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue)
+ public static<E extends Exception> BooleanExpression createOR(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue)
{
- return new LogicExpression(lvalue, rvalue)
- {
-
- public Object evaluate(AMQMessage message) throws AMQException
- {
-
- Boolean lv = (Boolean) left.evaluate(message);
- // Can we do an OR shortcut??
- if ((lv != null) && lv.booleanValue())
- {
- return Boolean.TRUE;
- }
-
- Boolean rv = (Boolean) right.evaluate(message);
-
- return (rv == null) ? null : rv;
- }
-
- public String getExpressionSymbol()
- {
- return "OR";
- }
- };
+ return new OrExpression(lvalue, rvalue);
}
- public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue)
+ public static<E extends Exception> BooleanExpression createAND(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue)
{
- return new LogicExpression(lvalue, rvalue)
- {
-
- public Object evaluate(AMQMessage message) throws AMQException
- {
-
- Boolean lv = (Boolean) left.evaluate(message);
-
- // Can we do an AND shortcut??
- if (lv == null)
- {
- return null;
- }
-
- if (!lv.booleanValue())
- {
- return Boolean.FALSE;
- }
-
- Boolean rv = (Boolean) right.evaluate(message);
-
- return (rv == null) ? null : rv;
- }
-
- public String getExpressionSymbol()
- {
- return "AND";
- }
- };
+ return new AndExpression(lvalue, rvalue);
}
/**
@@ -98,13 +49,74 @@ public abstract class LogicExpression extends BinaryExpression implements Boolea
super(left, right);
}
- public abstract Object evaluate(AMQMessage message) throws AMQException;
+ public abstract Object evaluate(Filterable<E> message) throws E;
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable<E> message) throws E
{
Object object = evaluate(message);
return (object != null) && (object == Boolean.TRUE);
}
+ private static class OrExpression<E extends Exception> extends LogicExpression<E>
+ {
+ public OrExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue)
+ {
+ super(lvalue, rvalue);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ Boolean lv = (Boolean) left.evaluate(message);
+ // Can we do an OR shortcut??
+ if ((lv != null) && lv.booleanValue())
+ {
+ return Boolean.TRUE;
+ }
+
+ Boolean rv = (Boolean) right.evaluate(message);
+
+ return (rv == null) ? null : rv;
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "OR";
+ }
+ }
+
+ private static class AndExpression<E extends Exception> extends LogicExpression<E>
+ {
+ public AndExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue)
+ {
+ super(lvalue, rvalue);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ Boolean lv = (Boolean) left.evaluate(message);
+
+ // Can we do an AND shortcut??
+ if (lv == null)
+ {
+ return null;
+ }
+
+ if (!lv.booleanValue())
+ {
+ return Boolean.FALSE;
+ }
+
+ Boolean rv = (Boolean) right.evaluate(message);
+
+ return (rv == null) ? null : rv;
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "AND";
+ }
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
index e6bfe974d5..58fc55f8e6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
@@ -22,8 +22,9 @@ package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
-public interface MessageFilter
+public interface MessageFilter<E extends Exception>
{
- boolean matches(AMQMessage message) throws AMQException;
+ boolean matches(Filterable<E> message) throws E;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
index 47ca930d12..f1b3b2511d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
@@ -22,7 +22,7 @@ package org.apache.qpid.server.filter;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
public class NoConsumerFilter implements MessageFilter
{
@@ -34,7 +34,7 @@ public class NoConsumerFilter implements MessageFilter
_logger.info("Created NoConsumerFilter");
}
- public boolean matches(AMQMessage message)
+ public boolean matches(Filterable message)
{
return true;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
index e5e9acf9bb..b30c70dac3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
@@ -30,12 +30,12 @@ import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.CommonContentHeaderProperties;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* Represents a property expression
*/
-public class PropertyExpression implements Expression
+public class PropertyExpression<E extends Exception> implements Expression<E>
{
// Constants - defined the same as JMS
private static final int NON_PERSISTENT = 1;
@@ -44,223 +44,60 @@ public class PropertyExpression implements Expression
private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class);
- private static final HashMap<String, Expression> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression>();
+ private static final HashMap<String, Expression<? extends Exception>> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression<? extends Exception>>();
- static
{
- JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression()
+ JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression<E>()
{
- public Object evaluate(AMQMessage message)
+ public Object evaluate(Filterable<E> message)
{
//TODO
return null;
}
});
- JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString replyTo = _properties.getReplyTo();
-
- return (replyTo == null) ? null : replyTo;
- }
- catch (AMQException e)
- {
- _logger.warn(e);
-
- return null;
- }
-
- }
-
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString type = _properties.getType();
-
- return (type == null) ? null : type;
- }
- catch (AMQException e)
- {
- _logger.warn(e);
-
- return null;
- }
-
- }
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
- try
- {
- int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT;
- if (_logger.isDebugEnabled())
- {
- _logger.debug("JMSDeliveryMode is :" + mode);
- }
-
- return mode;
- }
- catch (AMQException e)
- {
- _logger.warn(e);
- }
-
- return NON_PERSISTENT;
- }
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
-
- return (int) _properties.getPriority();
- }
- catch (AMQException e)
- {
- _logger.warn(e);
- }
-
- return DEFAULT_PRIORITY;
- }
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
-
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString messageId = _properties.getMessageId();
-
- return (messageId == null) ? null : messageId;
- }
- catch (AMQException e)
- {
- _logger.warn(e);
-
- return null;
- }
-
- }
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
-
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
-
- return _properties.getTimestamp();
- }
- catch (AMQException e)
- {
- _logger.warn(e);
-
- return null;
- }
-
- }
- });
-
- JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
-
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString correlationId = _properties.getCorrelationId();
-
- return (correlationId == null) ? null : correlationId;
- }
- catch (AMQException e)
- {
- _logger.warn(e);
+ JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new ReplyToExpression());
- return null;
- }
+ JMS_PROPERTY_EXPRESSIONS.put("JMSType", new TypeExpression());
- }
- });
+ JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new DeliveryModeExpression());
- JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression()
- {
- public Object evaluate(AMQMessage message)
- {
+ JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression());
- try
- {
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
+ JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression());
- return _properties.getExpiration();
- }
- catch (AMQException e)
- {
- _logger.warn(e);
+ JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression());
- return null;
- }
+ JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new CorrelationIdExpression());
- }
- });
+ JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression());
- JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression()
+ JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression<E>()
{
- public Object evaluate(AMQMessage message)
+ public Object evaluate(Filterable message) throws E
{
return message.isRedelivered();
}
});
-
}
- private final AMQShortString name;
- private final Expression jmsPropertyExpression;
+ private final String name;
+ private final Expression<E> jmsPropertyExpression;
+
+ public boolean outerTest()
+ {
+ return false;
+ }
public PropertyExpression(String name)
{
- this.name = new AMQShortString(name);
- jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name);
+ this.name = name;
+
+
+
+ jmsPropertyExpression = (Expression<E>) JMS_PROPERTY_EXPRESSIONS.get(name);
}
- public Object evaluate(AMQMessage message) throws AMQException
+ public Object evaluate(Filterable<E> message) throws E
{
if (jmsPropertyExpression != null)
@@ -283,7 +120,7 @@ public class PropertyExpression implements Expression
}
}
- public AMQShortString getName()
+ public String getName()
{
return name;
}
@@ -293,7 +130,7 @@ public class PropertyExpression implements Expression
*/
public String toString()
{
- return name.toString();
+ return name;
}
/**
@@ -319,4 +156,113 @@ public class PropertyExpression implements Expression
}
+ private static class ReplyToExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+ AMQShortString replyTo = _properties.getReplyTo();
+
+ return (replyTo == null) ? null : replyTo.toString();
+
+ }
+
+ }
+
+ private static class TypeExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+ AMQShortString type = _properties.getType();
+
+ return (type == null) ? null : type.toString();
+
+ }
+ }
+
+ private static class DeliveryModeExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT;
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("JMSDeliveryMode is :" + mode);
+ }
+
+ return mode;
+ }
+ }
+
+ private static class PriorityExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+
+ return (int) _properties.getPriority();
+ }
+ }
+
+ private static class MessageIDExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+ AMQShortString messageId = _properties.getMessageId();
+
+ return (messageId == null) ? null : messageId;
+
+ }
+ }
+
+ private static class TimestampExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+
+ return _properties.getTimestamp();
+ }
+ }
+
+ private static class CorrelationIdExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+ AMQShortString correlationId = _properties.getCorrelationId();
+
+ return (correlationId == null) ? null : correlationId.toString();
+ }
+ }
+
+ private static class ExpirationExpression<E extends Exception> implements Expression<E>
+ {
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ CommonContentHeaderProperties _properties =
+ (CommonContentHeaderProperties)
+ message.getContentHeaderBody().properties;
+
+ return _properties.getExpiration();
+
+ }
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
index 62a45f5420..cb738e1489 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
@@ -25,32 +25,33 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
-public class SimpleFilterManager implements FilterManager
+public class SimpleFilterManager implements FilterManager<AMQException>
{
private final Logger _logger = Logger.getLogger(SimpleFilterManager.class);
- private final ConcurrentLinkedQueue<MessageFilter> _filters;
+ private final ConcurrentLinkedQueue<MessageFilter<AMQException>> _filters;
public SimpleFilterManager()
{
_logger.debug("Creating SimpleFilterManager");
- _filters = new ConcurrentLinkedQueue<MessageFilter>();
+ _filters = new ConcurrentLinkedQueue<MessageFilter<AMQException>>();
}
- public void add(MessageFilter filter)
+ public void add(MessageFilter<AMQException> filter)
{
_filters.add(filter);
}
- public void remove(MessageFilter filter)
+ public void remove(MessageFilter<AMQException> filter)
{
_filters.remove(filter);
}
- public boolean allAllow(AMQMessage msg)
+ public boolean allAllow(Filterable<AMQException> msg)
{
- for (MessageFilter filter : _filters)
+ for (MessageFilter<AMQException> filter : _filters)
{
try
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
index 83b4ed5358..799a38af5a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
@@ -30,45 +30,23 @@ import java.util.Iterator;
import java.util.List;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
/**
* An expression which performs an operation on two expression values
*/
-public abstract class UnaryExpression implements Expression
+public abstract class UnaryExpression<E extends Exception> implements Expression<E>
{
private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
- protected Expression right;
+ protected Expression<E> right;
- public static Expression createNegate(Expression left)
+ public static<E extends Exception> Expression<E> createNegate(Expression<E> left)
{
- return new UnaryExpression(left)
- {
- public Object evaluate(AMQMessage message) throws AMQException
- {
- Object rvalue = right.evaluate(message);
- if (rvalue == null)
- {
- return null;
- }
-
- if (rvalue instanceof Number)
- {
- return negate((Number) rvalue);
- }
-
- return null;
- }
-
- public String getExpressionSymbol()
- {
- return "-";
- }
- };
+ return new NegativeExpression(left);
}
- public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not)
+ public static<E extends Exception> BooleanExpression createInExpression(PropertyExpression<E> right, List elements, final boolean not)
{
// Use a HashSet if there are many elements.
@@ -88,81 +66,17 @@ public abstract class UnaryExpression implements Expression
final Collection inList = t;
- return new BooleanUnaryExpression(right)
- {
- public Object evaluate(AMQMessage message) throws AMQException
- {
-
- Object rvalue = right.evaluate(message);
- if (rvalue == null)
- {
- return null;
- }
-
- if (rvalue.getClass() != String.class)
- {
- return null;
- }
-
- if (((inList != null) && inList.contains(rvalue)) ^ not)
- {
- return Boolean.TRUE;
- }
- else
- {
- return Boolean.FALSE;
- }
-
- }
-
- public String toString()
- {
- StringBuffer answer = new StringBuffer();
- answer.append(right);
- answer.append(" ");
- answer.append(getExpressionSymbol());
- answer.append(" ( ");
-
- int count = 0;
- for (Iterator i = inList.iterator(); i.hasNext();)
- {
- Object o = (Object) i.next();
- if (count != 0)
- {
- answer.append(", ");
- }
-
- answer.append(o);
- count++;
- }
-
- answer.append(" )");
-
- return answer.toString();
- }
-
- public String getExpressionSymbol()
- {
- if (not)
- {
- return "NOT IN";
- }
- else
- {
- return "IN";
- }
- }
- };
+ return new InExpression(right, inList, not);
}
- abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression
+ abstract static class BooleanUnaryExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E>
{
- public BooleanUnaryExpression(Expression left)
+ public BooleanUnaryExpression(Expression<E> left)
{
super(left);
}
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable<E> message) throws E
{
Object object = evaluate(message);
@@ -171,26 +85,9 @@ public abstract class UnaryExpression implements Expression
}
;
- public static BooleanExpression createNOT(BooleanExpression left)
+ public static<E extends Exception> BooleanExpression<E> createNOT(BooleanExpression<E> left)
{
- return new BooleanUnaryExpression(left)
- {
- public Object evaluate(AMQMessage message) throws AMQException
- {
- Boolean lvalue = (Boolean) right.evaluate(message);
- if (lvalue == null)
- {
- return null;
- }
-
- return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
- }
-
- public String getExpressionSymbol()
- {
- return "NOT";
- }
- };
+ return new NotExpression(left);
}
public static BooleanExpression createXPath(final String xpath)
@@ -203,36 +100,9 @@ public abstract class UnaryExpression implements Expression
return new XQueryExpression(xpath);
}
- public static BooleanExpression createBooleanCast(Expression left)
+ public static<E extends Exception> BooleanExpression createBooleanCast(Expression<E> left)
{
- return new BooleanUnaryExpression(left)
- {
- public Object evaluate(AMQMessage message) throws AMQException
- {
- Object rvalue = right.evaluate(message);
- if (rvalue == null)
- {
- return null;
- }
-
- if (!rvalue.getClass().equals(Boolean.class))
- {
- return Boolean.FALSE;
- }
-
- return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
- }
-
- public String toString()
- {
- return right.toString();
- }
-
- public String getExpressionSymbol()
- {
- return "";
- }
- };
+ return new BooleanCastExpression(left);
}
private static Number negate(Number left)
@@ -281,7 +151,7 @@ public abstract class UnaryExpression implements Expression
this.right = left;
}
- public Expression getRight()
+ public Expression<E> getRight()
{
return right;
}
@@ -334,4 +204,166 @@ public abstract class UnaryExpression implements Expression
*/
public abstract String getExpressionSymbol();
+ private static class NegativeExpression<E extends Exception> extends UnaryExpression<E>
+ {
+ public NegativeExpression(final Expression<E> left)
+ {
+ super(left);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ Object rvalue = right.evaluate(message);
+ if (rvalue == null)
+ {
+ return null;
+ }
+
+ if (rvalue instanceof Number)
+ {
+ return negate((Number) rvalue);
+ }
+
+ return null;
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "-";
+ }
+ }
+
+ private static class InExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ {
+ private final Collection _inList;
+ private final boolean _not;
+
+ public InExpression(final PropertyExpression<E> right, final Collection inList, final boolean not)
+ {
+ super(right);
+ _inList = inList;
+ _not = not;
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+
+ Object rvalue = right.evaluate(message);
+ if (rvalue == null)
+ {
+ return null;
+ }
+
+ if (rvalue.getClass() != String.class)
+ {
+ return null;
+ }
+
+ if (((_inList != null) && _inList.contains(rvalue)) ^ _not)
+ {
+ return Boolean.TRUE;
+ }
+ else
+ {
+ return Boolean.FALSE;
+ }
+
+ }
+
+ public String toString()
+ {
+ StringBuffer answer = new StringBuffer();
+ answer.append(right);
+ answer.append(" ");
+ answer.append(getExpressionSymbol());
+ answer.append(" ( ");
+
+ int count = 0;
+ for (Iterator i = _inList.iterator(); i.hasNext();)
+ {
+ Object o = (Object) i.next();
+ if (count != 0)
+ {
+ answer.append(", ");
+ }
+
+ answer.append(o);
+ count++;
+ }
+
+ answer.append(" )");
+
+ return answer.toString();
+ }
+
+ public String getExpressionSymbol()
+ {
+ if (_not)
+ {
+ return "NOT IN";
+ }
+ else
+ {
+ return "IN";
+ }
+ }
+ }
+
+ private static class NotExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ {
+ public NotExpression(final BooleanExpression<E> left)
+ {
+ super(left);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ Boolean lvalue = (Boolean) right.evaluate(message);
+ if (lvalue == null)
+ {
+ return null;
+ }
+
+ return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "NOT";
+ }
+ }
+
+ private static class BooleanCastExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ {
+ public BooleanCastExpression(final Expression<E> left)
+ {
+ super(left);
+ }
+
+ public Object evaluate(Filterable<E> message) throws E
+ {
+ Object rvalue = right.evaluate(message);
+ if (rvalue == null)
+ {
+ return null;
+ }
+
+ if (!rvalue.getClass().equals(Boolean.class))
+ {
+ return Boolean.FALSE;
+ }
+
+ return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public String toString()
+ {
+ return right.toString();
+ }
+
+ public String getExpressionSymbol()
+ {
+ return "";
+ }
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
index f5454afae5..1311178fb1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.filter;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -70,7 +71,7 @@ public final class XPathExpression implements BooleanExpression {
private final XPathEvaluator evaluator;
static public interface XPathEvaluator {
- public boolean evaluate(AMQMessage message) throws AMQException;
+ public boolean evaluate(Filterable message) throws AMQException;
}
XPathExpression(String xpath) {
@@ -92,7 +93,7 @@ public final class XPathExpression implements BooleanExpression {
}
}
- public Object evaluate(AMQMessage message) throws AMQException {
+ public Object evaluate(Filterable message) throws AMQException {
// try {
//FIXME this is flow to disk work
// if( message.isDropped() )
@@ -117,7 +118,7 @@ public final class XPathExpression implements BooleanExpression {
* @return true if the expression evaluates to Boolean.TRUE.
* @throws AMQException
*/
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable message) throws AMQException
{
Object object = evaluate(message);
return object!=null && object==Boolean.TRUE;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
index f5debb607a..c13f81cd08 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
@@ -19,6 +19,7 @@ package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
//
// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html>
@@ -35,7 +36,7 @@ public final class XQueryExpression implements BooleanExpression {
this.xpath = xpath;
}
- public Object evaluate(AMQMessage message) throws AMQException {
+ public Object evaluate(Filterable message) throws AMQException {
return Boolean.FALSE;
}
@@ -48,7 +49,7 @@ public final class XQueryExpression implements BooleanExpression {
* @return true if the expression evaluates to Boolean.TRUE.
* @throws AMQException
*/
- public boolean matches(AMQMessage message) throws AMQException
+ public boolean matches(Filterable message) throws AMQException
{
Object object = evaluate(message);
return object!=null && object==Boolean.TRUE;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
index 35d770fd5d..cc67776682 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
@@ -29,6 +29,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.Filterable;
import org.apache.xpath.CachedXPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.traversal.NodeIterator;
@@ -42,7 +43,7 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
this.xpath = xpath;
}
- public boolean evaluate(AMQMessage m) throws AMQException
+ public boolean evaluate(Filterable m) throws AMQException
{
// TODO - we would have to check the content type and then evaluate the content
// here... is this really a feature we wish to implement? - RobG
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
new file mode 100644
index 0000000000..895db7b15b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
@@ -0,0 +1,62 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.flow;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Set;
+import java.util.HashSet;
+
+public abstract class AbstractFlowCreditManager implements FlowCreditManager
+{
+ protected final AtomicBoolean _suspended = new AtomicBoolean(false);
+ private final Set<FlowCreditManagerListener> _listeners = new HashSet<FlowCreditManagerListener>();
+
+ public final void addStateListener(FlowCreditManagerListener listener)
+ {
+ _listeners.add(listener);
+ }
+
+ public final boolean removeListener(FlowCreditManagerListener listener)
+ {
+ return _listeners.remove(listener);
+ }
+
+ private void notifyListeners(final boolean suspended)
+ {
+ for(FlowCreditManagerListener listener : _listeners)
+ {
+ listener.creditStateChanged(!suspended);
+ }
+ }
+
+ protected final void setSuspended(final boolean suspended)
+ {
+ if(_suspended.compareAndSet(!suspended, suspended))
+ {
+ notifyListeners(suspended);
+ }
+ }
+
+ protected final void notifyIncreaseBytesCredit()
+ {
+ notifyListeners(false);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
new file mode 100644
index 0000000000..96a1071135
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
@@ -0,0 +1,77 @@
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Set;
+import java.util.HashSet;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class BytesOnlyCreditManager extends AbstractFlowCreditManager
+{
+ private final AtomicLong _bytesCredit;
+
+ public BytesOnlyCreditManager(long initialCredit)
+ {
+ _bytesCredit = new AtomicLong(initialCredit);
+ }
+
+ public void addCredit(long messageCredit, long bytesCredit)
+ {
+ _bytesCredit.addAndGet(bytesCredit);
+ setSuspended(false);
+ }
+
+ public void removeAllCredit()
+ {
+ _bytesCredit.set(0L);
+ }
+
+ public boolean hasCredit()
+ {
+ return _bytesCredit.get() > 0L;
+ }
+
+ public boolean useCreditForMessage(AMQMessage msg)
+ {
+ final long msgSize = msg.getSize();
+ if(hasCredit())
+ {
+ if(_bytesCredit.addAndGet(-msgSize) >= 0)
+ {
+ return true;
+ }
+ else
+ {
+ _bytesCredit.addAndGet(msgSize);
+ setSuspended(true);
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
new file mode 100644
index 0000000000..a249a6e63a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
@@ -0,0 +1,44 @@
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public interface FlowCreditManager
+{
+
+ public static interface FlowCreditManagerListener
+ {
+ void creditStateChanged(boolean hasCredit);
+ }
+
+ void addStateListener(FlowCreditManagerListener listener);
+
+ boolean removeListener(FlowCreditManagerListener listener);
+
+ public void addCredit(long messageCredit, long bytesCredit);
+
+ public void removeAllCredit();
+
+ public boolean hasCredit();
+
+ public boolean useCreditForMessage(AMQMessage msg);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
new file mode 100644
index 0000000000..d63431c3eb
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
@@ -0,0 +1,44 @@
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager
+{
+ public void addCredit(long messageCredit, long bytesCredit)
+ {
+ }
+
+ public void removeAllCredit()
+ {
+ }
+
+ public boolean hasCredit()
+ {
+ return true;
+ }
+
+ public boolean useCreditForMessage(AMQMessage msg)
+ {
+ return true;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
new file mode 100644
index 0000000000..9c377481de
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
@@ -0,0 +1,79 @@
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class MessageAndBytesCreditManager extends AbstractFlowCreditManager implements FlowCreditManager
+{
+ private long _messageCredit;
+ private long _bytesCredit;
+
+ MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit)
+ {
+ _messageCredit = messageCredit;
+ _bytesCredit = bytesCredit;
+ }
+
+ public synchronized void addCredit(long messageCredit, long bytesCredit)
+ {
+ _messageCredit += messageCredit;
+ _bytesCredit += bytesCredit;
+ setSuspended(hasCredit());
+ }
+
+ public synchronized void removeAllCredit()
+ {
+ _messageCredit = 0L;
+ _bytesCredit = 0L;
+ setSuspended(true);
+ }
+
+ public synchronized boolean hasCredit()
+ {
+ return (_messageCredit > 0L) && ( _bytesCredit > 0L );
+ }
+
+ public synchronized boolean useCreditForMessage(AMQMessage msg)
+ {
+ if(_messageCredit == 0L)
+ {
+ setSuspended(true);
+ return false;
+ }
+ else
+ {
+ final long msgSize = msg.getSize();
+ if(msgSize > _bytesCredit)
+ {
+ setSuspended(true);
+ return false;
+ }
+ _messageCredit--;
+ _bytesCredit -= msgSize;
+ setSuspended(false);
+ return true;
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
new file mode 100644
index 0000000000..c1b3a09006
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
@@ -0,0 +1,76 @@
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class MessageOnlyCreditManager extends AbstractFlowCreditManager implements FlowCreditManager
+{
+ private final AtomicLong _messageCredit;
+
+ public MessageOnlyCreditManager(final long initialCredit)
+ {
+ _messageCredit = new AtomicLong(initialCredit);
+ }
+
+ public void addCredit(long messageCredit, long bytesCredit)
+ {
+ setSuspended(false);
+ _messageCredit.addAndGet(messageCredit);
+ }
+
+ public void removeAllCredit()
+ {
+ setSuspended(true);
+ _messageCredit.set(0L);
+ }
+
+ public boolean hasCredit()
+ {
+ return _messageCredit.get() > 0L;
+ }
+
+ public boolean useCreditForMessage(AMQMessage msg)
+ {
+ if(hasCredit())
+ {
+ if(_messageCredit.addAndGet(-1L) >= 0)
+ {
+ setSuspended(false);
+ return true;
+ }
+ else
+ {
+ _messageCredit.addAndGet(1L);
+ setSuspended(true);
+ return false;
+ }
+ }
+ else
+ {
+ setSuspended(true);
+ return false;
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
new file mode 100644
index 0000000000..be0300f2c1
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
@@ -0,0 +1,185 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.queue.AMQMessage;
+
+public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager
+{
+
+ private volatile long _bytesCreditLimit;
+ private volatile long _messageCreditLimit;
+
+ private volatile long _bytesCredit;
+ private volatile long _messageCredit;
+
+ public Pre0_10CreditManager(long bytesCreditLimit, long messageCreditLimit)
+ {
+ _bytesCreditLimit = bytesCreditLimit;
+ _messageCreditLimit = messageCreditLimit;
+ _bytesCredit = bytesCreditLimit;
+ _messageCredit = messageCreditLimit;
+ }
+
+
+ public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit)
+ {
+ long bytesCreditChange = bytesCreditLimit - _bytesCreditLimit;
+ long messageCreditChange = messageCreditLimit - _messageCreditLimit;
+
+
+
+ if(bytesCreditChange != 0L)
+ {
+ if(bytesCreditLimit == 0L)
+ {
+ _bytesCredit = 0;
+ }
+ else
+ {
+ _bytesCredit += bytesCreditChange;
+ }
+ }
+
+
+ if(messageCreditChange != 0L)
+ {
+ if(messageCreditLimit == 0L)
+ {
+ _messageCredit = 0;
+ }
+ else
+ {
+ _messageCredit += messageCreditChange;
+ }
+ }
+
+
+ _bytesCreditLimit = bytesCreditLimit;
+ _messageCreditLimit = messageCreditLimit;
+
+ setSuspended(!hasCredit());
+
+ }
+
+
+ public synchronized void addCredit(final long messageCredit, final long bytesCredit)
+ {
+ final long messageCreditLimit = _messageCreditLimit;
+ boolean notifyIncrease = true;
+ if(messageCreditLimit != 0L)
+ {
+ notifyIncrease = (_messageCredit != 0);
+ long newCredit = _messageCredit + messageCredit;
+ _messageCredit = newCredit > messageCreditLimit ? messageCreditLimit : newCredit;
+ }
+
+
+ final long bytesCreditLimit = _bytesCreditLimit;
+ if(bytesCreditLimit != 0L)
+ {
+ long newCredit = _bytesCredit + bytesCredit;
+ _bytesCredit = newCredit > bytesCreditLimit ? bytesCreditLimit : newCredit;
+ if(notifyIncrease && bytesCredit>0)
+ {
+ notifyIncreaseBytesCredit();
+ }
+ }
+
+
+
+ setSuspended(!hasCredit());
+
+ }
+
+ public synchronized void removeAllCredit()
+ {
+ _bytesCredit = 0L;
+ _messageCredit = 0L;
+ setSuspended(!hasCredit());
+ }
+
+ public synchronized boolean hasCredit()
+ {
+ return (_bytesCreditLimit == 0L || _bytesCredit > 0)
+ && (_messageCreditLimit == 0L || _messageCredit > 0);
+ }
+
+ public synchronized boolean useCreditForMessage(final AMQMessage msg)
+ {
+ if(_messageCreditLimit != 0L)
+ {
+ if(_messageCredit != 0L)
+ {
+ if(_bytesCreditLimit == 0L)
+ {
+ _messageCredit--;
+
+ return true;
+ }
+ else
+ {
+ if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ {
+ _messageCredit--;
+ _bytesCredit -= msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ setSuspended(true);
+ return false;
+ }
+ }
+ else
+ {
+ if(_bytesCreditLimit == 0L)
+ {
+
+ return true;
+ }
+ else
+ {
+ if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ {
+ _bytesCredit -= msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
index 133c97a146..c13a69b793 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
@@ -1,65 +1,40 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.qpid.server.handler;
-
-import org.apache.qpid.framing.*;
-import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.AMQException;
-
-/**
- * @author Apache Software Foundation
- *
- *
- */
-public class AccessRequestHandler implements StateAwareMethodListener<AccessRequestBody>
-{
- private static final AccessRequestHandler _instance = new AccessRequestHandler();
-
-
- public static AccessRequestHandler getInstance()
- {
- return _instance;
- }
-
- private AccessRequestHandler()
- {
- }
-
- public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException
- {
- AMQProtocolSession session = stateManager.getProtocolSession();
-
- MethodRegistry methodRegistry = session.getMethodRegistry();
-
- // We don't implement access control class, but to keep clients happy that expect it
- // always use the "0" ticket.
- AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0);
-
- session.writeFrame(response.generateFrame(channelId));
- }
-}
+package org.apache.qpid.server.handler;
+
+import org.apache.qpid.framing.*;
+import org.apache.qpid.server.state.StateAwareMethodListener;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.AMQException;
+
+/**
+ * @author Apache Software Foundation
+ *
+ *
+ */
+public class AccessRequestHandler implements StateAwareMethodListener<AccessRequestBody>
+{
+ private static final AccessRequestHandler _instance = new AccessRequestHandler();
+
+
+ public static AccessRequestHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private AccessRequestHandler()
+ {
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AccessRequestBody body, int channelId) throws AMQException
+ {
+ AMQProtocolSession session = stateManager.getProtocolSession();
+
+ MethodRegistry methodRegistry = session.getMethodRegistry();
+
+ // We don't implement access control class, but to keep clients happy that expect it
+ // always use the "0" ticket.
+ AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0);
+
+ session.writeFrame(response.generateFrame(channelId));
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java
index bda1c16cf6..29054f55c1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java
@@ -21,11 +21,9 @@
package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQFrame;
import org.apache.qpid.framing.BasicCancelBody;
import org.apache.qpid.framing.BasicCancelOkBody;
import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQStateManager;
@@ -65,7 +63,7 @@ public class BasicCancelMethodHandler implements StateAwareMethodListener<BasicC
" nowait:" + body.getNowait());
}
- channel.unsubscribeConsumer(session, body.getConsumerTag());
+ channel.unsubscribeConsumer(body.getConsumerTag());
if (!body.getNowait())
{
MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
index 7cd4afdb77..5342a7f518 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
@@ -111,7 +111,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
try
{
- AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, session, !body.getNoAck(),
+ AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(),
body.getArguments(), body.getNoLocal(), body.getExclusive());
if (!body.getNowait())
{
@@ -121,8 +121,7 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
}
- //now allow queue to start async processing of any backlog of messages
- queue.deliverAsync();
+
}
catch (org.apache.qpid.AMQInvalidArgumentException ise)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
index 3731116cba..be1135dd91 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
@@ -1,101 +1,187 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.handler;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.BasicGetBody;
-import org.apache.qpid.framing.BasicGetEmptyBody;
-import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.security.access.Permission;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetBody>
-{
- private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class);
-
- private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler();
-
- public static BasicGetMethodHandler getInstance()
- {
- return _instance;
- }
-
- private BasicGetMethodHandler()
- {
- }
-
- public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException
- {
- AMQProtocolSession session = stateManager.getProtocolSession();
-
-
- VirtualHost vHost = session.getVirtualHost();
-
- AMQChannel channel = session.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId);
- }
- else
- {
- AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue());
-
- if (queue == null)
- {
- _log.info("No queue for '" + body.getQueue() + "'");
- if(body.getQueue()!=null)
- {
- throw body.getConnectionException(AMQConstant.NOT_FOUND,
- "No such queue, '" + body.getQueue()+ "'");
- }
- else
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "No queue name provided, no default queue defined.");
- }
- }
- else
- {
-
- //Perform ACLs
- vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue);
-
- if (!queue.performGet(session, channel, !body.getNoAck()))
- {
- MethodRegistry methodRegistry = session.getMethodRegistry();
- // TODO - set clusterId
- BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null);
-
-
- session.writeFrame(responseBody.generateFrame(channelId));
- }
- }
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicGetBody;
+import org.apache.qpid.framing.BasicGetEmptyBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.flow.MessageOnlyCreditManager;
+import org.apache.qpid.server.subscription.SubscriptionImpl;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
+import org.apache.qpid.server.subscription.RecordDeliveryMethod;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.SimpleAMQQueue;
+import org.apache.qpid.server.security.access.Permission;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.state.StateAwareMethodListener;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetBody>
+{
+ private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class);
+
+ private static final BasicGetMethodHandler _instance = new BasicGetMethodHandler();
+
+ public static BasicGetMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private BasicGetMethodHandler()
+ {
+ }
+
+ public void methodReceived(AMQStateManager stateManager, BasicGetBody body, int channelId) throws AMQException
+ {
+ AMQProtocolSession session = stateManager.getProtocolSession();
+
+
+ VirtualHost vHost = session.getVirtualHost();
+
+ AMQChannel channel = session.getChannel(channelId);
+ if (channel == null)
+ {
+ throw body.getChannelNotFoundException(channelId);
+ }
+ else
+ {
+ AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueueRegistry().getQueue(body.getQueue());
+ if (queue == null)
+ {
+ _log.info("No queue for '" + body.getQueue() + "'");
+ if(body.getQueue()!=null)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_FOUND,
+ "No such queue, '" + body.getQueue()+ "'");
+ }
+ else
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "No queue name provided, no default queue defined.");
+ }
+ }
+ else
+ {
+
+ //Perform ACLs
+ vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue);
+
+ if (!performGet(queue,session, channel, !body.getNoAck()))
+ {
+ MethodRegistry methodRegistry = session.getMethodRegistry();
+ // TODO - set clusterId
+ BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null);
+
+
+ session.writeFrame(responseBody.generateFrame(channelId));
+ }
+ }
+ }
+ }
+
+ public static boolean performGet(final AMQQueue queue,
+ final AMQProtocolSession session,
+ final AMQChannel channel,
+ final boolean acks)
+ throws AMQException
+ {
+
+ final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L);
+
+ final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod()
+ {
+
+ int _msg;
+
+ public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ throws AMQException
+ {
+ singleMessageCredit.useCreditForMessage(entry.getMessage());
+ session.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(),
+ deliveryTag, queue.getMessageCount());
+
+ }
+ };
+ final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod()
+ {
+
+ public void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ {
+ channel.addUnacknowledgedMessage(entry, deliveryTag, null);
+ }
+ };
+
+ Subscription sub;
+ if(acks)
+ {
+ sub = SubscriptionFactoryImpl.INSTANCE.createSubscription(channel, session, null, acks, null, false, singleMessageCredit, getDeliveryMethod, getRecordMethod);
+ }
+ else
+ {
+ sub = new GetNoAckSubscription(channel,
+ session,
+ null,
+ null,
+ false,
+ singleMessageCredit,
+ getDeliveryMethod,
+ getRecordMethod);
+ }
+
+ queue.registerSubscription(sub,false);
+ queue.flushSubscription(sub);
+ queue.unregisterSubscription(sub);
+ return(!singleMessageCredit.hasCredit());
+
+
+ }
+
+ public static final class GetNoAckSubscription extends SubscriptionImpl.NoAckSubscription
+ {
+ public GetNoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager,
+ ClientDeliveryMethod deliveryMethod,
+ RecordDeliveryMethod recordMethod)
+ throws AMQException
+ {
+ super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
+ }
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return !getCreditManager().useCreditForMessage(msg.getMessage());
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
index 0f99a21ee5..e8e42454de 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
@@ -91,7 +91,7 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic
MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body);
info.setExchange(exchange);
- channel.setPublishFrame(info, session, e);
+ channel.setPublishFrame(info, e);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java
index 3c95180dca..dd3281c65f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java
@@ -22,10 +22,8 @@ package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.BasicQosBody;
-import org.apache.qpid.framing.BasicQosOkBody;
import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -49,8 +47,8 @@ public class BasicQosHandler implements StateAwareMethodListener<BasicQosBody>
throw body.getChannelNotFoundException(channelId);
}
- channel.setPrefetchCount(body.getPrefetchCount());
- channel.setPrefetchSize(body.getPrefetchSize());
+ channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount());
+
MethodRegistry methodRegistry = session.getMethodRegistry();
AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
index bca35be535..15484273c8 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
@@ -1,75 +1,54 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.handler;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.framing.BasicRecoverBody;
-import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.framing.BasicRecoverSyncBody;
-import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
-import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
-import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.AMQException;
-
-public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener<BasicRecoverSyncBody>
-{
- private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class);
-
- private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler();
-
- public static BasicRecoverSyncMethodHandler getInstance()
- {
- return _instance;
- }
-
- public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException
- {
- AMQProtocolSession session = stateManager.getProtocolSession();
-
- _logger.debug("Recover received on protocol session " + session + " and channel " + channelId);
- AMQChannel channel = session.getChannel(channelId);
-
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId);
- }
-
- channel.resend(body.getRequeue());
-
- // Qpid 0-8 hacks a synchronous -ok onto recover.
- // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant
- if(session.getProtocolVersion().equals(ProtocolVersion.v0_9))
- {
- MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry();
- AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody();
- session.writeFrame(recoverOk.generateFrame(channelId));
-
- }
-
- }
-}
+package org.apache.qpid.server.handler;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.framing.BasicRecoverBody;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.BasicRecoverSyncBody;
+import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
+import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
+import org.apache.qpid.server.state.StateAwareMethodListener;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.AMQException;
+
+public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener<BasicRecoverSyncBody>
+{
+ private static final Logger _logger = Logger.getLogger(BasicRecoverSyncMethodHandler.class);
+
+ private static final BasicRecoverSyncMethodHandler _instance = new BasicRecoverSyncMethodHandler();
+
+ public static BasicRecoverSyncMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, BasicRecoverSyncBody body, int channelId) throws AMQException
+ {
+ AMQProtocolSession session = stateManager.getProtocolSession();
+
+ _logger.debug("Recover received on protocol session " + session + " and channel " + channelId);
+ AMQChannel channel = session.getChannel(channelId);
+
+
+ if (channel == null)
+ {
+ throw body.getChannelNotFoundException(channelId);
+ }
+
+ channel.resend(body.getRequeue());
+
+ // Qpid 0-8 hacks a synchronous -ok onto recover.
+ // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant
+ if(session.getProtocolVersion().equals(ProtocolVersion.v0_9))
+ {
+ MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry();
+ AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody();
+ session.writeFrame(recoverOk.generateFrame(channelId));
+
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
index 069cc6ea2c..f3cab10ed7 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
@@ -22,9 +22,8 @@ package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.BasicRejectBody;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.ack.UnacknowledgedMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -49,16 +48,6 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
AMQProtocolSession session = stateManager.getProtocolSession();
-
-
-// if (_logger.isDebugEnabled())
-// {
-// _logger.debug("Rejecting:" + evt.getMethod().deliveryTag +
-// ": Requeue:" + evt.getMethod().requeue +
-//// ": Resend:" + evt.getMethod().resend +
-// " on channel:" + channelId);
-// }
-
AMQChannel channel = session.getChannel(channelId);
if (channel == null)
@@ -76,7 +65,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
long deliveryTag = body.getDeliveryTag();
- UnacknowledgedMessage message = channel.getUnacknowledgedMessageMap().get(deliveryTag);
+ QueueEntry message = channel.getUnacknowledgedMessageMap().get(deliveryTag);
if (message == null)
{
@@ -85,11 +74,16 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
}
else
{
- if (message.isQueueDeleted() || message.getQueue().isDeleted())
+ if (message.isQueueDeleted())
{
_logger.warn("Message's Queue as already been purged, unable to Reject. " +
"Dropping message should use Dead Letter Queue");
- //sendtoDeadLetterQueue(msg)
+ message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
+ if(message != null)
+ {
+ message.discard(channel.getStoreContext());
+ }
+ //sendtoDeadLetterQueue(msg)
return;
}
@@ -111,7 +105,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
// If we haven't requested message to be resent to this consumer then reject it from ever getting it.
//if (!evt.getMethod().resend)
{
- message.entry.reject();
+ message.reject();
}
if (body.getRequeue())
@@ -121,6 +115,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
else
{
_logger.warn("Dropping message as requeue not required and there is no dead letter queue");
+ message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
//sendtoDeadLetterQueue(AMQMessage message)
// message.queue = channel.getDefaultDeadLetterQueue();
// channel.requeue(deliveryTag);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
index 491a2f80db..ccd42204d9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
@@ -22,12 +22,10 @@ package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
index 97d25f650d..39b048aecb 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
@@ -101,7 +101,7 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
else if (!exchange.getType().equals(body.getType()))
{
- throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(), null);
+ throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
index 0f6dc7a19d..46182e8c00 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
@@ -112,7 +112,7 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody>
if (!exch.isBound(routingKey, body.getArguments(), queue))
{
- queue.bind(routingKey, body.getArguments(), exch);
+ queue.bind(exch, routingKey, body.getArguments());
}
}
catch (AMQInvalidRoutingKeyException rke)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
index 7df864f189..379ec7a7d6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
@@ -34,9 +34,10 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.security.access.Permission;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.store.MessageStore;
@@ -123,7 +124,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
{
Exchange defaultExchange = exchangeRegistry.getDefaultExchange();
- queue.bind(queueName, null, defaultExchange);
+ queue.bind(defaultExchange, queueName, null);
_logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getName() + ")");
}
}
@@ -173,7 +174,9 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
{
final QueueRegistry registry = virtualHost.getQueueRegistry();
AMQShortString owner = body.getExclusive() ? session.getContextKey() : null;
- final AMQQueue queue = new AMQQueue(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost);
+
+ final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost,
+ body.getArguments());
if (body.getExclusive() && !body.getDurable())
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
index 310a73ffeb..dfc36f5b93 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
@@ -24,11 +24,10 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.QueueDeleteBody;
import org.apache.qpid.framing.QueueDeleteOkBody;
import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.store.MessageStore;
@@ -104,15 +103,16 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB
}
else
{
-
+
//Perform ACLs
virtualHost.getAccessManager().authorise(session, Permission.DELETE, body, queue);
- int purged = queue.delete(body.getIfUnused(), body.getIfEmpty());
+ int purged = queue.delete();
+
if (queue.isDurable())
{
- store.removeQueue(queue.getName());
+ store.removeQueue(queue);
}
MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
index a854c97f60..7377862875 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
@@ -1,121 +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.server.handler;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.QueuePurgeBody;
-import org.apache.qpid.framing.QueuePurgeOkBody;
-import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.protocol.AMQMethodEvent;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.security.access.Permission;
-
-public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBody>
-{
- private static final QueuePurgeHandler _instance = new QueuePurgeHandler();
-
- public static QueuePurgeHandler getInstance()
- {
- return _instance;
- }
-
- private final boolean _failIfNotFound;
-
- public QueuePurgeHandler()
- {
- this(true);
- }
-
- public QueuePurgeHandler(boolean failIfNotFound)
- {
- _failIfNotFound = failIfNotFound;
- }
-
- public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException
- {
- AMQProtocolSession session = stateManager.getProtocolSession();
- VirtualHost virtualHost = session.getVirtualHost();
- QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
-
- AMQChannel channel = session.getChannel(channelId);
-
-
- AMQQueue queue;
- if(body.getQueue() == null)
- {
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId);
- }
-
- //get the default queue on the channel:
- queue = channel.getDefaultQueue();
-
- if(queue == null)
- {
- if(_failIfNotFound)
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified.");
- }
- }
- }
- else
- {
- queue = queueRegistry.getQueue(body.getQueue());
- }
-
- if(queue == null)
- {
- if(_failIfNotFound)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.");
- }
- }
- else
- {
-
- //Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue);
-
- long purged = queue.clearQueue(channel.getStoreContext());
-
-
- if(!body.getNowait())
- {
-
- MethodRegistry methodRegistry = session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged);
- session.writeFrame(responseBody.generateFrame(channelId));
-
- }
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.QueuePurgeBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.state.StateAwareMethodListener;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.security.access.Permission;
+
+public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBody>
+{
+ private static final QueuePurgeHandler _instance = new QueuePurgeHandler();
+
+ public static QueuePurgeHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private final boolean _failIfNotFound;
+
+ public QueuePurgeHandler()
+ {
+ this(true);
+ }
+
+ public QueuePurgeHandler(boolean failIfNotFound)
+ {
+ _failIfNotFound = failIfNotFound;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, QueuePurgeBody body, int channelId) throws AMQException
+ {
+ AMQProtocolSession session = stateManager.getProtocolSession();
+ VirtualHost virtualHost = session.getVirtualHost();
+ QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
+
+ AMQChannel channel = session.getChannel(channelId);
+
+
+ AMQQueue queue;
+ if(body.getQueue() == null)
+ {
+
+ if (channel == null)
+ {
+ throw body.getChannelNotFoundException(channelId);
+ }
+
+ //get the default queue on the channel:
+ queue = channel.getDefaultQueue();
+
+ if(queue == null)
+ {
+ if(_failIfNotFound)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,"No queue specified.");
+ }
+ }
+ }
+ else
+ {
+ queue = queueRegistry.getQueue(body.getQueue());
+ }
+
+ if(queue == null)
+ {
+ if(_failIfNotFound)
+ {
+ throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.");
+ }
+ }
+ else
+ {
+
+ //Perform ACLs
+ virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue);
+
+ long purged = queue.clearQueue(channel.getStoreContext());
+
+
+ if(!body.getNowait())
+ {
+
+ MethodRegistry methodRegistry = session.getMethodRegistry();
+ AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged);
+ session.writeFrame(responseBody.generateFrame(channelId));
+
+ }
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index 6b2924031a..d73e33d6c8 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -1,24 +1,3 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
package org.apache.qpid.server.handler;
import org.apache.log4j.Logger;
@@ -63,7 +42,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
final AMQQueue queue;
- final AMQShortString routingKey;
+ final AMQShortString routingKey;
if (body.getQueue() == null)
{
@@ -105,7 +84,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
try
{
- queue.unBind(routingKey, body.getArguments(), exch);
+ queue.unBind(exch, routingKey, body.getArguments());
}
catch (AMQInvalidRoutingKeyException rke)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
index d24e4f6ffa..9475b83c8f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
@@ -1,566 +1,566 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.handler;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.AMQException;
-
-public class ServerMethodDispatcherImpl implements MethodDispatcher
-{
- private final AMQStateManager _stateManager;
-
- private static interface DispatcherFactory
- {
- public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager);
- }
-
- private static final Map<ProtocolVersion, DispatcherFactory> _dispatcherFactories =
- new HashMap<ProtocolVersion, DispatcherFactory>();
-
-
- static
- {
- _dispatcherFactories.put(ProtocolVersion.v8_0,
- new DispatcherFactory()
- {
- public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager)
- {
- return new ServerMethodDispatcherImpl_8_0(stateManager);
- }
- });
-
- _dispatcherFactories.put(ProtocolVersion.v0_9,
- new DispatcherFactory()
- {
- public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager)
- {
- return new ServerMethodDispatcherImpl_0_9(stateManager);
- }
- });
-
- }
-
-
- private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance();
- private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance();
- private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance();
- private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance();
- private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance();
- private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance();
- private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance();
- private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance();
- private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance();
- private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance();
- private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance();
- private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance();
- private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance();
- private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance();
- private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance();
- private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance();
- private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance();
- private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance();
- private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance();
- private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance();
- private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance();
- private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance();
- private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance();
- private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance();
- private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance();
- private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance();
- private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance();
- private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance();
- private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance();
-
-
-
- public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion)
- {
- return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager);
- }
-
-
- public ServerMethodDispatcherImpl(AMQStateManager stateManager)
- {
- _stateManager = stateManager;
- }
-
-
- protected AMQStateManager getStateManager()
- {
- return _stateManager;
- }
-
-
-
- public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException
- {
- _accessRequestHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException
- {
- _basicAckMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException
- {
- _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException
- {
- _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException
- {
- _basicGetMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException
- {
- _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException
- {
- _basicQosHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException
- {
- _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException
- {
- _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException
- {
- _channelOpenHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
- public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException
- {
- _channelCloseHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
- public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException
- {
- _channelCloseOkHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
- public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
- {
- _channelFlowHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException
- {
- _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
- public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException
- {
- _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
- public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException
- {
- _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException
- {
- _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException
- {
- _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException
- {
- _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException
- {
- _exchangeBoundHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException
- {
- _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException
- {
- _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException
- {
- _queueBindHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException
- {
- _queueDeclareHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException
- {
- _queueDeleteHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException
- {
- _queuePurgeHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException
- {
- _txCommitHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException
- {
- _txRollbackHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
- public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException
- {
- _txSelectHandler.methodReceived(_stateManager, body, channelId);
- return true;
- }
-
-
-
-
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.AMQException;
+
+public class ServerMethodDispatcherImpl implements MethodDispatcher
+{
+ private final AMQStateManager _stateManager;
+
+ private static interface DispatcherFactory
+ {
+ public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager);
+ }
+
+ private static final Map<ProtocolVersion, DispatcherFactory> _dispatcherFactories =
+ new HashMap<ProtocolVersion, DispatcherFactory>();
+
+
+ static
+ {
+ _dispatcherFactories.put(ProtocolVersion.v8_0,
+ new DispatcherFactory()
+ {
+ public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager)
+ {
+ return new ServerMethodDispatcherImpl_8_0(stateManager);
+ }
+ });
+
+ _dispatcherFactories.put(ProtocolVersion.v0_9,
+ new DispatcherFactory()
+ {
+ public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager)
+ {
+ return new ServerMethodDispatcherImpl_0_9(stateManager);
+ }
+ });
+
+ }
+
+
+ private static final AccessRequestHandler _accessRequestHandler = AccessRequestHandler.getInstance();
+ private static final ChannelCloseHandler _channelCloseHandler = ChannelCloseHandler.getInstance();
+ private static final ChannelOpenHandler _channelOpenHandler = ChannelOpenHandler.getInstance();
+ private static final ChannelCloseOkHandler _channelCloseOkHandler = ChannelCloseOkHandler.getInstance();
+ private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance();
+ private static final ConnectionCloseOkMethodHandler _connectionCloseOkMethodHandler = ConnectionCloseOkMethodHandler.getInstance();
+ private static final ConnectionOpenMethodHandler _connectionOpenMethodHandler = ConnectionOpenMethodHandler.getInstance();
+ private static final ConnectionTuneOkMethodHandler _connectionTuneOkMethodHandler = ConnectionTuneOkMethodHandler.getInstance();
+ private static final ConnectionSecureOkMethodHandler _connectionSecureOkMethodHandler = ConnectionSecureOkMethodHandler.getInstance();
+ private static final ConnectionStartOkMethodHandler _connectionStartOkMethodHandler = ConnectionStartOkMethodHandler.getInstance();
+ private static final ExchangeDeclareHandler _exchangeDeclareHandler = ExchangeDeclareHandler.getInstance();
+ private static final ExchangeDeleteHandler _exchangeDeleteHandler = ExchangeDeleteHandler.getInstance();
+ private static final ExchangeBoundHandler _exchangeBoundHandler = ExchangeBoundHandler.getInstance();
+ private static final BasicAckMethodHandler _basicAckMethodHandler = BasicAckMethodHandler.getInstance();
+ private static final BasicRecoverMethodHandler _basicRecoverMethodHandler = BasicRecoverMethodHandler.getInstance();
+ private static final BasicConsumeMethodHandler _basicConsumeMethodHandler = BasicConsumeMethodHandler.getInstance();
+ private static final BasicGetMethodHandler _basicGetMethodHandler = BasicGetMethodHandler.getInstance();
+ private static final BasicCancelMethodHandler _basicCancelMethodHandler = BasicCancelMethodHandler.getInstance();
+ private static final BasicPublishMethodHandler _basicPublishMethodHandler = BasicPublishMethodHandler.getInstance();
+ private static final BasicQosHandler _basicQosHandler = BasicQosHandler.getInstance();
+ private static final QueueBindHandler _queueBindHandler = QueueBindHandler.getInstance();
+ private static final QueueDeclareHandler _queueDeclareHandler = QueueDeclareHandler.getInstance();
+ private static final QueueDeleteHandler _queueDeleteHandler = QueueDeleteHandler.getInstance();
+ private static final QueuePurgeHandler _queuePurgeHandler = QueuePurgeHandler.getInstance();
+ private static final ChannelFlowHandler _channelFlowHandler = ChannelFlowHandler.getInstance();
+ private static final TxSelectHandler _txSelectHandler = TxSelectHandler.getInstance();
+ private static final TxCommitHandler _txCommitHandler = TxCommitHandler.getInstance();
+ private static final TxRollbackHandler _txRollbackHandler = TxRollbackHandler.getInstance();
+ private static final BasicRejectMethodHandler _basicRejectMethodHandler = BasicRejectMethodHandler.getInstance();
+
+
+
+ public static MethodDispatcher createMethodDispatcher(AMQStateManager stateManager, ProtocolVersion protocolVersion)
+ {
+ return _dispatcherFactories.get(protocolVersion).createMethodDispatcher(stateManager);
+ }
+
+
+ public ServerMethodDispatcherImpl(AMQStateManager stateManager)
+ {
+ _stateManager = stateManager;
+ }
+
+
+ protected AMQStateManager getStateManager()
+ {
+ return _stateManager;
+ }
+
+
+
+ public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException
+ {
+ _accessRequestHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException
+ {
+ _basicAckMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException
+ {
+ _basicCancelMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException
+ {
+ _basicConsumeMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException
+ {
+ _basicGetMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException
+ {
+ _basicPublishMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException
+ {
+ _basicQosHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException
+ {
+ _basicRecoverMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException
+ {
+ _basicRejectMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException
+ {
+ _channelOpenHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+ public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException
+ {
+ _channelCloseHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+ public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException
+ {
+ _channelCloseOkHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+ public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
+ {
+ _channelFlowHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+
+ public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException
+ {
+ _connectionOpenMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+ public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException
+ {
+ _connectionCloseMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+ public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException
+ {
+ _connectionCloseOkMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchDtxSelectOk(DtxSelectOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchDtxStartOk(DtxStartOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileCancelOk(FileCancelOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileConsumeOk(FileConsumeOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileDeliver(FileDeliverBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileOpen(FileOpenBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileOpenOk(FileOpenOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileQosOk(FileQosOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileReturn(FileReturnBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchFileStage(FileStageBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchStreamCancelOk(StreamCancelOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchStreamConsumeOk(StreamConsumeOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchStreamDeliver(StreamDeliverBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchStreamQosOk(StreamQosOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchStreamReturn(StreamReturnBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+
+ public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException
+ {
+ _connectionSecureOkMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException
+ {
+ _connectionStartOkMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException
+ {
+ _connectionTuneOkMethodHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchDtxSelect(DtxSelectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchDtxStart(DtxStartBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException
+ {
+ _exchangeBoundHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException
+ {
+ _exchangeDeclareHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException
+ {
+ _exchangeDeleteHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchFileAck(FileAckBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchFileCancel(FileCancelBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchFileConsume(FileConsumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchFilePublish(FilePublishBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchFileQos(FileQosBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchFileReject(FileRejectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException
+ {
+ _queueBindHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException
+ {
+ _queueDeclareHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException
+ {
+ _queueDeleteHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException
+ {
+ _queuePurgeHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchStreamCancel(StreamCancelBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchStreamConsume(StreamConsumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchStreamPublish(StreamPublishBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchStreamQos(StreamQosBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTunnelRequest(TunnelRequestBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTxCommit(TxCommitBody body, int channelId) throws AMQException
+ {
+ _txCommitHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchTxRollback(TxRollbackBody body, int channelId) throws AMQException
+ {
+ _txRollbackHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+ public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException
+ {
+ _txSelectHandler.methodReceived(_stateManager, body, channelId);
+ return true;
+ }
+
+
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java
index 382a85347b..8b1dca77ba 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_9.java
@@ -1,164 +1,164 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.handler;
-
-
-import org.apache.qpid.framing.amqp_0_9.MethodDispatcher_0_9;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.AMQException;
-
-
-
-public class ServerMethodDispatcherImpl_0_9
- extends ServerMethodDispatcherImpl
- implements MethodDispatcher_0_9
-
-{
-
- private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler =
- BasicRecoverSyncMethodHandler.getInstance();
- private static final QueueUnbindHandler _queueUnbindHandler =
- QueueUnbindHandler.getInstance();
-
-
- public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager)
- {
- super(stateManager);
- }
-
- public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
- {
- _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId);
- return true;
- }
-
- public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
- {
- _queueUnbindHandler.methodReceived(getStateManager(),body,channelId);
- return true;
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+
+import org.apache.qpid.framing.amqp_0_9.MethodDispatcher_0_9;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.AMQException;
+
+
+
+public class ServerMethodDispatcherImpl_0_9
+ extends ServerMethodDispatcherImpl
+ implements MethodDispatcher_0_9
+
+{
+
+ private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler =
+ BasicRecoverSyncMethodHandler.getInstance();
+ private static final QueueUnbindHandler _queueUnbindHandler =
+ QueueUnbindHandler.getInstance();
+
+
+ public ServerMethodDispatcherImpl_0_9(AMQStateManager stateManager)
+ {
+ super(stateManager);
+ }
+
+ public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
+ {
+ _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
+ {
+ _queueUnbindHandler.methodReceived(getStateManager(),body,channelId);
+ return true;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java
index 22f64cf7d3..d599ca3d4e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_8_0.java
@@ -1,86 +1,86 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.handler;
-
-import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.AMQException;
-
-public class ServerMethodDispatcherImpl_8_0
- extends ServerMethodDispatcherImpl
- implements MethodDispatcher_8_0
-{
- public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager)
- {
- super(stateManager);
- }
-
- public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException
- {
- return false;
- }
-
- public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException
- {
- return false;
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+import org.apache.qpid.framing.amqp_8_0.MethodDispatcher_8_0;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.AMQException;
+
+public class ServerMethodDispatcherImpl_8_0
+ extends ServerMethodDispatcherImpl
+ implements MethodDispatcher_8_0
+{
+ public ServerMethodDispatcherImpl_8_0(AMQStateManager stateManager)
+ {
+ super(stateManager);
+ }
+
+ public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchChannelAlert(ChannelAlertBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchTestContent(TestContentBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestContentOk(TestContentOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestInteger(TestIntegerBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestIntegerOk(TestIntegerOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestString(TestStringBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestStringOk(TestStringOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestTable(TestTableBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchTestTableOk(TestTableOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
index 79cc722e0e..9b23d88838 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
@@ -23,10 +23,8 @@ package org.apache.qpid.server.handler;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.TxCommitBody;
-import org.apache.qpid.framing.TxCommitOkBody;
import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQStateManager;
@@ -70,7 +68,7 @@ public class TxCommitHandler implements StateAwareMethodListener<TxCommitBody>
AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody();
session.writeFrame(responseBody.generateFrame(channelId));
- channel.processReturns(session);
+ channel.processReturns();
}
catch (AMQException e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java b/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java
index 0abb3cdd7d..fb18519fe1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/UnexpectedMethodException.java
@@ -1,33 +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.
- *
- */
-package org.apache.qpid.server.handler;
-
-
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.AMQException;
-
-public class UnexpectedMethodException extends AMQException
-{
- public UnexpectedMethodException(AMQMethodBody body)
- {
- super("Unexpected method recevied: " + body.getClass().getName());
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.handler;
+
+
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.AMQException;
+
+public class UnexpectedMethodException extends AMQException
+{
+ public UnexpectedMethodException(AMQMethodBody body)
+ {
+ super("Unexpected method recevied: " + body.getClass().getName());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
index 576d577b40..e01c5aabbf 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
@@ -1,57 +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.
- *
- */
-
-/*
- * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
- * Supported AMQP versions:
- * 8-0
- */
-package org.apache.qpid.server.output;
-
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.AMQException;
-
-public interface ProtocolOutputConverter
-{
- void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag);
-
- interface Factory
- {
- ProtocolOutputConverter newInstance(AMQProtocolSession session);
- }
-
- void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException;
-
- void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException;
-
- byte getProtocolMinorVersion();
-
- byte getProtocolMajorVersion();
-
- void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException;
-
- void writeFrame(AMQDataBlock block);
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
+ * Supported AMQP versions:
+ * 8-0
+ */
+package org.apache.qpid.server.output;
+
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.AMQException;
+
+public interface ProtocolOutputConverter
+{
+ void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag);
+
+ interface Factory
+ {
+ ProtocolOutputConverter newInstance(AMQProtocolSession session);
+ }
+
+ void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ throws AMQException;
+
+ void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException;
+
+ byte getProtocolMinorVersion();
+
+ byte getProtocolMajorVersion();
+
+ void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ throws AMQException;
+
+ void writeFrame(AMQDataBlock block);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
index 02fb1429c0..36e7e88fd6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
@@ -1,61 +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.
- *
- */
-
-/*
- * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
- * Supported AMQP versions:
- * 8-0
- */
-package org.apache.qpid.server.output;
-
-import org.apache.qpid.server.output.ProtocolOutputConverter.Factory;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.framing.ProtocolVersion;
-
-import java.util.Map;
-import java.util.HashMap;
-
-public class ProtocolOutputConverterRegistry
-{
-
- private static final Map<ProtocolVersion, Factory> _registry =
- new HashMap<ProtocolVersion, Factory>();
-
-
- static
- {
- register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory());
- register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory());
-
- }
-
- private static void register(ProtocolVersion version, Factory converter)
- {
-
- _registry.put(version,converter);
- }
-
-
- public static ProtocolOutputConverter getConverter(AMQProtocolSession session)
- {
- return _registry.get(session.getProtocolVersion()).newInstance(session);
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
+ * Supported AMQP versions:
+ * 8-0
+ */
+package org.apache.qpid.server.output;
+
+import org.apache.qpid.server.output.ProtocolOutputConverter.Factory;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.framing.ProtocolVersion;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class ProtocolOutputConverterRegistry
+{
+
+ private static final Map<ProtocolVersion, Factory> _registry =
+ new HashMap<ProtocolVersion, Factory>();
+
+
+ static
+ {
+ register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory());
+ register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory());
+
+ }
+
+ private static void register(ProtocolVersion version, Factory converter)
+ {
+
+ _registry.put(version,converter);
+ }
+
+
+ public static ProtocolOutputConverter getConverter(AMQProtocolSession session)
+ {
+ return _registry.get(session.getProtocolVersion()).newInstance(session);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
index d4cb7c878f..2b55d294b5 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
@@ -1,285 +1,284 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/*
- * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
- * Supported AMQP versions:
- * 8-0
- */
-package org.apache.qpid.server.output.amqp0_8;
-
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.AMQException;
-
-import org.apache.mina.common.ByteBuffer;
-
-import java.util.Iterator;
-
-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
-{
-
-
- public static Factory getInstanceFactory()
- {
- return new Factory()
- {
-
- public ProtocolOutputConverter newInstance(AMQProtocolSession session)
- {
- return new ProtocolOutputConverterImpl(session);
- }
- };
- }
-
- private final AMQProtocolSession _protocolSession;
-
- private ProtocolOutputConverterImpl(AMQProtocolSession session)
- {
- _protocolSession = session;
- }
-
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
- final Long messageId = message.getMessageId();
-
- final int bodyCount = messageHandle.getBodyCount(storeContext,messageId);
-
- if(bodyCount == 0)
- {
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
-
- writeFrame(compositeBlock);
- }
- else
- {
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext,messageId, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
- }
-
-
- }
-
-
- }
-
-
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
- {
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
- final long messageId = message.getMessageId();
-
- AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
-
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
-
- final int bodyCount = messageHandle.getBodyCount(storeContext,messageId);
- if(bodyCount == 0)
- {
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
- writeFrame(compositeBlock);
- }
- else
- {
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, messageId, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
- }
-
-
- }
-
-
- }
-
-
- private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicDeliverBody deliverBody =
- methodRegistry.createBasicDeliverBody(consumerTag,
- deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey());
- AMQFrame deliverFrame = deliverBody.generateFrame(channelId);
-
-
- return deliverFrame;
- }
-
- private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
- throws AMQException
- {
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicGetOkBody getOkBody =
- methodRegistry.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
- queueSize);
- AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
-
- return getOkFrame;
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolSession().getProtocolMinorVersion();
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolSession().getProtocolMajorVersion();
- }
-
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
- {
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicReturnBody basicReturnBody =
- methodRegistry.createBasicReturnBody(replyCode,
- replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
- AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
-
- return returnFrame;
- }
-
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException
- {
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
-
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
-
- writeFrame(compositeBlock);
- }
-
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
- }
-
-
- public void writeFrame(AMQDataBlock block)
- {
- getProtocolSession().writeFrame(block);
- }
-
-
- public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
- {
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag);
- writeFrame(basicCancelOkBody.generateFrame(channelId));
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
+ * Supported AMQP versions:
+ * 8-0
+ */
+package org.apache.qpid.server.output.amqp0_8;
+
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.AMQMessageHandle;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+
+import org.apache.mina.common.ByteBuffer;
+
+import java.util.Iterator;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+
+
+ public static Factory getInstanceFactory()
+ {
+ return new Factory()
+ {
+
+ public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+ {
+ return new ProtocolOutputConverterImpl(session);
+ }
+ };
+ }
+
+ private final AMQProtocolSession _protocolSession;
+
+ private ProtocolOutputConverterImpl(AMQProtocolSession session)
+ {
+ _protocolSession = session;
+ }
+
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _protocolSession;
+ }
+
+ public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ throws AMQException
+ {
+ AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+ message.getContentHeaderBody());
+
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final StoreContext storeContext = message.getStoreContext();
+
+
+ final int bodyCount = messageHandle.getBodyCount(storeContext);
+
+ if(bodyCount == 0)
+ {
+ SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
+ contentHeader);
+
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+
+
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+
+ AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
+ AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
+ writeFrame(compositeBlock);
+
+ //
+ // Now start writing out the other content bodies
+ //
+ for(int i = 1; i < bodyCount; i++)
+ {
+ cb = messageHandle.getContentChunk(storeContext, i);
+ writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
+ }
+
+
+ }
+
+
+ }
+
+
+ public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ {
+
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final StoreContext storeContext = message.getStoreContext();
+
+ AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+
+
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+ message.getContentHeaderBody());
+
+ final int bodyCount = messageHandle.getBodyCount(storeContext);
+ if(bodyCount == 0)
+ {
+ SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
+ contentHeader);
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+
+
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+
+ AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
+ AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
+ writeFrame(compositeBlock);
+
+ //
+ // Now start writing out the other content bodies
+ //
+ for(int i = 1; i < bodyCount; i++)
+ {
+ cb = messageHandle.getContentChunk(storeContext, i);
+ writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
+ }
+
+
+ }
+
+
+ }
+
+
+ private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ throws AMQException
+ {
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+
+ MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+ BasicDeliverBody deliverBody =
+ methodRegistry.createBasicDeliverBody(consumerTag,
+ deliveryTag,
+ messageHandle.isRedelivered(),
+ pb.getExchange(),
+ pb.getRoutingKey());
+ AMQFrame deliverFrame = deliverBody.generateFrame(channelId);
+
+
+ return deliverFrame;
+ }
+
+ private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ throws AMQException
+ {
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+
+ MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+ BasicGetOkBody getOkBody =
+ methodRegistry.createBasicGetOkBody(deliveryTag,
+ messageHandle.isRedelivered(),
+ pb.getExchange(),
+ pb.getRoutingKey(),
+ queueSize);
+ AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
+
+ return getOkFrame;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return getProtocolSession().getProtocolMinorVersion();
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return getProtocolSession().getProtocolMajorVersion();
+ }
+
+ private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ {
+ MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+ BasicReturnBody basicReturnBody =
+ methodRegistry.createBasicReturnBody(replyCode,
+ replyText,
+ message.getMessagePublishInfo().getExchange(),
+ message.getMessagePublishInfo().getRoutingKey());
+ AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
+
+ return returnFrame;
+ }
+
+ public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ throws AMQException
+ {
+ AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
+
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+ message.getContentHeaderBody());
+
+ Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ if (bodyFrameIterator.hasNext())
+ {
+ AMQDataBlock firstContentBody = bodyFrameIterator.next();
+ AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
+
+ writeFrame(compositeBlock);
+ }
+
+ //
+ // Now start writing out the other content bodies
+ // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
+ //
+ while (bodyFrameIterator.hasNext())
+ {
+ writeFrame(bodyFrameIterator.next());
+ }
+ }
+
+
+ public void writeFrame(AMQDataBlock block)
+ {
+ getProtocolSession().writeFrame(block);
+ }
+
+
+ public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+ {
+ MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+ BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag);
+ writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
index f87d3bcae1..c76c262edd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
@@ -1,397 +1,370 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.output.amqp0_9;
-
-import org.apache.mina.common.ByteBuffer;
-
-import java.util.Iterator;
-
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
-
-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
-{
- private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
- private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
-
-
- public static Factory getInstanceFactory()
- {
- return new Factory()
- {
-
- public ProtocolOutputConverter newInstance(AMQProtocolSession session)
- {
- return new ProtocolOutputConverterImpl(session);
- }
- };
- }
-
- private final AMQProtocolSession _protocolSession;
-
- private ProtocolOutputConverterImpl(AMQProtocolSession session)
- {
- _protocolSession = session;
- }
-
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody();
-
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
- final Long messageId = message.getMessageId();
-
- final int bodyCount = messageHandle.getBodyCount(storeContext,messageId);
-
- if(bodyCount == 0)
- {
- SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
- contentHeaderBody);
-
- writeFrame(compositeBlock);
- }
- else
- {
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0);
-
- AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb);
-
- CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext,messageId, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
-
- }
-
-
- }
-
- private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
- {
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- contentHeaderBody);
- return contentHeader;
- }
-
-
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
- {
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
- final long messageId = message.getMessageId();
-
- AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
-
-
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
-
- final int bodyCount = messageHandle.getBodyCount(storeContext,messageId);
- if(bodyCount == 0)
- {
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
- writeFrame(compositeBlock);
- }
- else
- {
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext,messageId, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, messageId, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
-
- }
-
-
- }
-
-
- private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag)
- throws AMQException
- {
-
-
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
-
- final AMQBody returnBlock = new AMQBody()
- {
-
-
-
- private final boolean _isRedelivered = messageHandle.isRedelivered();
- private final AMQShortString _exchangeName = pb.getExchange();
- private final AMQShortString _routingKey = pb.getRoutingKey();
-
-
- public AMQBody _underlyingBody;
-
- public AMQBody createAMQBody()
- {
- return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
- deliveryTag,
- _isRedelivered,
- _exchangeName,
- _routingKey);
-
-
-
-
-
- }
-
- public byte getFrameType()
- {
- return AMQMethodBody.TYPE;
- }
-
- public int getSize()
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- return _underlyingBody.getSize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- _underlyingBody.writePayload(buffer);
- }
-
- public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
- throws AMQException
- {
- throw new AMQException("This block should never be dispatched!");
- }
- };
- return returnBlock;
- }
-
- private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
- throws AMQException
- {
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
-
- BasicGetOkBody getOkBody =
- METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
- queueSize);
- AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
-
- return getOkFrame;
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolSession().getProtocolMinorVersion();
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolSession().getProtocolMajorVersion();
- }
-
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
- {
-
- BasicReturnBody basicReturnBody =
- METHOD_REGISTRY.createBasicReturnBody(replyCode,
- replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
- AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
-
- return returnFrame;
- }
-
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException
- {
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
-
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
-
- writeFrame(compositeBlock);
- }
-
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
- }
-
-
- public void writeFrame(AMQDataBlock block)
- {
- getProtocolSession().writeFrame(block);
- }
-
-
- public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
- {
-
- BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
- writeFrame(basicCancelOkBody.generateFrame(channelId));
-
- }
-
-
- public static final class CompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final AMQBody _contentBody;
- private final int _channel;
-
-
- public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
- _contentBody = contentBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
- }
- }
-
- public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final int _channel;
-
-
- public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
- }
- }
-
-}
+package org.apache.qpid.server.output.amqp0_9;
+
+import org.apache.mina.common.ByteBuffer;
+
+import java.util.Iterator;
+
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.AMQMessageHandle;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+ private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
+ private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
+
+
+ public static Factory getInstanceFactory()
+ {
+ return new Factory()
+ {
+
+ public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+ {
+ return new ProtocolOutputConverterImpl(session);
+ }
+ };
+ }
+
+ private final AMQProtocolSession _protocolSession;
+
+ private ProtocolOutputConverterImpl(AMQProtocolSession session)
+ {
+ _protocolSession = session;
+ }
+
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _protocolSession;
+ }
+
+ public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ throws AMQException
+ {
+ AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
+ final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody();
+
+
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final StoreContext storeContext = message.getStoreContext();
+
+
+ final int bodyCount = messageHandle.getBodyCount(storeContext);
+
+ if(bodyCount == 0)
+ {
+ SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
+ contentHeaderBody);
+
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+
+
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+
+ AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb);
+
+ CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+ writeFrame(compositeBlock);
+
+ //
+ // Now start writing out the other content bodies
+ //
+ for(int i = 1; i < bodyCount; i++)
+ {
+ cb = messageHandle.getContentChunk(storeContext, i);
+ writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
+ }
+
+
+ }
+
+ }
+
+ private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
+ {
+
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+ contentHeaderBody);
+ return contentHeader;
+ }
+
+
+ public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ {
+
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final StoreContext storeContext = message.getStoreContext();
+
+ AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+
+
+ AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
+
+ final int bodyCount = messageHandle.getBodyCount(storeContext);
+ if(bodyCount == 0)
+ {
+ SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
+ contentHeader);
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+
+
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+
+ AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb));
+ AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
+ writeFrame(compositeBlock);
+
+ //
+ // Now start writing out the other content bodies
+ //
+ for(int i = 1; i < bodyCount; i++)
+ {
+ cb = messageHandle.getContentChunk(storeContext, i);
+ writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
+ }
+
+
+ }
+
+
+ }
+
+
+ private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag)
+ throws AMQException
+ {
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+
+
+ final boolean isRedelivered = messageHandle.isRedelivered();
+ final AMQShortString exchangeName = pb.getExchange();
+ final AMQShortString routingKey = pb.getRoutingKey();
+
+ final AMQBody returnBlock = new AMQBody()
+ {
+
+ public AMQBody _underlyingBody;
+
+ public AMQBody createAMQBody()
+ {
+ return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
+ deliveryTag,
+ isRedelivered,
+ exchangeName,
+ routingKey);
+
+
+
+
+
+ }
+
+ public byte getFrameType()
+ {
+ return AMQMethodBody.TYPE;
+ }
+
+ public int getSize()
+ {
+ if(_underlyingBody == null)
+ {
+ _underlyingBody = createAMQBody();
+ }
+ return _underlyingBody.getSize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ if(_underlyingBody == null)
+ {
+ _underlyingBody = createAMQBody();
+ }
+ _underlyingBody.writePayload(buffer);
+ }
+
+ public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
+ throws AMQException
+ {
+ throw new AMQException("This block should never be dispatched!");
+ }
+ };
+ return returnBlock;
+ }
+
+ private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ throws AMQException
+ {
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ final AMQMessageHandle messageHandle = message.getMessageHandle();
+
+
+ BasicGetOkBody getOkBody =
+ METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+ messageHandle.isRedelivered(),
+ pb.getExchange(),
+ pb.getRoutingKey(),
+ queueSize);
+ AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
+
+ return getOkFrame;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return getProtocolSession().getProtocolMinorVersion();
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return getProtocolSession().getProtocolMajorVersion();
+ }
+
+ private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ {
+
+ BasicReturnBody basicReturnBody =
+ METHOD_REGISTRY.createBasicReturnBody(replyCode,
+ replyText,
+ message.getMessagePublishInfo().getExchange(),
+ message.getMessagePublishInfo().getRoutingKey());
+ AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
+
+ return returnFrame;
+ }
+
+ public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ throws AMQException
+ {
+ AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
+
+ AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
+
+ Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
+ //
+ // Optimise the case where we have a single content body. In that case we create a composite block
+ // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
+ //
+ if (bodyFrameIterator.hasNext())
+ {
+ AMQDataBlock firstContentBody = bodyFrameIterator.next();
+ AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+ CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
+
+ writeFrame(compositeBlock);
+ }
+
+ //
+ // Now start writing out the other content bodies
+ // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
+ //
+ while (bodyFrameIterator.hasNext())
+ {
+ writeFrame(bodyFrameIterator.next());
+ }
+ }
+
+
+ public void writeFrame(AMQDataBlock block)
+ {
+ getProtocolSession().writeFrame(block);
+ }
+
+
+ public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+ {
+
+ BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
+ writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+ }
+
+
+ public static final class CompositeAMQBodyBlock extends AMQDataBlock
+ {
+ public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
+
+ private final AMQBody _methodBody;
+ private final AMQBody _headerBody;
+ private final AMQBody _contentBody;
+ private final int _channel;
+
+
+ public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
+ {
+ _channel = channel;
+ _methodBody = methodBody;
+ _headerBody = headerBody;
+ _contentBody = contentBody;
+
+ }
+
+ public long getSize()
+ {
+ return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
+ }
+ }
+
+ public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
+ {
+ public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
+
+ private final AMQBody _methodBody;
+ private final AMQBody _headerBody;
+ private final int _channel;
+
+
+ public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
+ {
+ _channel = channel;
+ _methodBody = methodBody;
+ _headerBody = headerBody;
+
+ }
+
+ public long getSize()
+ {
+ return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
+ }
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java
index 4267642b14..bdb16d0fcb 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java
@@ -113,6 +113,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
private ProtocolOutputConverter _protocolOutputConverter;
private Principal _authorizedID;
private MethodDispatcher _dispatcher;
+ private ProtocolSessionIdentifier _sessionIdentifier;
public ManagedObject getManagedObject()
{
@@ -198,7 +199,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
}
private void frameReceived(AMQFrame frame) throws AMQException
- {
+ {
int channelId = frame.getChannel();
AMQBody body = frame.getBodyFrame();
@@ -373,7 +374,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
AMQChannel channel = getAndAssertChannel(channelId);
- channel.publishContentHeader(body, this);
+ channel.publishContentHeader(body);
}
@@ -381,7 +382,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
{
AMQChannel channel = getAndAssertChannel(channelId);
- channel.publishContentBody(body, this);
+ channel.publishContentBody(body);
}
public void heartbeatBodyReceived(int channelId, HeartbeatBody body)
@@ -443,7 +444,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
public boolean channelAwaitingClosure(int channelId)
{
- return _closingChannelsList.contains(channelId);
+ return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId);
}
public void addChannel(AMQChannel channel) throws AMQException
@@ -536,7 +537,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
{
try
{
- channel.close(this);
+ channel.close();
markChannelAwaitingCloseOk(channelId);
}
finally
@@ -602,7 +603,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
{
for (AMQChannel channel : _channelMap.values())
{
- channel.close(this);
+ channel.close();
}
_channelMap.clear();
@@ -633,7 +634,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
public String toString()
{
- return "AMQProtocolSession(" + _minaProtocolSession.getRemoteAddress() + ")";
+ return _minaProtocolSession.getRemoteAddress() + "("+(getAuthorizedID() == null ? "?" : getAuthorizedID().getName()+")");
}
public String dump()
@@ -702,6 +703,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
_clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString()));
}
}
+ _sessionIdentifier = new ProtocolSessionIdentifier(this);
}
private void setProtocolVersion(ProtocolVersion pv)
@@ -739,7 +741,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
public Object getClientIdentifier()
{
- return _minaProtocolSession.getRemoteAddress();
+ return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null;
}
public VirtualHost getVirtualHost()
@@ -789,6 +791,11 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
return _dispatcher;
}
+ public ProtocolSessionIdentifier getSessionIdentifier()
+ {
+ return _sessionIdentifier;
+ }
+
public String getClientVersion()
{
return (_clientVersion == null) ? null : _clientVersion.toString();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java
index 92f951ce39..a7599a3e0d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQNoMethodHandlerException.java
@@ -1,46 +1,46 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.protocol;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.protocol.AMQMethodEvent;
-
-/**
- * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represents failure to handle an AMQP method.
- * </table>
- *
- * @todo Not an AMQP exception as no status code.
- *
- * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a
- * Runtime.
- */
-public class AMQNoMethodHandlerException extends AMQException
-{
- public AMQNoMethodHandlerException(AMQMethodEvent<AMQMethodBody> evt)
- {
- super("AMQMethodEvent " + evt + " was not processed by any listener on Broker.");
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.protocol;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+/**
+ * AMQNoMethodHandlerException represents the case where no method handler exists to handle an AQMP method.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represents failure to handle an AMQP method.
+ * </table>
+ *
+ * @todo Not an AMQP exception as no status code.
+ *
+ * @todo Missing method handler. Unlikely to ever happen, and if it does its a coding error. Consider replacing with a
+ * Runtime.
+ */
+public class AMQNoMethodHandlerException extends AMQException
+{
+ public AMQNoMethodHandlerException(AMQMethodEvent<AMQMethodBody> evt)
+ {
+ super("AMQMethodEvent " + evt + " was not processed by any listener on Broker.");
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java
index ad1c507c04..d8dbf97e49 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java
@@ -265,6 +265,10 @@ public class AMQPFastProtocolHandler extends IoHandlerAdapter
*/
public void messageSent(IoSession protocolSession, Object object) throws Exception
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Message sent: " + object);
+ }
}
protected boolean isSSLClient(ConnectorConfiguration connectionConfig,
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
index c9316f7405..c3400029da 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.protocol;
import javax.security.sasl.SaslServer;
import org.apache.qpid.AMQException;
+import org.apache.qpid.common.ClientProperties;
import org.apache.qpid.framing.*;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.server.AMQChannel;
@@ -35,7 +36,27 @@ import java.security.Principal;
public interface AMQProtocolSession extends AMQVersionAwareProtocolSession
{
-
+ public static final class ProtocolSessionIdentifier
+ {
+ private final Object _sessionIdentifier;
+ private final Object _sessionInstance;
+
+ ProtocolSessionIdentifier(AMQProtocolSession session)
+ {
+ _sessionIdentifier = session.getClientIdentifier();
+ _sessionInstance = session.getClientProperties() == null ? null : session.getClientProperties().getObject(ClientProperties.instance.toAMQShortString());
+ }
+
+ public Object getSessionIdentifier()
+ {
+ return _sessionIdentifier;
+ }
+
+ public Object getSessionInstance()
+ {
+ return _sessionInstance;
+ }
+ }
public static interface Task
{
@@ -175,5 +196,7 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession
public MethodRegistry getMethodRegistry();
public MethodDispatcher getMethodDispatcher();
+
+ public ProtocolSessionIdentifier getSessionIdentifier();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java
index bb2db8d506..6e72aa062f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/UnknnownMessageTypeException.java
@@ -1,46 +1,46 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.protocol;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQDataBlock;
-
-/**
- * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represents failure to cast a frame to its expected type.
- * </table>
- *
- * @todo Not an AMQP exception as no status code.
- *
- * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would
- * be better just to leave that as a ClassCastException. However, check the framing layer catches this error
- * first.
- */
-public class UnknnownMessageTypeException extends AMQException
-{
- public UnknnownMessageTypeException(AMQDataBlock message)
- {
- super("Unknown message type: " + message.getClass().getName() + ": " + message);
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.protocol;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQDataBlock;
+
+/**
+ * UnknnownMessageTypeException represents a failure when Mina passes an unexpected frame type.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represents failure to cast a frame to its expected type.
+ * </table>
+ *
+ * @todo Not an AMQP exception as no status code.
+ *
+ * @todo Seems like this exception was created to handle an unsafe type cast that will never happen in practice. Would
+ * be better just to leave that as a ClassCastException. However, check the framing layer catches this error
+ * first.
+ */
+public class UnknnownMessageTypeException extends AMQException
+{
+ public UnknnownMessageTypeException(AMQDataBlock message)
+ {
+ super("Unknown message type: " + message.getClass().getName() + ": " + message);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
index a76b13ce74..0e5e7aa68c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
@@ -25,131 +25,55 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQBody;
import org.apache.qpid.framing.AMQDataBlock;
import org.apache.qpid.framing.AMQFrame;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.exchange.Exchange;
-import java.util.HashMap;
-import java.util.HashSet;
+
import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A deliverable message.
*/
-public class AMQMessage
+public class AMQMessage implements Filterable<AMQException>
{
/** Used for debugging purposes. */
private static final Logger _log = Logger.getLogger(AMQMessage.class);
- /** Used in clustering. @todo What for? */
- private Set<Object> _tokens;
-
- /** Only use in clustering. @todo What for? */
- private AMQProtocolSession _publisher;
-
- private final Long _messageId;
-
private final AtomicInteger _referenceCount = new AtomicInteger(1);
- private AMQMessageHandle _messageHandle;
+ private final AMQMessageHandle _messageHandle;
/** Holds the transactional context in which this message is being processed. */
- private TransactionalContext _txnContext;
+ private StoreContext _storeContext;
+
+ /** Flag to indicate that this message requires 'immediate' delivery. */
+
+ private static final byte IMMEDIATE = 0x01;
/**
* Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality
* for messages published with the 'immediate' flag.
*/
- private boolean _deliveredToConsumer;
- /** Flag to indicate that this message requires 'immediate' delivery. */
- private boolean _immediate;
+ private static final byte DELIVERED_TO_CONSUMER = 0x02;
- private TransientMessageData _transientMessageData = new TransientMessageData();
+ private byte _flags = 0;
private long _expiration;
+ private final long _size;
+ private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier;
+ private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER);
- private Exchange _exchange;
- private static final boolean SYNCED_CLOCKS =
- ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false);
-
- private static final long UNKNOWN_SIZE = Long.MIN_VALUE;
-
- private long _size = UNKNOWN_SIZE;
-
-
-
- public String debugIdentity()
- {
- return "(HC:" + System.identityHashCode(this) + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")";
- }
-
- public void setExpiration()
- {
- long expiration =
- ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getExpiration();
- long timestamp =
- ((BasicContentHeaderProperties) _transientMessageData.getContentHeaderBody().properties).getTimestamp();
-
- if (SYNCED_CLOCKS)
- {
- _expiration = expiration;
- }
- else
- {
- // Update TTL to be in broker time.
- if (expiration != 0L)
- {
- if (timestamp != 0L)
- {
- // todo perhaps use arrival time
- long diff = (System.currentTimeMillis() - timestamp);
-
- if ((diff > 1000L) || (diff < 1000L))
- {
- _expiration = expiration + diff;
- }
- }
- }
- }
-
- }
-
- public boolean isReferenced()
- {
- return _referenceCount.get() > 0;
- }
-
- public void setExchange(final Exchange exchange)
- {
- _exchange = exchange;
- }
-
- public void route() throws AMQException
- {
- _exchange.route(this);
- }
-
- public void enqueue(final List<AMQQueue> queues)
- {
- _transientMessageData.setDestinationQueues(queues);
- }
/**
* Used to iterate through all the body frames associated with this message. Will not keep all the data in memory
@@ -172,7 +96,7 @@ public class AMQMessage
{
try
{
- return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1);
+ return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1);
}
catch (AMQException e)
{
@@ -189,7 +113,7 @@ public class AMQMessage
AMQBody cb =
getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(),
- _messageId, ++_index));
+ ++_index));
return new AMQFrame(_channel, cb);
}
@@ -212,9 +136,14 @@ public class AMQMessage
}
}
+ public void clearStoreContext()
+ {
+ _storeContext = new StoreContext();
+ }
+
public StoreContext getStoreContext()
{
- return _txnContext.getStoreContext();
+ return _storeContext;
}
private class BodyContentIterator implements Iterator<ContentChunk>
@@ -226,7 +155,7 @@ public class AMQMessage
{
try
{
- return _index < (_messageHandle.getBodyCount(getStoreContext(), _messageId) - 1);
+ return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1);
}
catch (AMQException e)
{
@@ -240,7 +169,7 @@ public class AMQMessage
{
try
{
- return _messageHandle.getContentChunk(getStoreContext(), _messageId, ++_index);
+ return _messageHandle.getContentChunk(getStoreContext(), ++_index);
}
catch (AMQException e)
{
@@ -254,13 +183,7 @@ public class AMQMessage
}
}
- public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext)
- {
- _messageId = messageId;
- _txnContext = txnContext;
- _immediate = info.isImmediate();
- _transientMessageData.setMessagePublishInfo(info);
- }
+
/**
* Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal
@@ -276,141 +199,85 @@ public class AMQMessage
public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext)
throws AMQException
{
- _messageId = messageId;
_messageHandle = factory.createMessageHandle(messageId, store, true);
- _txnContext = txnConext;
- _transientMessageData = null;
-
+ _storeContext = txnConext.getStoreContext();
+ _size = _messageHandle.getBodySize(txnConext.getStoreContext());
}
- /**
- * Used in testing only. This allows the passing of the content header immediately on construction.
+ /**
+ * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal
+ * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to
+ * queues.
*
- * @param messageId
- * @param info
- * @param txnContext
- * @param contentHeader
+ * @param messageHandle
+ *
+ * @throws AMQException
*/
- public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext,
- ContentHeaderBody contentHeader) throws AMQException
+ public AMQMessage(
+ AMQMessageHandle messageHandle,
+ StoreContext storeConext,
+ MessagePublishInfo info)
+ throws AMQException
{
- this(messageId, info, txnContext);
- setContentHeaderBody(contentHeader);
- }
+ _messageHandle = messageHandle;
+ _storeContext = storeConext;
- /* *
- * Used in testing only. This allows the passing of the content header and some body fragments on construction.
- *
- * @param messageId
- * @param info
- * @param txnContext
- * @param contentHeader
- * @param destinationQueues
- * @param contentBodies
- *
- * @throws AMQException
- */ /*
- public AMQMessage(Long messageId, MessagePublishInfo info, TransactionalContext txnContext,
- ContentHeaderBody contentHeader, List<AMQQueue> destinationQueues, List<ContentChunk> contentBodies,
- MessageStore messageStore, StoreContext storeContext, MessageHandleFactory messageHandleFactory) throws AMQException
- {
- this(messageId, info, txnContext, contentHeader);
- _transientMessageData.setDestinationQueues(destinationQueues);
- routingComplete(messageStore, storeContext, messageHandleFactory);
- for (ContentChunk cb : contentBodies)
+ if(info.isImmediate())
{
- addContentBodyFrame(storeContext, cb);
+ _flags |= IMMEDIATE;
}
+ _size = messageHandle.getBodySize(storeConext);
+
}
- */
+
+
protected AMQMessage(AMQMessage msg) throws AMQException
{
- _messageId = msg._messageId;
_messageHandle = msg._messageHandle;
- _txnContext = msg._txnContext;
- _deliveredToConsumer = msg._deliveredToConsumer;
- _transientMessageData = msg._transientMessageData;
- }
+ _storeContext = msg._storeContext;
+ _flags = msg._flags;
+ _size = msg._size;
- public Iterator<AMQDataBlock> getBodyFrameIterator(AMQProtocolSession protocolSession, int channel)
- {
- return new BodyFrameIterator(protocolSession, channel);
}
- public Iterator<ContentChunk> getContentBodyIterator()
+
+ public String debugIdentity()
{
- return new BodyContentIterator();
+ return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")";
}
- public ContentHeaderBody getContentHeaderBody() throws AMQException
+ public void setExpiration(final long expiration)
{
- if (_transientMessageData != null)
- {
- return _transientMessageData.getContentHeaderBody();
- }
- else
- {
- return _messageHandle.getContentHeaderBody(getStoreContext(), _messageId);
- }
+
+ _expiration = expiration;
+
}
- public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException
+ public boolean isReferenced()
{
- _transientMessageData.setContentHeaderBody(contentHeaderBody);
- _size = _transientMessageData.getContentHeaderBody().bodySize;
+ return _referenceCount.get() > 0;
}
- public void routingComplete(MessageStore store, StoreContext storeContext, MessageHandleFactory factory)
- throws AMQException
+ public Iterator<AMQDataBlock> getBodyFrameIterator(AMQProtocolSession protocolSession, int channel)
{
- final boolean persistent = isPersistent();
- _messageHandle = factory.createMessageHandle(_messageId, store, persistent);
- if (persistent)
- {
- _txnContext.beginTranIfNecessary();
- }
-
- // enqueuing the messages ensure that if required the destinations are recorded to a
- // persistent store
-
- for (AMQQueue q : _transientMessageData.getDestinationQueues())
- {
- _messageHandle.enqueue(storeContext, _messageId, q);
- }
-
- if (_transientMessageData.getContentHeaderBody().bodySize == 0)
- {
- deliver(storeContext);
- }
-
-
+ return new BodyFrameIterator(protocolSession, channel);
}
- public boolean addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk) throws AMQException
+ public Iterator<ContentChunk> getContentBodyIterator()
{
- _transientMessageData.addBodyLength(contentChunk.getSize());
- final boolean allContentReceived = isAllContentReceived();
- _messageHandle.addContentBodyFrame(storeContext, _messageId, contentChunk, allContentReceived);
- if (allContentReceived)
- {
- deliver(storeContext);
-
- return true;
- }
- else
- {
- return false;
- }
+ return new BodyContentIterator();
}
- public boolean isAllContentReceived() throws AMQException
+ public ContentHeaderBody getContentHeaderBody() throws AMQException
{
- return _transientMessageData.isAllContentReceived();
+ return _messageHandle.getContentHeaderBody(getStoreContext());
}
+
+
public Long getMessageId()
{
- return _messageId;
+ return _messageHandle.getMessageId();
}
/**
@@ -425,13 +292,18 @@ public class AMQMessage
}
/** Threadsafe. Increment the reference count on the message. */
- public void incrementReference()
+ public boolean incrementReference()
{
- _referenceCount.incrementAndGet();
- // if (_log.isDebugEnabled())
- // {
- // _log.debug("Ref count on message " + debugIdentity() + " incremented " + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6));
- // }
+ if(_referenceCount.incrementAndGet() <= 1)
+ {
+ _referenceCount.decrementAndGet();
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+
}
/**
@@ -445,6 +317,7 @@ public class AMQMessage
*/
public void decrementReference(StoreContext storeContext) throws MessageCleanupException
{
+
int count = _referenceCount.decrementAndGet();
// note that the operation of decrementing the reference count and then removing the message does not
@@ -453,25 +326,25 @@ public class AMQMessage
// not relying on the all the increments having taken place before the delivery manager decrements.
if (count == 0)
{
+ // set the reference count way below 0 so that we can detect that the message has been deleted
+ // this is to guard against the message being spontaneously recreated (from the mgmt console)
+ // by copying from other queues at the same time as it is being removed.
+ _referenceCount.set(Integer.MIN_VALUE/2);
+
try
{
- // if (_log.isDebugEnabled())
- // {
- // _log.debug("Decremented ref count on message " + debugIdentity() + " is zero; removing message" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6));
- // }
-
// must check if the handle is null since there may be cases where we decide to throw away a message
// and the handle has not yet been constructed
if (_messageHandle != null)
{
- _messageHandle.removeMessage(storeContext, _messageId);
+ _messageHandle.removeMessage(storeContext);
}
}
catch (AMQException e)
{
// to maintain consistency, we revert the count
incrementReference();
- throw new MessageCleanupException(_messageId, e);
+ throw new MessageCleanupException(getMessageId(), e);
}
}
else
@@ -484,15 +357,6 @@ public class AMQMessage
}
}
- public void setPublisher(AMQProtocolSession publisher)
- {
- _publisher = publisher;
- }
-
- public AMQProtocolSession getPublisher()
- {
- return _publisher;
- }
/**
* Called selectors to determin if the message has already been sent
@@ -501,101 +365,30 @@ public class AMQMessage
*/
public boolean getDeliveredToConsumer()
{
- return _deliveredToConsumer;
- }
-
-
- public boolean checkToken(Object token)
- {
-
- if (_tokens == null)
- {
- _tokens = new HashSet<Object>();
- }
-
- if (_tokens.contains(token))
- {
- return true;
- }
- else
- {
- _tokens.add(token);
-
- return false;
- }
- }
-
- /**
- * Registers a queue to which this message is to be delivered. This is called from the exchange when it is routing
- * the message. This will be called before any content bodies have been received so that the choice of
- * AMQMessageHandle implementation can be picked based on various criteria.
- *
- * @param queue the queue
- *
- * @throws org.apache.qpid.AMQException if there is an error enqueuing the message
- */
- public void enqueue(AMQQueue queue) throws AMQException
- {
- _transientMessageData.addDestinationQueue(queue);
- }
-
- /**
- * NOTE: Think about why you are using this method. Normal usages would want to do
- * AMQQueue.dequeue(StoreContext, AMQMessage)
- * This will keep the queue statistics up-to-date.
- * Currently this method is only called _correctly_ from AMQQueue dequeue.
- * Ideally we would have a better way for the queue to dequeue the message.
- * Especially since enqueue isn't the recipriocal of this method.
- * @deprecated
- * @param storeContext
- * @param queue
- * @throws AMQException
- */
- void dequeue(StoreContext storeContext, AMQQueue queue) throws AMQException
- {
- _messageHandle.dequeue(storeContext, _messageId, queue);
+ return (_flags & DELIVERED_TO_CONSUMER) != 0;
}
public boolean isPersistent() throws AMQException
{
- if (_transientMessageData != null)
- {
- return _transientMessageData.isPersistent();
- }
- else
- {
- return _messageHandle.isPersistent(getStoreContext(), _messageId);
- }
+ return _messageHandle.isPersistent();
}
/**
* Called to enforce the 'immediate' flag.
*
- * @throws NoConsumersException if the message is marked for immediate delivery but has not been marked as delivered
+ * @returns true if the message is marked for immediate delivery but has not been marked as delivered
* to a consumer
*/
- public void checkDeliveredToConsumer() throws NoConsumersException
+ public boolean immediateAndNotDelivered()
{
- if (_immediate && !_deliveredToConsumer)
- {
- throw new NoConsumersException(this);
- }
+ return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE;
+
}
public MessagePublishInfo getMessagePublishInfo() throws AMQException
{
- MessagePublishInfo pb;
- if (_transientMessageData != null)
- {
- pb = _transientMessageData.getMessagePublishInfo();
- }
- else
- {
- pb = _messageHandle.getMessagePublishInfo(getStoreContext(), _messageId);
- }
-
- return pb;
+ return _messageHandle.getMessagePublishInfo(getStoreContext());
}
public boolean isRedelivered()
@@ -641,46 +434,9 @@ public class AMQMessage
*/
public void setDeliveredToConsumer()
{
- _deliveredToConsumer = true;
+ _flags |= DELIVERED_TO_CONSUMER;
}
- private void deliver(StoreContext storeContext) throws AMQException
- {
- // we get a reference to the destination queues now so that we can clear the
- // transient message data as quickly as possible
- List<AMQQueue> destinationQueues = _transientMessageData.getDestinationQueues();
- if (_log.isDebugEnabled())
- {
- _log.debug("Delivering message " + debugIdentity() + " to " + destinationQueues);
- }
-
- try
- {
- // first we allow the handle to know that the message has been fully received. This is useful if it is
- // maintaining any calculated values based on content chunks
- _messageHandle.setPublishAndContentHeaderBody(storeContext, _messageId,
- _transientMessageData.getMessagePublishInfo(), _transientMessageData.getContentHeaderBody());
-
- // we then allow the transactional context to do something with the message content
- // now that it has all been received, before we attempt delivery
- _txnContext.messageFullyReceived(isPersistent());
-
- for (AMQQueue q : destinationQueues)
- {
- // Increment the references to this message for each queue delivery.
- incrementReference();
- // normal deliver so add this message at the end.
- _txnContext.deliver(q.createEntry(this), false);
- }
- }
- finally
- {
-
- // Remove refence for routing process . Reference count should now == delivered queue count
- decrementReference(storeContext);
- _transientMessageData = null;
- }
- }
public AMQMessageHandle getMessageHandle()
@@ -690,28 +446,23 @@ public class AMQMessage
public long getSize()
{
- if(_size == UNKNOWN_SIZE)
- {
- try
- {
- _size = getContentHeaderBody().bodySize;
- }
- catch (AMQException e)
- {
- _log.warn("Unable to retrieve message meta data for message:" + this, e);
- return 0;
- }
- }
return _size;
+
+ }
+
+ public Object getPublisherClientInstance()
+ {
+ return _sessionIdentifier.getSessionInstance();
+ }
+
+ public Object getPublisherIdentifier()
+ {
+ return _sessionIdentifier.getSessionIdentifier();
}
- public void restoreTransientMessageData() throws AMQException
+ public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier)
{
- TransientMessageData transientMessageData = new TransientMessageData();
- transientMessageData.setMessagePublishInfo(getMessagePublishInfo());
- transientMessageData.setContentHeaderBody(getContentHeaderBody());
- transientMessageData.addBodyLength(getContentHeaderBody().getSize());
- _transientMessageData = transientMessageData;
+ _sessionIdentifier = sessionIdentifier;
}
@@ -720,7 +471,7 @@ public class AMQMessage
// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " +
// _taken + " by :" + _takenBySubcription;
- return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount;
+ return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
index ede55b3bbf..0ddd4e4d92 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
@@ -29,23 +29,27 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo;
/**
* A pluggable way of getting message data. Implementations can provide intelligent caching for example or
* even no caching at all to minimise the broker memory footprint.
- *
- * The method all take a messageId to avoid having to store it in the instance - the AMQMessage container
- * must already keen the messageId so it is pointless storing it twice.
*/
public interface AMQMessageHandle
{
- ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException;
+ ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException;
+
+ /**
+ *
+ * @return the messageId for the message associated with this handle
+ */
+ Long getMessageId();
+
/**
* @return the number of body frames associated with this message
*/
- int getBodyCount(StoreContext context, Long messageId) throws AMQException;
+ int getBodyCount(StoreContext context) throws AMQException;
/**
* @return the size of the body
*/
- long getBodySize(StoreContext context, Long messageId) throws AMQException;
+ long getBodySize(StoreContext context) throws AMQException;
/**
* Get a particular content body
@@ -53,27 +57,23 @@ public interface AMQMessageHandle
* @return a content body
* @throws IllegalArgumentException if the index is invalid
*/
- ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws IllegalArgumentException, AMQException;
+ ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException;
- void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody) throws AMQException;
+ void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException;
- MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException;
+ MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException;
boolean isRedelivered();
void setRedelivered(boolean redelivered);
- boolean isPersistent(StoreContext context, Long messageId) throws AMQException;
+ boolean isPersistent();
- void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo,
+ void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo,
ContentHeaderBody contentHeaderBody)
throws AMQException;
- void removeMessage(StoreContext storeContext, Long messageId) throws AMQException;
-
- void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException;
-
- void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException;
+ void removeMessage(StoreContext storeContext) throws AMQException;
long getArrivalTime();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
new file mode 100644
index 0000000000..ba6b392d13
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
@@ -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.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.subscription.SubscriptionList;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.AMQException;
+
+public class AMQPriorityQueue extends SimpleAMQQueue
+{
+ protected AMQPriorityQueue(final AMQShortString name,
+ final boolean durable,
+ final AMQShortString owner,
+ final boolean autoDelete,
+ final VirtualHost virtualHost,
+ int priorities)
+ throws AMQException
+ {
+ super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities));
+ }
+
+ @Override
+ protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry)
+ {
+ // check that all subscriptions are not in advance of the entry
+ SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator();
+ while(subIter.advance() && !entry.isAcquired())
+ {
+ final Subscription subscription = subIter.getNode().getSubscription();
+ QueueEntry subnode = subscription.getLastSeenEntry();
+ while((entry.compareTo(subnode) < 0) && !entry.isAcquired())
+ {
+ if(subscription.setLastSeenEntry(subnode,entry))
+ {
+ break;
+ }
+ else
+ {
+ subnode = subscription.getLastSeenEntry();
+ }
+ }
+
+ }
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 7c6db0b4b3..f3e4e7c28b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -20,1005 +20,186 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.management.Managable;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.AMQException;
-import javax.management.JMException;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * This is an AMQ Queue, and should not be confused with a JMS queue or any other abstraction like that. It is described
- * fully in RFC 006.
- */
-public class AMQQueue implements Managable, Comparable
-{
-
- /**
- * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription
- * already exists.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represent failure to create a subscription, because an exclusive subscription already exists.
- * </table>
- *
- * @todo Not an AMQP exception as no status code.
- *
- * @todo Move to top level, used outside this class.
- */
- public static final class ExistingExclusiveSubscription extends AMQException
- {
-
- public ExistingExclusiveSubscription()
- {
- super("");
- }
- }
-
- /**
- * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription
- * already exists.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represent failure to create an exclusize subscription, as a subscription already exists.
- * </table>
- *
- * @todo Not an AMQP exception as no status code.
- *
- * @todo Move to top level, used outside this class.
- */
- public static final class ExistingSubscriptionPreventsExclusive extends AMQException
- {
- public ExistingSubscriptionPreventsExclusive()
- {
- super("");
- }
- }
-
- private static final Logger _logger = Logger.getLogger(AMQQueue.class);
-
- private final AMQShortString _name;
-
- /** null means shared */
- private final AMQShortString _owner;
-
- private final boolean _durable;
-
- /** If true, this queue is deleted when the last subscriber is removed */
- private final boolean _autoDelete;
-
- /** Holds subscribers to the queue. */
- private final SubscriptionSet _subscribers;
-
- private final SubscriptionFactory _subscriptionFactory;
-
- private final AtomicInteger _subscriberCount = new AtomicInteger();
-
- private final AtomicBoolean _isExclusive = new AtomicBoolean();
-
- private final AtomicBoolean _deleted = new AtomicBoolean(false);
-
- private List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>();
-
- /** Manages message delivery. */
- private final DeliveryManager _deliveryMgr;
-
- /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */
- private final ExchangeBindings _bindings = new ExchangeBindings(this);
-
- /** Executor on which asynchronous delivery will be carriedout where required */
- private final Executor _asyncDelivery;
-
- private final AMQQueueMBean _managedObject;
-
- private final VirtualHost _virtualHost;
-
- /** max allowed size(KB) of a single message */
- @Configured(path = "maximumMessageSize", defaultValue = "0")
- public long _maximumMessageSize;
-
- /** max allowed number of messages on a queue. */
- @Configured(path = "maximumMessageCount", defaultValue = "0")
- public long _maximumMessageCount;
-
- /** max queue depth for the queue */
- @Configured(path = "maximumQueueDepth", defaultValue = "0")
- public long _maximumQueueDepth;
-
- /** maximum message age before alerts occur */
- @Configured(path = "maximumMessageAge", defaultValue = "0")
- public long _maximumMessageAge;
-
- /** the minimum interval between sending out consequetive alerts of the same type */
- @Configured(path = "minimumAlertRepeatGap", defaultValue = "0")
- public long _minimumAlertRepeatGap;
-
- /** total messages received by the queue since startup. */
- public AtomicLong _totalMessagesReceived = new AtomicLong();
-
-
- private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class);
-
-
- public AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost)
- throws AMQException
- {
- this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(),
- new SubscriptionSet(), new SubscriptionImpl.Factory());
- }
-
- protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete,
- VirtualHost virtualHost, SubscriptionSet subscribers) throws AMQException
- {
- this(name, durable, owner, autoDelete, virtualHost, AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers,
- new SubscriptionImpl.Factory());
- }
-
- protected AMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete,
- VirtualHost virtualHost, Executor asyncDelivery, SubscriptionSet subscribers,
- SubscriptionFactory subscriptionFactory) throws AMQException
- {
- if (name == null)
- {
- throw new IllegalArgumentException("Queue name must not be null");
- }
-
- if (virtualHost == null)
- {
- throw new IllegalArgumentException("Virtual Host must not be null");
- }
-
- _name = name;
- _durable = durable;
- _owner = owner;
- _autoDelete = autoDelete;
- _virtualHost = virtualHost;
- _asyncDelivery = asyncDelivery;
-
- _managedObject = createMBean();
- _managedObject.register();
-
- _subscribers = subscribers;
- _subscriptionFactory = subscriptionFactory;
- _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscribers, this);
-
- // This ensure that the notification checks for the configured alerts are created.
- setMaximumMessageAge(_maximumMessageAge);
- setMaximumMessageCount(_maximumMessageCount);
- setMaximumMessageSize(_maximumMessageSize);
- setMaximumQueueDepth(_maximumQueueDepth);
-
- }
-
- private AMQQueueMBean createMBean() throws AMQException
- {
- try
- {
- return new AMQQueueMBean(this);
- }
- catch (JMException ex)
- {
- throw new AMQException("AMQQueue MBean creation has failed ", ex);
- }
- }
-
- public final AMQShortString getName()
- {
- return _name;
- }
+import java.util.List;
+import java.util.Set;
- public boolean isShared()
- {
- return _owner == null;
- }
+public interface AMQQueue extends Managable, Comparable<AMQQueue>
+{
- public boolean isDurable()
- {
- return _durable;
- }
+ AMQShortString getName();
- public AMQShortString getOwner()
- {
- return _owner;
- }
+ boolean isDurable();
- public boolean isAutoDelete()
- {
- return _autoDelete;
- }
+ boolean isAutoDelete();
- public boolean isDeleted()
- {
- return _deleted.get();
- }
+ AMQShortString getOwner();
- /** @return no of messages(undelivered) on the queue. */
- public int getMessageCount()
- {
- return _deliveryMgr.getQueueMessageCount();
- }
+ VirtualHost getVirtualHost();
- /** @return List of messages(undelivered) on the queue. */
- public List<QueueEntry> getMessagesOnTheQueue()
- {
- return _deliveryMgr.getMessages();
- }
- /**
- * Returns messages within the given range of message Ids.
- *
- * @param fromMessageId
- * @param toMessageId
- *
- * @return List of messages
- */
- public List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId)
- {
- return _deliveryMgr.getMessages(fromMessageId, toMessageId);
- }
+ void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException;
- public long getQueueDepth()
- {
- return _deliveryMgr.getTotalMessageSize();
- }
+ void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException;
- /**
- * @param messageId
- *
- * @return QueueEntry with give id if exists. null if QueueEntry with given id doesn't exist.
- */
- public QueueEntry getMessageOnTheQueue(long messageId)
- {
- List<QueueEntry> list = getMessagesOnTheQueue(messageId, messageId);
- if ((list == null) || (list.size() == 0))
- {
- return null;
- }
- return list.get(0);
- }
- /**
- * Moves messages from this queue to another queue, and also commits the move on the message store. Delivery activity
- * on the queues being moved between is suspended during the move.
- *
- * @param fromMessageId The first message id to move.
- * @param toMessageId The last message id to move.
- * @param queueName The queue to move the messages to.
- * @param storeContext The context of the message store under which to perform the move. This is associated with
- * the stores transactional context.
- */
- public synchronized void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName,
- StoreContext storeContext)
- {
- AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
+ void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException;
- MessageStore fromStore = getVirtualHost().getMessageStore();
- MessageStore toStore = toQueue.getVirtualHost().getMessageStore();
+ void unregisterSubscription(final Subscription subscription) throws AMQException;
- if (toStore != fromStore)
- {
- throw new RuntimeException("Can only move messages between queues on the same message store.");
- }
- try
- {
- // Obtain locks to prevent activity on the queues being moved between.
- startMovingMessages();
- toQueue.startMovingMessages();
-
- // Get the list of messages to move.
- List<QueueEntry> foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId);
-
- try
- {
- fromStore.beginTran(storeContext);
-
- // Move the messages in on the message store.
- for (QueueEntry entry : foundMessagesList)
- {
- AMQMessage message = entry.getMessage();
- fromStore.dequeueMessage(storeContext, _name, message.getMessageId());
- toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId());
- }
-
- // Commit and flush the move transcations.
- try
- {
- fromStore.commitTran(storeContext);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
- }
-
- // Move the messages on the in-memory queues.
- toQueue.enqueueMovedMessages(storeContext, foundMessagesList);
- _deliveryMgr.removeMovedMessages(foundMessagesList);
- }
- // Abort the move transactions on move failures.
- catch (AMQException e)
- {
- try
- {
- fromStore.abortTran(storeContext);
- }
- catch (AMQException ae)
- {
- throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae);
- }
- }
- }
- // Release locks to allow activity on the queues being moved between to continue.
- finally
- {
- toQueue.stopMovingMessages();
- stopMovingMessages();
- }
- }
-
- /**
- * Copies messages on this queue to another queue, and also commits the move on the message store. Delivery activity
- * on the queues being moved between is suspended during the move.
- *
- * @param fromMessageId The first message id to move.
- * @param toMessageId The last message id to move.
- * @param queueName The queue to move the messages to.
- * @param storeContext The context of the message store under which to perform the move. This is associated with
- * the stores transactional context.
- */
- public synchronized void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName,
- StoreContext storeContext)
- {
- AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
-
- MessageStore fromStore = getVirtualHost().getMessageStore();
- MessageStore toStore = toQueue.getVirtualHost().getMessageStore();
-
- if (toStore != fromStore)
- {
- throw new RuntimeException("Can only move messages between queues on the same message store.");
- }
-
- try
- {
- // Obtain locks to prevent activity on the queues being moved between.
- startMovingMessages();
- toQueue.startMovingMessages();
-
- // Get the list of messages to move.
- List<QueueEntry> foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId);
-
- try
- {
- fromStore.beginTran(storeContext);
-
- // Move the messages in on the message store.
- for (QueueEntry entry : foundMessagesList)
- {
- AMQMessage message = entry.getMessage();
- toStore.enqueueMessage(storeContext, toQueue._name, message.getMessageId());
- message.takeReference();
- }
-
- // Commit and flush the move transcations.
- try
- {
- fromStore.commitTran(storeContext);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
- }
-
- // Move the messages on the in-memory queues.
- toQueue.enqueueMovedMessages(storeContext, foundMessagesList);
- }
- // Abort the move transactions on move failures.
- catch (AMQException e)
- {
- try
- {
- fromStore.abortTran(storeContext);
- }
- catch (AMQException ae)
- {
- throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae);
- }
- }
- }
- // Release locks to allow activity on the queues being moved between to continue.
- finally
- {
- toQueue.stopMovingMessages();
- stopMovingMessages();
- }
- }
-
- /**
- * Removes messages from this queue, and also commits the remove on the message store. Delivery activity
- * on the queues being moved between is suspended during the remove.
- *
- * @param fromMessageId The first message id to move.
- * @param toMessageId The last message id to move.
- * @param storeContext The context of the message store under which to perform the move. This is associated with
- * the stores transactional context.
- */
- public synchronized void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext)
- {
- MessageStore fromStore = getVirtualHost().getMessageStore();
-
- try
- {
- // Obtain locks to prevent activity on the queues being moved between.
- startMovingMessages();
-
- // Get the list of messages to move.
- List<QueueEntry> foundMessagesList = getMessagesOnTheQueue(fromMessageId, toMessageId);
-
- try
- {
- fromStore.beginTran(storeContext);
-
- // remove the messages in on the message store.
- for (QueueEntry entry : foundMessagesList)
- {
- AMQMessage message = entry.getMessage();
- fromStore.dequeueMessage(storeContext, _name, message.getMessageId());
- }
-
- // Commit and flush the move transcations.
- try
- {
- fromStore.commitTran(storeContext);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
- }
-
- // remove the messages on the in-memory queues.
- _deliveryMgr.removeMovedMessages(foundMessagesList);
- }
- // Abort the move transactions on move failures.
- catch (AMQException e)
- {
- try
- {
- fromStore.abortTran(storeContext);
- }
- catch (AMQException ae)
- {
- throw new RuntimeException("Failed to abort transaction whilst moving messages on message store.", ae);
- }
- }
- }
- // Release locks to allow activity on the queues being moved between to continue.
- finally
- {
- stopMovingMessages();
- }
- }
+ int getConsumerCount();
- public void startMovingMessages()
- {
- _deliveryMgr.startMovingMessages();
- }
+ int getActiveConsumerCount();
- private void enqueueMovedMessages(StoreContext storeContext, List<QueueEntry> messageList)
- {
- _deliveryMgr.enqueueMovedMessages(storeContext, messageList);
- _totalMessagesReceived.addAndGet(messageList.size());
- }
+ boolean isUnused();
- public void stopMovingMessages()
- {
- _deliveryMgr.stopMovingMessages();
- _deliveryMgr.processAsync(_asyncDelivery);
- }
+ boolean isEmpty();
- /** @return MBean object associated with this Queue */
- public ManagedObject getManagedObject()
- {
- return _managedObject;
- }
+ int getMessageCount();
- public long getMaximumMessageSize()
- {
- return _maximumMessageSize;
- }
+ int getUndeliveredMessageCount();
- public void setMaximumMessageSize(final long maximumMessageSize)
- {
- _maximumMessageSize = maximumMessageSize;
- if(maximumMessageSize == 0L)
- {
- _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT);
- }
- else
- {
- _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT);
- }
- }
- public int getConsumerCount()
- {
- return _subscribers.size();
- }
+ long getQueueDepth();
- public int getActiveConsumerCount()
- {
- return _subscribers.getWeight();
- }
+ long getReceivedMessageCount();
- public long getReceivedMessageCount()
- {
- return _totalMessagesReceived.get();
- }
+ long getOldestMessageArrivalTime();
- public long getMaximumMessageCount()
- {
- return _maximumMessageCount;
- }
+ boolean isDeleted();
- public void setMaximumMessageCount(final long maximumMessageCount)
- {
- _maximumMessageCount = maximumMessageCount;
- if(maximumMessageCount == 0L)
- {
- _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT);
- }
- else
- {
- _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT);
- }
+ int delete() throws AMQException;
- }
+ QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException;
- public long getMaximumQueueDepth()
- {
- return _maximumQueueDepth;
- }
+ void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException;
- // Sets the queue depth, the max queue size
- public void setMaximumQueueDepth(final long maximumQueueDepth)
- {
- _maximumQueueDepth = maximumQueueDepth;
- if(maximumQueueDepth == 0L)
- {
- _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT);
- }
- else
- {
- _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT);
- }
+ void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException;
- }
- public long getOldestMessageArrivalTime()
- {
- return _deliveryMgr.getOldestMessageArrival();
- }
+ boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException;
- /** Removes the QueueEntry from the top of the queue. */
- public synchronized void deleteMessageFromTop(StoreContext storeContext) throws AMQException
- {
- _deliveryMgr.removeAMessageFromTop(storeContext, this);
- }
+
- /** removes all the messages from the queue. */
- public synchronized long clearQueue(StoreContext storeContext) throws AMQException
- {
- return _deliveryMgr.clearAllMessages(storeContext);
- }
+ void addQueueDeleteTask(final Task task);
- public void bind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException
- {
- exchange.registerQueue(routingKey, this, arguments);
- if (isDurable() && exchange.isDurable())
- {
- _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments);
- }
- _bindings.addBinding(routingKey, arguments, exchange);
- }
+ List<QueueEntry> getMessagesOnTheQueue();
- public void unBind(AMQShortString routingKey, FieldTable arguments, Exchange exchange) throws AMQException
- {
- exchange.deregisterQueue(routingKey, this, arguments);
- if (isDurable() && exchange.isDurable())
- {
- _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments);
- }
+ List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId);
- _bindings.remove(routingKey, arguments, exchange);
- }
+ QueueEntry getMessageOnTheQueue(long messageId);
- public void registerProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag, boolean acks,
- FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException
- {
- if (incrementSubscriberCount() > 1)
- {
- if (isExclusive())
- {
- decrementSubscriberCount();
- throw new ExistingExclusiveSubscription();
- }
- else if (exclusive)
- {
- decrementSubscriberCount();
- throw new ExistingSubscriptionPreventsExclusive();
- }
- }
- else if (exclusive)
- {
- setExclusive(true);
- }
+ void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName,
+ StoreContext storeContext);
- if (_logger.isDebugEnabled())
- {
- _logger.debug(MessageFormat.format("Registering protocol session {0} with channel {1} and "
- + "consumer tag {2} with {3}", ps, channel, consumerTag, this));
- }
+ void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext);
- Subscription subscription =
- _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks, filters, noLocal, this);
+ void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext);
- if (subscription.filtersMessages())
- {
- if (_deliveryMgr.hasQueuedMessages())
- {
- _deliveryMgr.populatePreDeliveryQueue(subscription);
- }
- }
- _subscribers.addSubscriber(subscription);
- if(exclusive)
- {
- _subscribers.setExclusive(true);
- }
- subscription.start();
- }
+ long getMaximumMessageSize();
- private boolean isExclusive()
- {
- return _isExclusive.get();
- }
+ void setMaximumMessageSize(long value);
- private void setExclusive(boolean exclusive)
- {
- _isExclusive.set(exclusive);
- }
- private int incrementSubscriberCount()
- {
- return _subscriberCount.incrementAndGet();
- }
+ long getMaximumMessageCount();
- private int decrementSubscriberCount()
- {
- return _subscriberCount.decrementAndGet();
- }
+ void setMaximumMessageCount(long value);
- public void unregisterProtocolSession(AMQProtocolSession ps, int channel, AMQShortString consumerTag) throws AMQException
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug(MessageFormat.format(
- "Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}",
- ps, channel, consumerTag, this));
- }
- _subscribers.setExclusive(false);
- Subscription removedSubscription;
- if ((removedSubscription = _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, ps,
- consumerTag)))
- == null)
- {
- throw new AMQException("Protocol session with channel " + channel + " and consumer tag " + consumerTag
- + " and protocol session key " + ps.getKey() + " not registered with queue " + this);
- }
+ long getMaximumQueueDepth();
- removedSubscription.close();
- setExclusive(false);
- decrementSubscriberCount();
+ void setMaximumQueueDepth(long value);
- // if we are eligible for auto deletion, unregister from the queue registry
- if (_autoDelete && _subscribers.isEmpty())
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Auto-deleteing queue:" + this);
- }
-
- autodelete();
- // we need to manually fire the event to the removed subscription (which was the last one left for this
- // queue. This is because the delete method uses the subscription set which has just been cleared
- removedSubscription.queueDeleted(this);
- }
- }
- public boolean isUnused()
- {
- return _subscribers.isEmpty();
- }
+ long getMaximumMessageAge();
- public boolean isEmpty()
- {
- return !_deliveryMgr.hasQueuedMessages();
- }
+ void setMaximumMessageAge(final long maximumMessageAge);
- public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException
- {
- if (checkUnused && !_subscribers.isEmpty())
- {
- _logger.info("Will not delete " + this + " as it is in use.");
- return 0;
- }
- else if (checkEmpty && _deliveryMgr.hasQueuedMessages())
- {
- _logger.info("Will not delete " + this + " as it is not empty.");
+ long getMinimumAlertRepeatGap();
- return 0;
- }
- else
- {
- delete();
- return _deliveryMgr.getQueueMessageCount();
- }
- }
+ void deleteMessageFromTop(StoreContext storeContext) throws AMQException;
- public void delete() throws AMQException
- {
- if (!_deleted.getAndSet(true))
- {
- _subscribers.queueDeleted(this);
- _bindings.deregister();
- _virtualHost.getQueueRegistry().unregisterQueue(_name);
- _managedObject.unregister();
- for (Task task : _deleteTaskList)
- {
- task.doTask(this);
- }
-
- _deleteTaskList.clear();
- }
- }
+ long clearQueue(StoreContext storeContext) throws AMQException;
- protected void autodelete() throws AMQException
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug(MessageFormat.format("autodeleting {0}", this));
- }
- delete();
- }
- /*public void processGet(StoreContext storeContext, AMQMessage msg, boolean deliverFirst) throws AMQException
- {
- // fixme not sure what this is doing. should we be passing deliverFirst through here?
- // This code is not used so when it is perhaps it should
- _deliveryMgr.deliver(storeContext, getName(), msg, deliverFirst);
- try
- {
- msg.checkDeliveredToConsumer();
- updateReceivedMessageCount(msg);
- }
- catch (NoConsumersException e)
- {
- // as this message will be returned, it should be removed
- // from the queue:
- dequeue(storeContext, msg);
- }
- }*/
+ void removeExpiredIfNoSubscribers() throws AMQException;
- // public DeliveryManager getDeliveryManager()
- // {
- // return _deliveryMgr;
- // }
+ Set<NotificationCheck> getNotificationChecks();
- public void process(StoreContext storeContext, QueueEntry entry, boolean deliverFirst) throws AMQException
- {
- AMQMessage msg = entry.getMessage();
- _deliveryMgr.deliver(storeContext, _name, entry, deliverFirst);
- try
- {
- msg.checkDeliveredToConsumer();
- updateReceivedMessageCount(entry);
- }
- catch (NoConsumersException e)
- {
- // as this message will be returned, it should be removed
- // from the queue:
- dequeue(storeContext, entry);
- }
- }
+ void flushSubscription(final Subscription sub) throws AMQException;
- public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException
- {
- try
- {
- entry.getMessage().dequeue(storeContext, this);
- }
- catch (MessageCleanupException e)
- {
- // Message was dequeued, but could not then be deleted
- // though it is no longer referenced. This should be very
- // rare and can be detected and cleaned up on recovery or
- // done through some form of manual intervention.
- _logger.error(e, e);
- }
- catch (AMQException e)
- {
- throw new FailedDequeueException(_name.toString(), e);
- }
- }
+ void deliverAsync(final Subscription sub);
- public void deliverAsync()
- {
- _deliveryMgr.processAsync(_asyncDelivery);
- }
+ void deliverAsync();
- protected SubscriptionManager getSubscribers()
- {
- return _subscribers;
- }
- protected void updateReceivedMessageCount(QueueEntry entry) throws AMQException
+ /**
+ * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription
+ * already exists.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent failure to create a subscription, because an exclusive subscription already exists.
+ * </table>
+ *
+ * @todo Not an AMQP exception as no status code.
+ *
+ * @todo Move to top level, used outside this class.
+ */
+ static final class ExistingExclusiveSubscription extends AMQException
{
- AMQMessage msg = entry.getMessage();
-
- if (!msg.isRedelivered())
- {
- _totalMessagesReceived.incrementAndGet();
- }
- try
- {
- _managedObject.checkForNotification(msg);
- }
- catch (JMException e)
+ public ExistingExclusiveSubscription()
{
- throw new AMQException("Unable to get notification from manage queue: " + e, e);
+ super("");
}
}
- public boolean equals(Object o)
+ /**
+ * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription
+ * already exists.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent failure to create an exclusize subscription, as a subscription already exists.
+ * </table>
+ *
+ * @todo Not an AMQP exception as no status code.
+ *
+ * @todo Move to top level, used outside this class.
+ */
+ static final class ExistingSubscriptionPreventsExclusive extends AMQException
{
- if (this == o)
- {
- return true;
- }
-
- if ((o == null) || (getClass() != o.getClass()))
+ public ExistingSubscriptionPreventsExclusive()
{
- return false;
+ super("");
}
-
- final AMQQueue amqQueue = (AMQQueue) o;
-
- return (_name.equals(amqQueue._name));
- }
-
- public int hashCode()
- {
- return _name.hashCode();
}
- public String toString()
- {
- return "Queue(" + _name + ")@" + System.identityHashCode(this);
- }
-
- public boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException
- {
- return _deliveryMgr.performGet(session, channel, acks);
- }
-
- public QueueRegistry getQueueRegistry()
- {
- return _virtualHost.getQueueRegistry();
- }
-
- public VirtualHost getVirtualHost()
- {
- return _virtualHost;
- }
-
- public static interface Task
+ static interface Task
{
public void doTask(AMQQueue queue) throws AMQException;
}
-
- public void addQueueDeleteTask(Task task)
- {
- _deleteTaskList.add(task);
- }
-
- public long getMinimumAlertRepeatGap()
- {
- return _minimumAlertRepeatGap;
- }
-
- public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap)
- {
- _minimumAlertRepeatGap = minimumAlertRepeatGap;
- }
-
- public long getMaximumMessageAge()
- {
- return _maximumMessageAge;
- }
-
- public void setMaximumMessageAge(long maximumMessageAge)
- {
- _maximumMessageAge = maximumMessageAge;
- if(maximumMessageAge == 0L)
- {
- _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT);
- }
- else
- {
- _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT);
- }
- }
-
- public void subscriberHasPendingResend(boolean hasContent, SubscriptionImpl subscription, QueueEntry entry)
- {
- _deliveryMgr.subscriberHasPendingResend(hasContent, subscription, entry);
- }
-
- public QueueEntry createEntry(AMQMessage amqMessage)
- {
- return new QueueEntry(this, amqMessage);
- }
-
- public int compareTo(Object o)
- {
- return _name.compareTo(((AMQQueue) o).getName());
- }
-
-
- public void removeExpiredIfNoSubscribers() throws AMQException
- {
- synchronized(_subscribers.getChangeLock())
- {
- if(_subscribers.isEmpty())
- {
- _deliveryMgr.removeExpired();
- }
- }
- }
-
- public final Set<NotificationCheck> getNotificationChecks()
- {
- return _notificationChecks;
- }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
new file mode 100644
index 0000000000..431b76754f
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.AMQException;
+
+
+public class AMQQueueFactory
+{
+ private static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
+
+ public static AMQQueue createAMQQueueImpl(AMQShortString name,
+ boolean durable,
+ AMQShortString owner,
+ boolean autoDelete,
+ VirtualHost virtualHost, final FieldTable arguments)
+ throws AMQException
+ {
+
+ final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1;
+
+ if(priorities > 1)
+ {
+ return new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities);
+ }
+ else
+ {
+ return new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost);
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index 348a136f9d..2ed6be77c6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -292,7 +292,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
}
/**
- * @see org.apache.qpid.server.queue.AMQQueue#deleteMessageFromTop
+ * @see AMQQueue#deleteMessageFromTop
*/
public void deleteMessageFromTop() throws JMException
{
@@ -307,7 +307,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
}
/**
- * @see org.apache.qpid.server.queue.AMQQueue#clearQueue
+ * @see AMQQueue#clearQueue
*/
public void clearQueue() throws JMException
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java
deleted file mode 100644
index 0e8cff0f2a..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java
+++ /dev/null
@@ -1,1097 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize;
-import org.apache.qpid.util.MessageQueue;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantLock;
-
-
-/** Manages delivery of messages on behalf of a queue */
-public class ConcurrentSelectorDeliveryManager implements DeliveryManager
-{
- private static final Logger _log = Logger.getLogger(ConcurrentSelectorDeliveryManager.class);
-
- @Configured(path = "advanced.compressBufferOnQueue",
- defaultValue = "false")
- public boolean compressBufferOnQueue;
- /** Holds any queued messages */
- private final MessageQueue<QueueEntry> _messages = new ConcurrentLinkedMessageQueueAtomicSize<QueueEntry>();
-
- /** Ensures that only one asynchronous task is running for this manager at any time. */
- private final AtomicBoolean _processing = new AtomicBoolean();
- /** The subscriptions on the queue to whom messages are delivered */
- private final SubscriptionManager _subscriptions;
-
- /**
- * A reference to the queue we are delivering messages for. We need this to be able to pass the code that handles
- * acknowledgements a handle on the queue.
- */
- private final AMQQueue _queue;
-
- /**
- * Flag used while moving messages from this queue to another. For moving messages the async delivery should also
- * stop. This flat should be set to true to stop async delivery and set to false to enable async delivery again.
- */
- private AtomicBoolean _movingMessages = new AtomicBoolean();
-
- /**
- * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced
- * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be
- * delivered via the async thread. <p/> Lock is used to control access to hasQueuedMessages() and over the addition
- * of messages to the queue.
- */
- private ReentrantLock _lock = new ReentrantLock();
- private AtomicLong _totalMessageSize = new AtomicLong();
- private AtomicInteger _extraMessages = new AtomicInteger();
- private Set<Subscription> _hasContent = Collections.synchronizedSet(new HashSet<Subscription>());
- private final Object _queueHeadLock = new Object();
- private String _processingThreadName = "";
-
- ConcurrentSelectorDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue)
- {
-
- //Set values from configuration
- Configurator.configure(this);
-
- if (compressBufferOnQueue)
- {
- _log.warn("Compressing Buffers on queue.");
- }
-
- _subscriptions = subscriptions;
- _queue = queue;
- }
-
-
- private boolean addMessageToQueue(QueueEntry entry, boolean deliverFirst)
- {
- AMQMessage msg = entry.getMessage();
- // Shrink the ContentBodies to their actual size to save memory.
- if (compressBufferOnQueue)
- {
- Iterator<ContentChunk> it = msg.getContentBodyIterator();
- while (it.hasNext())
- {
- ContentChunk cb = it.next();
- cb.reduceToFit();
- }
- }
-
- if (deliverFirst)
- {
- synchronized (_queueHeadLock)
- {
- _messages.pushHead(entry);
- }
- }
- else
- {
- _messages.offer(entry);
- }
-
- _totalMessageSize.addAndGet(msg.getSize());
-
- return true;
- }
-
-
- public boolean hasQueuedMessages()
- {
- _lock.lock();
- try
- {
- return !(_messages.isEmpty() && _hasContent.isEmpty());
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- public int getQueueMessageCount()
- {
- return getMessageCount();
- }
-
- /**
- * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine
- * size. The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue.
- *
- * @return int the number of messages in the delivery queue.
- */
- private int getMessageCount()
- {
- return _messages.size() + _extraMessages.get();
- }
-
-
- public long getTotalMessageSize()
- {
- return _totalMessageSize.get();
- }
-
- public long getOldestMessageArrival()
- {
- QueueEntry entry = _messages.peek();
- return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime();
- }
-
- public void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry entry)
- {
- _lock.lock();
- try
- {
- if (hasContent)
- {
- _log.debug("Queue has adding subscriber content");
- _hasContent.add(subscription);
- _totalMessageSize.addAndGet(entry.getSize());
- _extraMessages.addAndGet(1);
- }
- else
- {
- _log.debug("Queue has removing subscriber content");
- if (entry == null)
- {
- _hasContent.remove(subscription);
- }
- else
- {
- _totalMessageSize.addAndGet(-entry.getSize());
- _extraMessages.addAndGet(-1);
- }
- }
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- /**
- * NOTE : This method should only be called when there are no active subscribers
- */
- public void removeExpired() throws AMQException
- {
- _lock.lock();
- try
- {
- // New Context to for dealing with the MessageStore.
- StoreContext context = new StoreContext();
-
- for(Iterator<QueueEntry> iter = _messages.iterator(); iter.hasNext();)
- {
- QueueEntry entry = iter.next();
- if(entry.expired())
- {
- // fixme: Currently we have to update the total byte size here for the data in the queue
- _totalMessageSize.addAndGet(-entry.getSize());
-
- // Remove the message from the queue in the MessageStore
- _queue.dequeue(context,entry);
-
- // This queue nolonger needs a reference to this message
- entry.getMessage().decrementReference(context);
- iter.remove();
- }
- }
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- /** @return the state of the async processor. */
- public boolean isProcessingAsync()
- {
- return _processing.get();
- }
-
- /**
- * Returns all the messages in the Queue
- *
- * @return List of messages
- */
- public List<QueueEntry> getMessages()
- {
- List<QueueEntry> list = new ArrayList<QueueEntry>();
-
- _lock.lock();
- try
- {
- for (QueueEntry entry : _messages)
- {
- list.add(entry);
- }
- }
- finally
- {
- _lock.unlock();
- }
-
- return list;
- }
-
- /**
- * Returns messages within the range of given messageIds
- *
- * @param fromMessageId
- * @param toMessageId
- *
- * @return
- */
- public List<QueueEntry> getMessages(long fromMessageId, long toMessageId)
- {
- if (fromMessageId <= 0 || toMessageId <= 0)
- {
- return null;
- }
-
- long maxMessageCount = toMessageId - fromMessageId + 1;
-
- List<QueueEntry> foundMessagesList = new ArrayList<QueueEntry>();
- _lock.lock();
- try
- {
- for (QueueEntry entry : _messages)
- {
- long msgId = entry.getMessage().getMessageId();
- if (msgId >= fromMessageId && msgId <= toMessageId)
- {
- foundMessagesList.add(entry);
- }
- // break if the no of messages are found
- if (foundMessagesList.size() == maxMessageCount)
- {
- break;
- }
- }
- }
- finally
- {
- _lock.unlock();
- }
-
- return foundMessagesList;
- }
-
- public void populatePreDeliveryQueue(Subscription subscription)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Populating PreDeliveryQueue for Subscription(" + System.identityHashCode(subscription) + ")");
- }
-
- Iterator<QueueEntry> currentQueue = _messages.iterator();
-
- while (currentQueue.hasNext())
- {
- QueueEntry entry = currentQueue.next();
-
- if (subscription.hasInterest(entry))
- {
- subscription.enqueueForPreDelivery(entry, false);
- }
-
- }
- }
-
- public boolean performGet(AMQProtocolSession protocolSession, AMQChannel channel, boolean acks) throws AMQException
- {
- QueueEntry entry = getNextMessage();
- if (entry == null)
- {
- return false;
- }
- else
- {
-
- try
- {
- // if we do not need to wait for client acknowledgements
- // we can decrement the reference count immediately.
-
- // By doing this _before_ the send we ensure that it
- // doesn't get sent if it can't be dequeued, preventing
- // duplicate delivery on recovery.
-
- // The send may of course still fail, in which case, as
- // the message is unacked, it will be lost.
- if (!acks)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("No ack mode so dequeuing message immediately: " + entry.getMessage().getMessageId());
- }
- _queue.dequeue(channel.getStoreContext(), entry);
- }
- synchronized (channel)
- {
- long deliveryTag = channel.getNextDeliveryTag();
-
- if (acks)
- {
- channel.addUnacknowledgedMessage(entry, deliveryTag, null);
- }
-
- protocolSession.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(),
- deliveryTag, _queue.getMessageCount());
-
- }
- _totalMessageSize.addAndGet(-entry.getSize());
-
- if (!acks)
- {
- entry.getMessage().decrementReference(channel.getStoreContext());
- }
- }
- finally
- {
- entry.setDeliveredToConsumer();
- }
- return true;
-
- }
- }
-
- /**
- * For feature of moving messages, this method is used. It sets the lock and sets the movingMessages flag, so that
- * the asyn delivery is also stopped.
- */
- public void startMovingMessages()
- {
- _movingMessages.set(true);
- }
-
- /**
- * Once moving messages to another queue is done or aborted, remove lock and unset the movingMessages flag, so that
- * the async delivery can start again.
- */
- public void stopMovingMessages()
- {
- _movingMessages.set(false);
- if (_lock.isHeldByCurrentThread())
- {
- _lock.unlock();
- }
- }
-
- /**
- * Messages will be removed from this queue and all preDeliveryQueues
- *
- * @param messageList
- */
- public void removeMovedMessages(List<QueueEntry> messageList)
- {
- // Remove from the
- boolean hasSubscribers = _subscriptions.hasActiveSubscribers();
- if (hasSubscribers)
- {
- for (Subscription sub : _subscriptions.getSubscriptions())
- {
- if (!sub.isSuspended() && sub.filtersMessages())
- {
- Queue<QueueEntry> preDeliveryQueue = sub.getPreDeliveryQueue();
- for (QueueEntry entry : messageList)
- {
- preDeliveryQueue.remove(entry);
- }
- }
- }
- }
-
- for (QueueEntry entry : messageList)
- {
- if (_messages.remove(entry))
- {
- _totalMessageSize.getAndAdd(-entry.getSize());
- }
- }
- }
-
- /**
- * Now with implementation of predelivery queues, this method will mark the message on the top as taken.
- *
- * @param storeContext
- *
- * @throws AMQException
- */
- public void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException
- {
- _lock.lock();
-
- try
- {
- QueueEntry entry = _messages.poll();
-
- if (entry != null)
- {
- queue.dequeue(storeContext, entry);
-
- _totalMessageSize.addAndGet(-entry.getSize());
-
- //If this causes ref count to hit zero then data will be purged so message.getSize() will NPE.
- entry.getMessage().decrementReference(storeContext);
-
- }
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- public long clearAllMessages(StoreContext storeContext) throws AMQException
- {
- long count = 0;
-
- _lock.lock();
- try
- {
- synchronized (_queueHeadLock)
- {
- QueueEntry entry = getNextMessage();
-
- // todo: note: why do we need this? Why not reuse the passed 'storeContext'
- //Create a new StoreContext for decrementing the References
- StoreContext context = new StoreContext();
-
- while (entry != null)
- {
- //and remove it
- _messages.poll();
-
- // todo: NOTE: Why is this a different context to the new local 'context'?
- _queue.dequeue(storeContext, entry);
-
- entry.getMessage().decrementReference(context);
-
- entry = getNextMessage();
- count++;
- }
- _totalMessageSize.set(0L);
- }
- }
- finally
- {
- _lock.unlock();
- }
- return count;
- }
-
- /**
- * This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged.
- *
- * @return the next message or null
- *
- * @throws org.apache.qpid.AMQException
- */
- private QueueEntry getNextMessage() throws AMQException
- {
- return getNextMessage(_messages, null, false);
- }
-
- private QueueEntry getNextMessage(Queue<QueueEntry> messages, Subscription sub, boolean purgeOnly) throws AMQException
- {
- QueueEntry entry = messages.peek();
-
- //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.)
- while (purgeMessage(entry, sub, purgeOnly))
- {
- AMQMessage message = entry.getMessage();
-
- //remove the already taken message or expired
- QueueEntry removed = messages.poll();
-
- assert removed == entry;
-
- // if the message expired then the _totalMessageSize needs adjusting
- if (message.expired(_queue) && !entry.taken(sub))
- {
- _totalMessageSize.addAndGet(-entry.getSize());
-
- // New Store Context for removing expired messages
- StoreContext storeContext = new StoreContext();
-
- // Use the reapingStoreContext as any sub(if we have one) may be in a tx.
- _queue.dequeue(storeContext, entry);
-
- message.decrementReference(storeContext);
-
- if (_log.isInfoEnabled())
- {
- _log.info(debugIdentity() + " Doing clean up of the main _message queue.");
- }
- }
-
- //else the clean up is not required as the message has already been taken for this queue therefore
- // it was the responsibility of the code that took the message to ensure the _totalMessageSize was updated.
-
- if (_log.isDebugEnabled())
- {
- _log.debug("Removed taken message:" + message.debugIdentity());
- }
-
- // try the next message
- entry = messages.peek();
- }
-
- return entry;
- }
-
- /**
- * This method will return true if the message is to be purged from the queue.
- *
- *
- * SIDE-EFFECT: The message will be taken by the Subscription(sub) for the current Queue(_queue)
- *
- * @param message
- * @param sub
- *
- * @return
- *
- * @throws AMQException
- */
- private boolean purgeMessage(QueueEntry message, Subscription sub) throws AMQException
- {
- return purgeMessage(message, sub, false);
- }
-
- /**
- * This method will return true if the message is to be purged from the queue.
- * \
- * SIDE-EFFECT: The msg will be taken by the Subscription(sub) for the current Queue(_queue) when purgeOnly is false
- *
- * @param message
- * @param sub
- * @param purgeOnly When set to false the message will be taken by the given Subscription.
- *
- * @return if the msg should be purged
- *
- * @throws AMQException
- */
- private boolean purgeMessage(QueueEntry message, Subscription sub, boolean purgeOnly) throws AMQException
- {
- //Original.. complicated while loop control
-// (message != null
-// && (
-// ((sub != null && !sub.isBrowser()) || message.isTaken(_queue))
-// || sub == null)
-// && message.taken(_queue, sub));
-
- boolean purge = false;
-
- // if the message is null then don't purge as we have no messagse.
- if (message != null)
- {
- // Check that the message hasn't expired.
- if (message.expired())
- {
- return true;
- }
-
- // if we have a subscriber perform message checks
- if (sub != null)
- {
- // if we have a queue browser(we don't purge) so check mark the message as taken
- purge = ((!sub.isBrowser() || message.isTaken()));
- }
- else
- {
- // if there is no subscription we are doing
- // a get or purging so mark message as taken.
- message.isTaken();
- // and then ensure that it gets purged
- purge = true;
- }
- }
-
- if (purgeOnly)
- {
- // If we are simply purging the queue don't take the message
- // just purge up to the next non-taken msg.
- return purge && message.isTaken();
- }
- else
- {
- // if we are purging then ensure we mark this message taken for the current subscriber
- // the current subscriber may be null in the case of a get or a purge but this is ok.
- return purge && message.taken(sub);
- }
- }
-
- public void sendNextMessage(Subscription sub, AMQQueue queue)
- {
-
- Queue<QueueEntry> messageQueue = sub.getNextQueue(_messages);
-
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Async sendNextMessage for sub (" + System.identityHashCode(sub) +
- ") from queue (" + System.identityHashCode(messageQueue) +
- ") AMQQueue (" + System.identityHashCode(queue) + ")");
- }
-
- if (messageQueue == null)
- {
- // There is no queue with messages currently. This is ok... just means the queue has no msgs matching selector
- if (_log.isInfoEnabled())
- {
- _log.info(debugIdentity() + sub + ": asked to send messages but has none on given queue:" + queue);
- }
- return;
- }
-
- QueueEntry entry = null;
- QueueEntry removed = null;
- try
- {
- synchronized (_queueHeadLock)
- {
- entry = getNextMessage(messageQueue, sub, false);
-
- // message will be null if we have no messages in the messageQueue.
- if (entry == null)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "No messages for Subscriber(" + System.identityHashCode(sub) + ") from queue; (" + System.identityHashCode(messageQueue) + ")");
- }
- return;
- }
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Async Delivery Message :" + entry + "(" + System.identityHashCode(entry) +
- ") by :" + System.identityHashCode(this) +
- ") to :" + System.identityHashCode(sub));
- }
-
-
- if (messageQueue == _messages)
- {
- _totalMessageSize.addAndGet(-entry.getSize());
- }
-
- sub.send(entry, _queue);
-
- //remove sent message from our queue.
- removed = messageQueue.poll();
- //If we don't remove the message from _messages
- // Otherwise the Async send will never end
- }
-
- if (removed != entry)
- {
- _log.error("Just send message:" + entry.getMessage().debugIdentity() + " BUT removed this from queue:" + removed);
- }
-
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.getMessage().debugIdentity() + "d:" + entry +
- ") by :" + System.identityHashCode(this) +
- ") to :" + System.identityHashCode(sub));
- }
-
-
- if (messageQueue == sub.getResendQueue())
- {
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "All messages sent from resendQueue for " + sub);
- }
- if (messageQueue.isEmpty())
- {
- subscriberHasPendingResend(false, sub, null);
- //better to use the above method as this keeps all the tracking in one location.
- // _hasContent.remove(sub);
- }
-
- _extraMessages.decrementAndGet();
- }
- else if (messageQueue == sub.getPreDeliveryQueue() && !sub.isBrowser())
- {
- cleanMainQueue(sub);
- }
-
- }
- catch (AMQException e)
- {
- if (entry != null)
- {
- entry.release();
- }
- else
- {
- _log.error(debugIdentity() + "Unable to release message as it is null. " + e, e);
- }
- _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e);
- }
- }
-
- private void cleanMainQueue(Subscription sub)
- {
- try
- {
- getNextMessage(_messages, sub, true);
- }
- catch (AMQException e)
- {
- _log.warn("Problem during main queue purge:" + e.getMessage());
- }
- }
-
- /**
- * enqueues the messages in the list on the queue and all required predelivery queues
- *
- * @param storeContext
- * @param movedMessageList
- */
- public void enqueueMovedMessages(StoreContext storeContext, List<QueueEntry> movedMessageList)
- {
- _lock.lock();
- try
- {
- for (QueueEntry entry : movedMessageList)
- {
- addMessageToQueue(entry, false);
- }
-
- // enqueue on the pre delivery queues
- for (Subscription sub : _subscriptions.getSubscriptions())
- {
- for (QueueEntry entry : movedMessageList)
- {
- // Only give the message to those that want them.
- if (sub.hasInterest(entry))
- {
- sub.enqueueForPreDelivery(entry, true);
- }
- }
- }
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- /**
- * Only one thread should ever execute this method concurrently, but it can do so while other threads invoke
- * deliver().
- */
- private void processQueue()
- {
- //record thread name
- if (_log.isDebugEnabled())
- {
- _processingThreadName = Thread.currentThread().getName();
- }
-
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Running process Queue." + currentStatus());
- }
-
- // Continue to process delivery while we haveSubscribers and messages
- boolean hasSubscribers = _subscriptions.hasActiveSubscribers();
-
- while (hasSubscribers && hasQueuedMessages() && !_movingMessages.get())
- {
- hasSubscribers = false;
-
- for (Subscription sub : _subscriptions.getSubscriptions())
- {
- synchronized (sub.getSendLock())
- {
- if (!sub.isSuspended())
- {
- sendNextMessage(sub, _queue);
-
- hasSubscribers = true;
- }
- }
- }
- }
-
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Done process Queue." + currentStatus());
- }
-
- }
-
- public void deliver(StoreContext context, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws AMQException
- {
-
- final boolean debugEnabled = _log.isDebugEnabled();
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + "deliver :first(" + deliverFirst + ") :" + entry);
- }
-
- //Check if we have someone to deliver the message to.
- _lock.lock();
- try
- {
- Subscription s = _subscriptions.nextSubscriber(entry);
-
- if (s == null || (!s.filtersMessages() && hasQueuedMessages())) //no-one can take the message right now or we're queueing
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + "Testing Message(" + entry + ") for Queued Delivery:" + currentStatus());
- }
- if (!entry.getMessage().getMessagePublishInfo().isImmediate())
- {
- addMessageToQueue(entry, deliverFirst);
-
- //release lock now message is on queue.
- _lock.unlock();
-
- //Pre Deliver to all subscriptions
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + "We have " + _subscriptions.getSubscriptions().size() +
- " subscribers to give the message to:" + currentStatus());
- }
- for (Subscription sub : _subscriptions.getSubscriptions())
- {
-
- // Only give the message to those that want them.
- if (sub.hasInterest(entry))
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + "Queuing message(" + System.identityHashCode(entry) +
- ") for PreDelivery for subscriber(" + System.identityHashCode(sub) + ")");
- }
- sub.enqueueForPreDelivery(entry, deliverFirst);
- }
- }
-
- //if we have a non-filtering subscriber but queued messages && we're not Async && we have other Active subs then something is wrong!
- if ((s != null && hasQueuedMessages()) && !isProcessingAsync() && _subscriptions.hasActiveSubscribers())
- {
- _queue.deliverAsync();
- }
-
- }
- }
- else
- {
-
- if (s.filtersMessages())
- {
- if (s.getPreDeliveryQueue().size() > 0)
- {
- _log.error("Direct delivery from PDQ with queued msgs:" + s.getPreDeliveryQueue().size());
- }
- }
- else if (_messages.size() > 0)
- {
- _log.error("Direct delivery from MainQueue queued msgs:" + _messages.size());
- }
-
- //release lock now
- _lock.unlock();
- synchronized (s.getSendLock())
- {
- if (!s.isSuspended())
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + "Delivering Message:" + entry.getMessage().debugIdentity() + " to(" +
- System.identityHashCode(s) + ") :" + s);
- }
-
- if (entry.taken(s))
- {
- //Message has been delivered so don't redeliver.
- // This can currently occur because of the recursive call below
- // During unit tests the send can occur
- // client then rejects
- // this reject then releases the message by the time the
- // if(!msg.isTaken()) call is made below
- // the message has been released so that thread loops to send the message again
- // of course by the time it gets back to here. the thread that released the
- // message is now ready to send it. Here is a sample trace for reference
-//1192627162613:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]
-//1192627162613:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}
-//1192627162613:Thread[pool-917-thread-4,5,main]:28398657 Sent :dt:214 msg:(HC:5529738 ID:145 Ref:1)
-//1192627162613:Thread[pool-917-thread-2,5,main]:Reject message by:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]
-//1192627162613:Thread[pool-917-thread-2,5,main]:Releasing Message:(HC:5529738 ID:145 Ref:1)
-//1192627162613:Thread[pool-917-thread-2,5,main]:Msg:Release:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:This:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=41, session=anonymous(5050419), resendQueue=false]}
-//1192627162613:Thread[pool-917-thread-2,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]
-//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:suspended: Message((HC:5529738 ID:145 Ref:1)) has not been taken so recursing!: Subscriber:28398657
-//1192627162629:Thread[pool-917-thread-4,5,main]:CSDM:delivery:(true)message:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]
-//1192627162629:Thread[pool-917-thread-2,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=false} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=null}
-//1192627162629:Thread[pool-917-thread-2,5,main]:25386607 Sent :dt:172 msg:(HC:5529738 ID:145 Ref:1)
-//1192627162629:Thread[pool-917-thread-4,5,main]:Msg:taken:Q:Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326:sub:[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]:this:Message[(HC:5529738 ID:145 Ref:1)]: 145; ref count: 1; taken for queues: {Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=true} by Subs:{Queue(queue-596fb10e-2968-4e51-a751-1e6643bf9dd6)@16017326=[channel=Channel: id 1, transaction mode: true, prefetch marks: 2500/5000, consumerTag=33, session=anonymous(26960027), resendQueue=false]}
- // Note: In the last request to take the message from thread 4,5 the message has been
- // taken by the previous call done by thread 2,5
-
-
- return;
- }
- //Deliver the message
- s.send(entry, _queue);
- }
- else
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + " Subscription(" + System.identityHashCode(s) + ") became " +
- "suspended between nextSubscriber and send for message:" + entry.getMessage().debugIdentity());
- }
- }
- }
-
- //
- // Why do we do this? What was the reasoning? We should have a better approach
- // than recursion and rejecting if someone else sends it before we do.
- //
- if (!entry.isTaken())
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + " Message(" + entry.getMessage().debugIdentity() + ") has not been taken so recursing!:" +
- " Subscriber:" + System.identityHashCode(s));
- }
-
- deliver(context, name, entry, deliverFirst);
- }
- else
- {
- if (debugEnabled)
- {
- _log.debug(debugIdentity() + " Message(" + entry.toString() +
- ") has been taken so disregarding deliver request to Subscriber:" +
- System.identityHashCode(s));
- }
- }
- }
-
- }
- finally
- {
- //ensure lock is released
- if (_lock.isHeldByCurrentThread())
- {
- _lock.unlock();
- }
- }
- }
-
- private final String id = "(" + String.valueOf(System.identityHashCode(this)) + ")";
-
- private String debugIdentity()
- {
- return id;
- }
-
- final Runner _asyncDelivery = new Runner();
-
- private class Runner implements Runnable
- {
- public void run()
- {
- String startName = Thread.currentThread().getName();
- Thread.currentThread().setName("CSDM-AsyncDelivery:" + startName);
- boolean running = true;
- while (running && !_movingMessages.get())
- {
- processQueue();
-
- //Check that messages have not been added since we did our last peek();
- // Synchronize with the thread that adds to the queue.
- // If the queue is still empty then we can exit
- synchronized (_asyncDelivery)
- {
- if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers()))
- {
- running = false;
- _processing.set(false);
- }
- }
- }
- Thread.currentThread().setName(startName);
- }
- }
-
- public void processAsync(Executor executor)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Processing Async." + currentStatus());
- }
-
- synchronized (_asyncDelivery)
- {
- if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers())
- {
- //are we already running? if so, don't re-run
- if (_processing.compareAndSet(false, true))
- {
- if (_log.isDebugEnabled())
- {
- _log.debug(debugIdentity() + "Executing Async process.");
- }
- executor.execute(_asyncDelivery);
- }
- }
- }
- }
-
- private String currentStatus()
- {
- return " Queued:" + (_messages.isEmpty() ? "Empty " : "Contains(H:M)") +
- "(" + ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize() +
- ":" + (_messages.size() - ((ConcurrentLinkedMessageQueueAtomicSize) _messages).headSize()) + ") " +
- " Extra: " + (_hasContent.isEmpty() ? "Empty " : "Contains") +
- "(" + _hasContent.size() + ":" + _extraMessages.get() + ") " +
- " Active:" + _subscriptions.hasActiveSubscribers() +
- " Processing:" + (_processing.get() ? " true : Processing Thread: " + _processingThreadName : " false");
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java
deleted file mode 100644
index 1568f58e2e..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.StoreContext;
-
-interface DeliveryManager
-{
- /**
- * Determines whether there are queued messages. Sets _queueing to false if there are no queued messages. This needs
- * to be atomic.
- *
- * @return true if there are queued messages
- */
- boolean hasQueuedMessages();
-
- /**
- * This method should not be used to determin if there are messages in the queue.
- *
- * @return int The number of messages in the queue
- *
- * @use hasQueuedMessages() for all controls relating to having messages on the queue.
- */
- int getQueueMessageCount();
-
- /**
- * Requests that the delivery manager start processing the queue asynchronously if there is work that can be done
- * (i.e. there are messages queued up and subscribers that can receive them. <p/> This should be called when
- * subscribers are added, but only after the consume-ok message has been returned as message delivery may start
- * immediately. It should also be called after unsuspending a client. <p/>
- *
- * @param executor the executor on which the delivery should take place
- */
- void processAsync(Executor executor);
-
- /**
- * Handles message delivery. The delivery manager is always in one of two modes; it is either queueing messages for
- * asynchronous delivery or delivering directly.
- *
- * @param storeContext
- * @param name the name of the entity on whose behalf we are delivering the message
- * @param entry the message to deliver
- * @param deliverFirst
- *
- * @throws org.apache.qpid.server.queue.FailedDequeueException
- * if the message could not be dequeued
- */
- void deliver(StoreContext storeContext, AMQShortString name, QueueEntry entry, boolean deliverFirst) throws FailedDequeueException, AMQException;
-
- void removeAMessageFromTop(StoreContext storeContext, AMQQueue queue) throws AMQException;
-
- long clearAllMessages(StoreContext storeContext) throws AMQException;
-
- void startMovingMessages();
-
- void enqueueMovedMessages(StoreContext context, List<QueueEntry> messageList);
-
- void stopMovingMessages();
-
- void removeMovedMessages(List<QueueEntry> messageListToRemove);
-
- List<QueueEntry> getMessages();
-
- List<QueueEntry> getMessages(long fromMessageId, long toMessageId);
-
- void populatePreDeliveryQueue(Subscription subscription);
-
- boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException;
-
- long getTotalMessageSize();
-
- long getOldestMessageArrival();
-
- void subscriberHasPendingResend(boolean hasContent, Subscription subscription, QueueEntry msg);
-
- void removeExpired() throws AMQException;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
index e6377b33da..d2e5a02508 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
@@ -109,9 +109,9 @@ class ExchangeBindings
}
- public void remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange)
+ public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange)
{
- _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments));
+ return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments));
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java
new file mode 100644
index 0000000000..d38932bb61
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java
@@ -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.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.AMQException;
+
+public interface Filterable<E extends Exception>
+{
+ ContentHeaderBody getContentHeaderBody() throws E;
+
+ boolean isPersistent() throws E;
+
+ boolean isRedelivered();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
index 0b40f01f1a..35ad5be4e0 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
@@ -22,11 +22,10 @@ package org.apache.qpid.server.queue;
import java.util.LinkedList;
import java.util.List;
+import java.util.Collections;
import java.util.ArrayList;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ContentChunk;
@@ -41,32 +40,40 @@ public class InMemoryMessageHandle implements AMQMessageHandle
private MessagePublishInfo _messagePublishInfo;
- private List<ContentChunk> _contentBodies = new ArrayList<ContentChunk>();
+ private List<ContentChunk> _contentBodies;
private boolean _redelivered;
private long _arrivalTime;
- public InMemoryMessageHandle()
+ private final Long _messageId;
+
+ public InMemoryMessageHandle(final Long messageId)
{
+ _messageId = messageId;
}
- public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException
+ public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException
{
return _contentHeaderBody;
}
- public int getBodyCount(StoreContext context, Long messageId)
+ public Long getMessageId()
+ {
+ return _messageId;
+ }
+
+ public int getBodyCount(StoreContext context)
{
return _contentBodies.size();
}
- public long getBodySize(StoreContext context, Long messageId) throws AMQException
+ public long getBodySize(StoreContext context) throws AMQException
{
- return getContentHeaderBody(context, messageId).bodySize;
+ return getContentHeaderBody(context).bodySize;
}
- public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException
+ public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException
{
if (index > _contentBodies.size() - 1)
{
@@ -76,13 +83,28 @@ public class InMemoryMessageHandle implements AMQMessageHandle
return _contentBodies.get(index);
}
- public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentBody, boolean isLastContentBody)
+ public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody)
throws AMQException
{
- _contentBodies.add(contentBody);
+ if(_contentBodies == null)
+ {
+ if(isLastContentBody)
+ {
+ _contentBodies = Collections.singletonList(contentBody);
+ }
+ else
+ {
+ _contentBodies = new ArrayList<ContentChunk>();
+ _contentBodies.add(contentBody);
+ }
+ }
+ else
+ {
+ _contentBodies.add(contentBody);
+ }
}
- public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException
+ public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException
{
return _messagePublishInfo;
}
@@ -98,12 +120,9 @@ public class InMemoryMessageHandle implements AMQMessageHandle
_redelivered = redelivered;
}
- public boolean isPersistent(StoreContext context, Long messageId) throws AMQException
+ public boolean isPersistent()
{
- //todo remove literal values to a constant file such as AMQConstants in common
- ContentHeaderBody chb = getContentHeaderBody(context, messageId);
- return chb.properties instanceof BasicContentHeaderProperties &&
- ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2;
+ return false;
}
/**
@@ -112,26 +131,20 @@ public class InMemoryMessageHandle implements AMQMessageHandle
* @param contentHeaderBody
* @throws AMQException
*/
- public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo messagePublishInfo,
+ public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo,
ContentHeaderBody contentHeaderBody)
throws AMQException
{
_messagePublishInfo = messagePublishInfo;
_contentHeaderBody = contentHeaderBody;
+ if(contentHeaderBody.bodySize == 0)
+ {
+ _contentBodies = Collections.EMPTY_LIST;
+ }
_arrivalTime = System.currentTimeMillis();
}
- public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
- {
- // NO OP
- }
-
- public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException
- {
- // NO OP
- }
-
- public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException
+ public void removeMessage(StoreContext storeContext) throws AMQException
{
// NO OP
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
new file mode 100644
index 0000000000..9d769d7582
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
@@ -0,0 +1,336 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.exchange.NoRouteException;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.AMQException;
+import org.apache.log4j.Logger;
+
+import java.util.Collection;
+
+public class IncomingMessage implements Filterable<RuntimeException>
+{
+
+ /** Used for debugging purposes. */
+ private static final Logger _logger = Logger.getLogger(IncomingMessage.class);
+
+ private static final boolean SYNCHED_CLOCKS =
+ ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false);
+
+ private final MessagePublishInfo _messagePublishInfo;
+ private ContentHeaderBody _contentHeaderBody;
+ private AMQMessageHandle _messageHandle;
+ private final Long _messageId;
+ private final TransactionalContext _txnContext;
+
+
+
+ /**
+ * Keeps a track of how many bytes we have received in body frames
+ */
+ private long _bodyLengthReceived = 0;
+
+ /**
+ * This is stored during routing, to know the queues to which this message should immediately be
+ * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done
+ * by the message handle.
+ */
+ private Collection<AMQQueue> _destinationQueues;
+
+ private AMQProtocolSession _publisher;
+ private MessageStore _messageStore;
+ private long _expiration;
+
+ private Exchange _exchange;
+
+
+ public IncomingMessage(final Long messageId,
+ final MessagePublishInfo info,
+ final TransactionalContext txnContext,
+ final AMQProtocolSession publisher)
+ {
+ _messageId = messageId;
+ _messagePublishInfo = info;
+ _txnContext = txnContext;
+ _publisher = publisher;
+
+ }
+
+ public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException
+ {
+ _contentHeaderBody = contentHeaderBody;
+ }
+
+ public void setExpiration()
+ {
+ long expiration =
+ ((BasicContentHeaderProperties) _contentHeaderBody.properties).getExpiration();
+ long timestamp =
+ ((BasicContentHeaderProperties) _contentHeaderBody.properties).getTimestamp();
+
+ if (SYNCHED_CLOCKS)
+ {
+ _expiration = expiration;
+ }
+ else
+ {
+ // Update TTL to be in broker time.
+ if (expiration != 0L)
+ {
+ if (timestamp != 0L)
+ {
+ // todo perhaps use arrival time
+ long diff = (System.currentTimeMillis() - timestamp);
+
+ if ((diff > 1000L) || (diff < 1000L))
+ {
+ _expiration = expiration + diff;
+ }
+ }
+ }
+ }
+
+ }
+
+ public void routingComplete(final MessageStore store,
+ final MessageHandleFactory factory) throws AMQException
+ {
+
+ final boolean persistent = isPersistent();
+ _messageHandle = factory.createMessageHandle(_messageId, store, persistent);
+ if (persistent)
+ {
+ _txnContext.beginTranIfNecessary();
+ // enqueuing the messages ensure that if required the destinations are recorded to a
+ // persistent store
+
+ if(_destinationQueues != null)
+ {
+ for (AMQQueue q : _destinationQueues)
+ {
+ if(q.isDurable())
+ {
+
+ _messageStore.enqueueMessage(_txnContext.getStoreContext(), q, _messageId);
+ }
+ }
+ }
+
+ }
+
+
+
+
+ }
+
+ public AMQMessage deliverToQueues()
+ throws AMQException
+ {
+
+ // we get a reference to the destination queues now so that we can clear the
+ // transient message data as quickly as possible
+ Collection<AMQQueue> destinationQueues = _destinationQueues;
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Delivering message " + _messageId + " to " + destinationQueues);
+ }
+
+ AMQMessage message = null;
+
+ try
+ {
+ // first we allow the handle to know that the message has been fully received. This is useful if it is
+ // maintaining any calculated values based on content chunks
+ _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(),
+ _messagePublishInfo, getContentHeaderBody());
+
+
+ message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo);
+
+ message.setExpiration(_expiration);
+ message.setClientIdentifier(_publisher.getSessionIdentifier());
+
+
+
+
+ if ((destinationQueues == null) || destinationQueues.isEmpty())
+ {
+
+ if (isMandatory() || isImmediate())
+ {
+ throw new NoRouteException("No Route for message", message);
+
+ }
+ else
+ {
+ _logger.warn("MESSAGE DISCARDED: No routes for message - " + message);
+ }
+ }
+ else
+ {
+ // TODO
+
+ int offset;
+ final int queueCount = destinationQueues.size();
+ if(queueCount == 1)
+ {
+ offset = 0;
+ }
+ else
+ {
+ offset = ((int)(message.getMessageId().longValue())) % queueCount;
+ if(offset < 0)
+ {
+ offset = -offset;
+ }
+ }
+
+ int i = 0;
+ for (AMQQueue q : destinationQueues)
+ {
+ if(++i > offset)
+ {
+ // Increment the references to this message for each queue delivery.
+ message.incrementReference();
+ // normal deliver so add this message at the end.
+ _txnContext.deliver(q, message);
+ }
+ }
+ i = 0;
+ if(offset != 0)
+ {
+ for (AMQQueue q : destinationQueues)
+ {
+ if(i++ < offset)
+ {
+ // Increment the references to this message for each queue delivery.
+ message.incrementReference();
+ // normal deliver so add this message at the end.
+ _txnContext.deliver(q, message);
+ }
+ }
+ }
+
+ }
+
+ // we then allow the transactional context to do something with the message content
+ // now that it has all been received, before we attempt delivery
+ _txnContext.messageFullyReceived(isPersistent());
+ message.clearStoreContext();
+ return message;
+ }
+ finally
+ {
+ // Remove refence for routing process . Reference count should now == delivered queue count
+ if(message != null) message.decrementReference(_txnContext.getStoreContext());
+ }
+
+ }
+
+ public void addContentBodyFrame(final ContentChunk contentChunk)
+ throws AMQException
+ {
+
+ _bodyLengthReceived += contentChunk.getSize();
+
+ _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived());
+
+ }
+
+ public boolean allContentReceived()
+ {
+ return (_bodyLengthReceived == getContentHeaderBody().bodySize);
+ }
+
+ public AMQShortString getExchange() throws AMQException
+ {
+ return _messagePublishInfo.getExchange();
+ }
+
+ public AMQShortString getRoutingKey() throws AMQException
+ {
+ return _messagePublishInfo.getRoutingKey();
+ }
+
+ public boolean isMandatory() throws AMQException
+ {
+ return _messagePublishInfo.isMandatory();
+ }
+
+
+ public boolean isImmediate() throws AMQException
+ {
+ return _messagePublishInfo.isImmediate();
+ }
+
+ public ContentHeaderBody getContentHeaderBody()
+ {
+ return _contentHeaderBody;
+ }
+
+
+ public boolean isPersistent()
+ {
+ //todo remove literal values to a constant file such as AMQConstants in common
+ return getContentHeaderBody().properties instanceof BasicContentHeaderProperties &&
+ ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2;
+ }
+
+ public boolean isRedelivered()
+ {
+ return false;
+ }
+
+ public void setMessageStore(final MessageStore messageStore)
+ {
+ _messageStore = messageStore;
+ }
+
+ public Long getMessageId()
+ {
+ return _messageId;
+ }
+
+ public void setExchange(final Exchange e)
+ {
+ _exchange = e;
+ }
+
+ public void route() throws AMQException
+ {
+ _exchange.route(this);
+ }
+
+ public void enqueue(final Collection<AMQQueue> queues)
+ {
+ _destinationQueues = queues;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java
index 061ab56024..2bc94995e9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java
@@ -126,7 +126,7 @@ public interface ManagedQueue
* @param age maximum age of message.
* @throws IOException
*/
- @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on thr broker")
+ @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on the broker")
void setMaximumMessageAge(Long age) throws IOException;
/**
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java
index 94ab935115..0b214ca336 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java
@@ -36,11 +36,11 @@ public class MessageHandleFactory
// just hardcoded for now
if (persistent)
{
- return new WeakReferenceMessageHandle(store);
+ return new WeakReferenceMessageHandle(messageId, store);
}
else
{
- return new InMemoryMessageHandle();
+ return new InMemoryMessageHandle(messageId);
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
index 12d6c5998a..6f9efd3200 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
@@ -1,129 +1,138 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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;
-
-public enum NotificationCheck
-{
-
- MESSAGE_COUNT_ALERT
- {
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
- {
- int msgCount;
- final long maximumMessageCount = queue.getMaximumMessageCount();
- if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount)
- {
- listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached.");
- return true;
- }
- return false;
- }
- },
- MESSAGE_SIZE_ALERT(true)
- {
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
- {
- final long maximumMessageSize = queue.getMaximumMessageSize();
- if(maximumMessageSize != 0)
- {
- // Check for threshold message size
- long messageSize = (msg == null) ? 0 : msg.getSize();
-
- if (messageSize >= maximumMessageSize)
- {
- listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]");
- return true;
- }
- }
- return false;
- }
-
- },
- QUEUE_DEPTH_ALERT
- {
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
- {
- // Check for threshold queue depth in bytes
- final long maximumQueueDepth = queue.getMaximumQueueDepth();
-
- if(maximumQueueDepth != 0)
- {
- final long queueDepth = queue.getQueueDepth();
-
- if (queueDepth >= maximumQueueDepth)
- {
- listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached.");
- return true;
- }
- }
- return false;
- }
-
- },
- MESSAGE_AGE_ALERT
- {
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
- {
-
- final long maxMessageAge = queue.getMaximumMessageAge();
- if(maxMessageAge != 0)
- {
- final long currentTime = System.currentTimeMillis();
- final long thresholdTime = currentTime - maxMessageAge;
- final long firstArrivalTime = queue.getOldestMessageArrivalTime();
-
- if(firstArrivalTime < thresholdTime)
- {
- long oldestAge = currentTime - firstArrivalTime;
- listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached.");
-
- return true;
- }
- }
- return false;
-
- }
-
- }
- ;
-
- private final boolean _messageSpecific;
-
- NotificationCheck()
- {
- this(false);
- }
-
- NotificationCheck(boolean messageSpecific)
- {
- _messageSpecific = messageSpecific;
- }
-
- public boolean isMessageSpecific()
- {
- return _messageSpecific;
- }
-
- abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener);
-
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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;
+
+public enum NotificationCheck
+{
+
+ MESSAGE_COUNT_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ int msgCount;
+ final long maximumMessageCount = queue.getMaximumMessageCount();
+ if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount)
+ {
+ listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached.");
+ return true;
+ }
+ return false;
+ }
+ },
+ MESSAGE_SIZE_ALERT(true)
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ final long maximumMessageSize = queue.getMaximumMessageSize();
+ if(maximumMessageSize != 0)
+ {
+ // Check for threshold message size
+ long messageSize;
+ try
+ {
+ messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize;
+ }
+ catch (AMQException e)
+ {
+ messageSize = 0;
+ }
+
+
+ if (messageSize >= maximumMessageSize)
+ {
+ listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ },
+ QUEUE_DEPTH_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ // Check for threshold queue depth in bytes
+ final long maximumQueueDepth = queue.getMaximumQueueDepth();
+
+ if(maximumQueueDepth != 0)
+ {
+ final long queueDepth = queue.getQueueDepth();
+
+ if (queueDepth >= maximumQueueDepth)
+ {
+ listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached.");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ },
+ MESSAGE_AGE_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+
+ final long maxMessageAge = queue.getMaximumMessageAge();
+ if(maxMessageAge != 0)
+ {
+ final long currentTime = System.currentTimeMillis();
+ final long thresholdTime = currentTime - maxMessageAge;
+ final long firstArrivalTime = queue.getOldestMessageArrivalTime();
+
+ if(firstArrivalTime < thresholdTime)
+ {
+ long oldestAge = currentTime - firstArrivalTime;
+ listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached.");
+
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ }
+ ;
+
+ private final boolean _messageSpecific;
+
+ NotificationCheck()
+ {
+ this(false);
+ }
+
+ NotificationCheck(boolean messageSpecific)
+ {
+ _messageSpecific = messageSpecific;
+ }
+
+ public boolean isMessageSpecific()
+ {
+ return _messageSpecific;
+ }
+
+ abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener);
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
new file mode 100644
index 0000000000..e6628832cb
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
@@ -0,0 +1,164 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.framing.CommonContentHeaderProperties;
+import org.apache.qpid.AMQException;
+
+public class PriorityQueueList implements QueueEntryList
+{
+ private final AMQQueue _queue;
+ private final QueueEntryList[] _priorityLists;
+ private final int _priorities;
+ private final int _priorityOffset;
+
+ public PriorityQueueList(AMQQueue queue, int priorities)
+ {
+ _queue = queue;
+ _priorityLists = new QueueEntryList[priorities];
+ _priorities = priorities;
+ _priorityOffset = 5-((priorities + 1)/2);
+ for(int i = 0; i < priorities; i++)
+ {
+ _priorityLists[i] = new SimpleQueueEntryList(queue);
+ }
+ }
+
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ public QueueEntry add(AMQMessage message)
+ {
+ try
+ {
+ int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset;
+ if(index >= _priorities)
+ {
+ index = _priorities-1;
+ }
+ else if(index < 0)
+ {
+ index = 0;
+ }
+ return _priorityLists[index].add(message);
+ }
+ catch (AMQException e)
+ {
+ // TODO - fix AMQ Exception
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public QueueEntry next(QueueEntry node)
+ {
+ QueueEntryImpl nodeImpl = (QueueEntryImpl)node;
+ QueueEntry next = nodeImpl.getNext();
+
+ if(next == null)
+ {
+ QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList();
+ int index;
+ for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--);
+
+ while(next == null && index != 0)
+ {
+ index--;
+ next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext();
+ }
+
+ }
+ return next;
+ }
+
+ private final class PriorityQueueEntryListIterator implements QueueEntryIterator
+ {
+ private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ];
+ private QueueEntry _lastNode;
+
+ PriorityQueueEntryListIterator()
+ {
+ for(int i = 0; i < _priorityLists.length; i++)
+ {
+ _iterators[i] = _priorityLists[i].iterator();
+ }
+ _lastNode = _iterators[_iterators.length - 1].getNode();
+ }
+
+
+ public boolean atTail()
+ {
+ for(int i = 0; i < _iterators.length; i++)
+ {
+ if(!_iterators[i].atTail())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public QueueEntry getNode()
+ {
+ return _lastNode;
+ }
+
+ public boolean advance()
+ {
+ for(int i = _iterators.length-1; i >= 0; i--)
+ {
+ if(_iterators[i].advance())
+ {
+ _lastNode = _iterators[i].getNode();
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public QueueEntryIterator iterator()
+ {
+ return new PriorityQueueEntryListIterator();
+ }
+
+ public QueueEntry getHead()
+ {
+ return _priorityLists[_priorities-1].getHead();
+ }
+
+ static class Factory implements QueueEntryListFactory
+ {
+ private final int _priorities;
+
+ Factory(int priorities)
+ {
+ _priorities = priorities;
+ }
+
+ public QueueEntryList createQueueEntryList(AMQQueue queue)
+ {
+ return new PriorityQueueList(queue, _priorities);
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index 8553db3e09..dd967a7cb1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -1,173 +1,186 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.store.StoreContext;
-import org.apache.log4j.Logger;
-
-import java.util.Set;
-import java.util.HashSet;
-import java.util.concurrent.atomic.AtomicReference;
-
+import org.apache.qpid.server.subscription.Subscription;
-public class QueueEntry
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public interface QueueEntry extends Comparable<QueueEntry>
{
- /**
- * Used for debugging purposes.
- */
- private static final Logger _log = Logger.getLogger(QueueEntry.class);
-
- private final AMQQueue _queue;
- private final AMQMessage _message;
- private Set<Subscription> _rejectedBy = null;
- private AtomicReference<Object> _owner = new AtomicReference<Object>();
-
-
- public QueueEntry(AMQQueue queue, AMQMessage message)
+ public static enum State
{
- _queue = queue;
- _message = message;
+ AVAILABLE,
+ ACQUIRED,
+ EXPIRED,
+ DEQUEUED,
+ DELETED
}
-
- public AMQQueue getQueue()
+ public static interface StateChangeListener
{
- return _queue;
+ public void stateChanged(QueueEntry entry, State oldSate, State newState);
}
- public AMQMessage getMessage()
+ public abstract class EntryState
{
- return _message;
- }
+ private EntryState()
+ {
+ }
- public long getSize()
- {
- return getMessage().getSize();
+ public abstract State getState();
}
- public boolean getDeliveredToConsumer()
- {
- return getMessage().getDeliveredToConsumer();
- }
- public boolean expired() throws AMQException
+ public final class AvailableState extends EntryState
{
- return getMessage().expired(_queue);
- }
- public boolean isTaken()
- {
- return _owner.get() != null;
+ public State getState()
+ {
+ return State.AVAILABLE;
+ }
}
- public boolean taken(Subscription sub)
- {
- return !(_owner.compareAndSet(null, sub == null ? this : sub));
- }
- public void setDeliveredToConsumer()
+ public final class DequeuedState extends EntryState
{
- getMessage().setDeliveredToConsumer();
- }
- public void release()
- {
- _owner.set(null);
+ public State getState()
+ {
+ return State.DEQUEUED;
+ }
}
- public String debugIdentity()
- {
- return getMessage().debugIdentity();
- }
- public void process(StoreContext storeContext, boolean deliverFirst) throws AMQException
+ public final class DeletedState extends EntryState
{
- _queue.process(storeContext, this, deliverFirst);
- }
- public void checkDeliveredToConsumer() throws NoConsumersException
- {
- _message.checkDeliveredToConsumer();
+ public State getState()
+ {
+ return State.DELETED;
+ }
}
- public void setRedelivered(boolean b)
+ public final class ExpiredState extends EntryState
{
- getMessage().setRedelivered(b);
- }
- public Subscription getDeliveredSubscription()
- {
- synchronized (this)
+ public State getState()
{
- Object owner = _owner.get();
- if (owner instanceof Subscription)
- {
- return (Subscription) owner;
- }
- else
- {
- return null;
- }
+ return State.EXPIRED;
}
}
- public void reject()
+
+ public final class NonSubscriptionAcquiredState extends EntryState
{
- reject(getDeliveredSubscription());
+ public State getState()
+ {
+ return State.ACQUIRED;
+ }
}
- public void reject(Subscription subscription)
+ public final class SubscriptionAcquiredState extends EntryState
{
- if (subscription != null)
- {
- if (_rejectedBy == null)
- {
- _rejectedBy = new HashSet<Subscription>();
- }
+ private final Subscription _subscription;
- _rejectedBy.add(subscription);
- }
- else
+ public SubscriptionAcquiredState(Subscription subscription)
{
- _log.warn("Requesting rejection by null subscriber:" + debugIdentity());
+ _subscription = subscription;
}
- }
- public boolean isRejectedBy(Subscription subscription)
- {
- boolean rejected = _rejectedBy != null;
- if (rejected) // We have subscriptions that rejected this message
+ public State getState()
{
- return _rejectedBy.contains(subscription);
+ return State.ACQUIRED;
}
- else // This messasge hasn't been rejected yet.
+
+ public Subscription getSubscription()
{
- return rejected;
+ return _subscription;
}
}
+ final static EntryState AVAILABLE_STATE = new AvailableState();
+ final static EntryState DELETED_STATE = new DeletedState();
+ final static EntryState DEQUEUED_STATE = new DequeuedState();
+ final static EntryState EXPIRED_STATE = new ExpiredState();
+ final static EntryState NON_SUBSCRIPTION_ACQUIRED_STATE = new NonSubscriptionAcquiredState();
+
+
+
+
+ AMQQueue getQueue();
+
+ AMQMessage getMessage();
+
+ long getSize();
+
+ boolean getDeliveredToConsumer();
+
+ boolean expired() throws AMQException;
+
+ boolean isAcquired();
+
+ boolean acquire();
+ boolean acquire(Subscription sub);
+
+ boolean delete();
+ boolean isDeleted();
+
+ boolean acquiredBySubscription();
+
+ void setDeliveredToSubscription();
+
+ void release();
+
+ String debugIdentity();
+
+ boolean immediateAndNotDelivered();
+
+ void setRedelivered(boolean b);
+
+ Subscription getDeliveredSubscription();
+
+ void reject();
+
+ void reject(Subscription subscription);
+
+ boolean isRejectedBy(Subscription subscription);
+
+ void requeue(StoreContext storeContext) throws AMQException;
+
+ void dequeue(final StoreContext storeContext) throws FailedDequeueException;
+
+ void dispose(final StoreContext storeContext) throws MessageCleanupException;
+
+ void restoreCredit();
+
+ void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException;
+
+ boolean isQueueDeleted();
+
+ void addStateChangeListener(StateChangeListener listener);
+ boolean removeStateChangeListener(StateChangeListener listener);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
new file mode 100644
index 0000000000..d26d6af7b2
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -0,0 +1,392 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.server.store.StoreContext;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.log4j.Logger;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+
+public class QueueEntryImpl implements QueueEntry
+{
+
+ /**
+ * Used for debugging purposes.
+ */
+ private static final Logger _log = Logger.getLogger(QueueEntryImpl.class);
+
+ private final SimpleQueueEntryList _queueEntryList;
+
+ private AMQMessage _message;
+
+
+ private Set<Subscription> _rejectedBy = null;
+
+ private volatile EntryState _state = AVAILABLE_STATE;
+
+ private static final
+ AtomicReferenceFieldUpdater<QueueEntryImpl, EntryState>
+ _stateUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (QueueEntryImpl.class, EntryState.class, "_state");
+
+
+ private volatile Set<StateChangeListener> _stateChangeListeners;
+
+ private static final
+ AtomicReferenceFieldUpdater<QueueEntryImpl, Set>
+ _listenersUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (QueueEntryImpl.class, Set.class, "_stateChangeListeners");
+
+
+ private static final
+ AtomicLongFieldUpdater<QueueEntryImpl>
+ _entryIdUpdater =
+ AtomicLongFieldUpdater.newUpdater
+ (QueueEntryImpl.class, "_entryId");
+
+
+ private volatile long _entryId;
+
+ volatile QueueEntryImpl _next;
+
+
+ QueueEntryImpl(SimpleQueueEntryList queueEntryList)
+ {
+ this(queueEntryList,null,Long.MIN_VALUE);
+ _state = DELETED_STATE;
+ }
+
+
+ public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId)
+ {
+ _queueEntryList = queueEntryList;
+ _message = message;
+
+ _entryIdUpdater.set(this, entryId);
+ }
+
+ public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message)
+ {
+ _queueEntryList = queueEntryList;
+ _message = message;
+ }
+
+ protected void setEntryId(long entryId)
+ {
+ _entryIdUpdater.set(this, entryId);
+ }
+
+ protected long getEntryId()
+ {
+ return _entryId;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return _queueEntryList.getQueue();
+ }
+
+ public AMQMessage getMessage()
+ {
+ return _message;
+ }
+
+ public long getSize()
+ {
+ return getMessage().getSize();
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return getMessage().getDeliveredToConsumer();
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return getMessage().expired(getQueue());
+ }
+
+ public boolean isAcquired()
+ {
+ return _state.getState() == State.ACQUIRED;
+ }
+
+ public boolean acquire()
+ {
+ return acquire(NON_SUBSCRIPTION_ACQUIRED_STATE);
+ }
+
+ private boolean acquire(final EntryState state)
+ {
+ boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state);
+ if(acquired && _stateChangeListeners != null)
+ {
+ notifyStateChange(State.AVAILABLE, State.ACQUIRED);
+ }
+
+ return acquired;
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return acquire(sub.getOwningState());
+ }
+
+ public boolean acquiredBySubscription()
+ {
+
+ return (_state instanceof SubscriptionAcquiredState);
+ }
+
+ public void setDeliveredToSubscription()
+ {
+ getMessage().setDeliveredToConsumer();
+ }
+
+ public void release()
+ {
+ _stateUpdater.set(this,AVAILABLE_STATE);
+ }
+
+ public String debugIdentity()
+ {
+ return getMessage().debugIdentity();
+ }
+
+
+ public boolean immediateAndNotDelivered()
+ {
+ return _message.immediateAndNotDelivered();
+ }
+
+ public void setRedelivered(boolean b)
+ {
+ getMessage().setRedelivered(b);
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ EntryState state = _state;
+ if (state instanceof SubscriptionAcquiredState)
+ {
+ return ((SubscriptionAcquiredState) state).getSubscription();
+ }
+ else
+ {
+ return null;
+ }
+
+ }
+
+ public void reject()
+ {
+ reject(getDeliveredSubscription());
+ }
+
+ public void reject(Subscription subscription)
+ {
+ if (subscription != null)
+ {
+ if (_rejectedBy == null)
+ {
+ _rejectedBy = new HashSet<Subscription>();
+ }
+
+ _rejectedBy.add(subscription);
+ }
+ else
+ {
+ _log.warn("Requesting rejection by null subscriber:" + debugIdentity());
+ }
+ }
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+
+ if (_rejectedBy != null) // We have subscriptions that rejected this message
+ {
+ return _rejectedBy.contains(subscription);
+ }
+ else // This messasge hasn't been rejected yet.
+ {
+ return false;
+ }
+ }
+
+
+ public void requeue(final StoreContext storeContext) throws AMQException
+ {
+ getQueue().requeue(storeContext, this);
+ if(_stateChangeListeners != null)
+ {
+ notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
+ }
+ }
+
+ public void dequeue(final StoreContext storeContext) throws FailedDequeueException
+ {
+ EntryState state = _state;
+
+ if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE))
+ {
+ getQueue().dequeue(storeContext, this);
+ if(_stateChangeListeners != null)
+ {
+ notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED);
+ }
+
+ }
+
+ }
+
+ private void notifyStateChange(final State oldState, final State newState)
+ {
+ for(StateChangeListener l : _stateChangeListeners)
+ {
+ l.stateChanged(this, oldState, newState);
+ }
+ }
+
+ public void dispose(final StoreContext storeContext) throws MessageCleanupException
+ {
+ if(delete())
+ {
+ getMessage().decrementReference(storeContext);
+ }
+ }
+
+ public void restoreCredit()
+ {
+ EntryState state = _state;
+ if(state instanceof SubscriptionAcquiredState)
+ {
+ Subscription s = ((SubscriptionAcquiredState) _state).getSubscription();
+ s.restoreCredit(this);
+ }
+ }
+
+ public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
+ {
+ //if the queue is null then the message is waiting to be acked, but has been removed.
+ if (getQueue() != null)
+ {
+ dequeue(storeContext);
+ }
+
+ dispose(storeContext);
+ }
+
+ public boolean isQueueDeleted()
+ {
+ return getQueue().isDeleted();
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+ Set<StateChangeListener> listeners = _stateChangeListeners;
+ if(listeners == null)
+ {
+ _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet<StateChangeListener>());
+ listeners = _stateChangeListeners;
+ }
+
+ listeners.add(listener);
+ }
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+ Set<StateChangeListener> listeners = _stateChangeListeners;
+ if(listeners != null)
+ {
+ return listeners.remove(listener);
+ }
+
+ return false;
+ }
+
+
+ public int compareTo(final QueueEntry o)
+ {
+ QueueEntryImpl other = (QueueEntryImpl)o;
+ return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0;
+ }
+
+ public QueueEntryImpl getNext()
+ {
+
+ QueueEntryImpl next = nextNode();
+ while(next != null && next.isDeleted())
+ {
+
+ final QueueEntryImpl newNext = next.nextNode();
+ if(newNext != null)
+ {
+ SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext);
+ next = nextNode();
+ }
+ else
+ {
+ next = null;
+ }
+
+ }
+ return next;
+ }
+
+ QueueEntryImpl nextNode()
+ {
+ return _next;
+ }
+
+ public boolean isDeleted()
+ {
+ return _state == DELETED_STATE;
+ }
+
+ public boolean delete()
+ {
+ EntryState state = _state;
+
+ if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE))
+ {
+ _queueEntryList.advanceHead();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public QueueEntryList getQueueEntryList()
+ {
+ return _queueEntryList;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
new file mode 100644
index 0000000000..c5c115a2d1
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
@@ -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.
+*
+*/
+package org.apache.qpid.server.queue;
+
+public interface QueueEntryIterator
+{
+ boolean atTail();
+
+ QueueEntry getNode();
+
+ boolean advance();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
new file mode 100644
index 0000000000..313e076f61
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -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.
+*
+*/
+package org.apache.qpid.server.queue;
+
+public interface QueueEntryList
+{
+ AMQQueue getQueue();
+
+ QueueEntry add(AMQMessage message);
+
+ QueueEntry next(QueueEntry node);
+
+ QueueEntryIterator iterator();
+
+ QueueEntry getHead();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java
new file mode 100644
index 0000000000..4dbce45f67
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java
@@ -0,0 +1,26 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.queue;
+
+interface QueueEntryListFactory
+{
+ public QueueEntryList createQueueEntryList(AMQQueue queue);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java
index f1e7c98387..959ca03c80 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java
@@ -1,27 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-
-public interface QueueNotificationListener
-{
- void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg);
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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;
+
+
+public interface QueueNotificationListener
+{
+ void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
new file mode 100644
index 0000000000..247402e442
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -0,0 +1,1671 @@
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionList;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.pool.ReadWriteRunnable;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.configuration.Configured;
+import org.apache.log4j.Logger;
+
+import javax.management.JMException;
+import java.util.List;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
+{
+ private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
+
+ private final AMQShortString _name;
+
+ /** null means shared */
+ private final AMQShortString _owner;
+
+ private final boolean _durable;
+
+ /** If true, this queue is deleted when the last subscriber is removed */
+ private final boolean _autoDelete;
+
+ private final VirtualHost _virtualHost;
+
+ /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */
+ private final ExchangeBindings _bindings = new ExchangeBindings(this);
+
+ private final AtomicBoolean _deleted = new AtomicBoolean(false);
+
+ private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>();
+
+ private final AtomicInteger _atomicQueueCount = new AtomicInteger(0);
+
+ private final AtomicLong _atomicQueueSize = new AtomicLong(0L);
+
+ private final AtomicInteger _activeSubscriberCount = new AtomicInteger();
+
+ protected final SubscriptionList _subscriptionList = new SubscriptionList(this);
+ private final AtomicReference<SubscriptionList.SubscriptionNode> _lastSubscriptionNode = new AtomicReference<SubscriptionList.SubscriptionNode>(_subscriptionList.getHead());
+
+ private volatile Subscription _exclusiveSubscriber;
+
+
+ private final QueueEntryList _entries;
+
+
+ private final AMQQueueMBean _managedObject;
+ private final Executor _asyncDelivery;
+ private final AtomicLong _totalMessagesReceived = new AtomicLong();
+
+
+
+ /** max allowed size(KB) of a single message */
+ @Configured(path = "maximumMessageSize", defaultValue = "0")
+ public long _maximumMessageSize;
+
+ /** max allowed number of messages on a queue. */
+ @Configured(path = "maximumMessageCount", defaultValue = "0")
+ public long _maximumMessageCount;
+
+ /** max queue depth for the queue */
+ @Configured(path = "maximumQueueDepth", defaultValue = "0")
+ public long _maximumQueueDepth;
+
+ /** maximum message age before alerts occur */
+ @Configured(path = "maximumMessageAge", defaultValue = "0")
+ public long _maximumMessageAge;
+
+ /** the minimum interval between sending out consequetive alerts of the same type */
+ @Configured(path = "minimumAlertRepeatGap", defaultValue = "0")
+ public long _minimumAlertRepeatGap;
+
+
+
+ private static final int MAX_ASYNC_DELIVERIES = 10;
+
+
+ private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class);
+
+
+ private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE);
+ private AtomicReference _asynchronousRunner = new AtomicReference(null);
+ private AtomicInteger _deliveredMessages = new AtomicInteger();
+
+ protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost)
+ throws AMQException
+ {
+ this(name,durable,owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory());
+ }
+
+ protected SimpleAMQQueue(AMQShortString name,
+ boolean durable,
+ AMQShortString owner,
+ boolean autoDelete,
+ VirtualHost virtualHost,
+ QueueEntryListFactory entryListFactory)
+ throws AMQException
+ {
+
+ if (name == null)
+ {
+ throw new IllegalArgumentException("Queue name must not be null");
+ }
+
+ if (virtualHost == null)
+ {
+ throw new IllegalArgumentException("Virtual Host must not be null");
+ }
+
+ _name = name;
+ _durable = durable;
+ _owner = owner;
+ _autoDelete = autoDelete;
+ _virtualHost = virtualHost;
+ _entries = entryListFactory.createQueueEntryList(this);
+
+ _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService();
+
+ try
+ {
+ _managedObject = new AMQQueueMBean(this);
+ _managedObject.register();
+ }
+ catch (JMException e)
+ {
+ throw new AMQException("AMQQueue MBean creation has failed ", e);
+ }
+
+
+ // This ensure that the notification checks for the configured alerts are created.
+ setMaximumMessageAge(_maximumMessageAge);
+ setMaximumMessageCount(_maximumMessageCount);
+ setMaximumMessageSize(_maximumMessageSize);
+ setMaximumQueueDepth(_maximumQueueDepth);
+
+ }
+
+ // ------ Getters and Setters
+
+ public AMQShortString getName()
+ {
+ return _name;
+ }
+
+ public boolean isDurable()
+ {
+ return _durable;
+ }
+
+ public boolean isAutoDelete()
+ {
+ return _autoDelete;
+ }
+
+ public AMQShortString getOwner()
+ {
+ return _owner;
+ }
+
+ public VirtualHost getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+
+ // ------ bind and unbind
+
+ public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ exchange.registerQueue(routingKey, this, arguments);
+ if (isDurable() && exchange.isDurable())
+ {
+ _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments);
+ }
+
+ _bindings.addBinding(routingKey, arguments, exchange);
+ }
+
+ public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ exchange.deregisterQueue(routingKey, this, arguments);
+ if (isDurable() && exchange.isDurable())
+ {
+ _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments);
+ }
+
+ boolean removed = _bindings.remove(routingKey, arguments, exchange);
+ if(!removed)
+ {
+ _logger.error("Mismatch between queue bindings and exchange record of bindings");
+ }
+ }
+
+
+ // ------ Manage Subscriptions
+
+ public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException
+ {
+
+
+ if(isExclusiveSubscriber())
+ {
+ throw new ExistingExclusiveSubscription();
+ }
+
+ if(exclusive)
+ {
+ if(getConsumerCount() != 0)
+ {
+ throw new ExistingSubscriptionPreventsExclusive();
+ }
+ else
+ {
+ _exclusiveSubscriber = subscription;
+
+ }
+ }
+
+
+ _activeSubscriberCount.incrementAndGet();
+ subscription.setStateListener(this);
+ subscription.setLastSeenEntry(null,_entries.getHead());
+
+ if(!isDeleted())
+ {
+ subscription.setQueue(this);
+ _subscriptionList.add(subscription);
+ if(isDeleted())
+ {
+ subscription.queueDeleted(this);
+ }
+ }
+ else
+ {
+ // TODO
+ }
+
+
+ deliverAsync(subscription);
+
+ }
+
+ public synchronized void unregisterSubscription(final Subscription subscription) throws AMQException
+ {
+ if(subscription == null)
+ {
+ throw new NullPointerException("subscription argument is null");
+ }
+
+ boolean removed = _subscriptionList.remove(subscription);
+
+
+
+ if(removed)
+ {
+ subscription.close();
+ // No longer can the queue have an exclusive consumer
+ setExclusiveSubscriber(null);
+
+
+ QueueEntry lastSeen;
+
+ while((lastSeen = subscription.getLastSeenEntry()) != null)
+ {
+ subscription.setLastSeenEntry(lastSeen, null);
+ }
+
+
+
+
+ // auto-delete queues must be deleted if there are no remaining subscribers
+
+ if (_autoDelete && getConsumerCount() == 0)
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Auto-deleteing queue:" + this);
+ }
+
+ delete();
+
+ // we need to manually fire the event to the removed subscription (which was the last one left for this
+ // queue. This is because the delete method uses the subscription set which has just been cleared
+ subscription.queueDeleted(this);
+ }
+ }
+
+
+ }
+
+
+ // ------ Enqueue / Dequeue
+
+ public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException
+ {
+
+
+
+ incrementQueueCount();
+ incrementQueueSize(message);
+
+ _totalMessagesReceived.incrementAndGet();
+
+
+ QueueEntry entry;
+ Subscription exclusiveSub = _exclusiveSubscriber;
+
+ if(exclusiveSub != null)
+ {
+ exclusiveSub.getSendLock();
+
+ try
+ {
+ entry = _entries.add(message);
+
+ deliverToSubscription(exclusiveSub, entry);
+
+
+ // where there is more than one producer there's a reasonable chance that even though there is
+ // no "queueing" we do not deliver because we get an interleving of _entries.add and
+ // deliverToSubscription between threads. Therefore have one more try.
+ if(!(entry.isAcquired() || entry.isDeleted()))
+ {
+ deliverToSubscription(exclusiveSub, entry);
+ }
+ }
+ finally
+ {
+ exclusiveSub.releaseSendLock();
+ }
+ }
+ else
+ {
+ entry = _entries.add(message);
+ /*
+
+ iterate over subscriptions and if any is at the end of the queue and can deliver this message, then deliver the message
+
+ */
+ SubscriptionList.SubscriptionNode node = _lastSubscriptionNode.get();
+ SubscriptionList.SubscriptionNode nextNode = node.getNext();
+ if(nextNode == null)
+ {
+ nextNode = _subscriptionList.getHead().getNext();
+ }
+ while(nextNode != null)
+ {
+ if(_lastSubscriptionNode.compareAndSet(node, nextNode))
+ {
+ break;
+ }
+ else
+ {
+ node = _lastSubscriptionNode.get();
+ nextNode = node.getNext();
+ if(nextNode == null)
+ {
+ nextNode = _subscriptionList.getHead().getNext();
+ }
+ }
+ }
+
+
+ // always do one extra loop after we believe we've finished
+ // this catches the case where we *just* miss an update
+ int loops = 2;
+
+ while(!(entry.isAcquired() || entry.isDeleted()) && loops != 0)
+ {
+ if(nextNode == null)
+ {
+ loops--;
+ nextNode = _subscriptionList.getHead();
+ }
+ else
+ {
+ // if subscription at end, and active, offer
+ Subscription sub = nextNode.getSubscription();
+ deliverToSubscription(sub, entry);
+ }
+ nextNode = nextNode.getNext();
+
+ }
+ }
+
+
+ if(entry.immediateAndNotDelivered())
+ {
+ dequeue(storeContext, entry);
+ entry.dispose(storeContext);
+ }
+ else if(!(entry.isAcquired() || entry.isDeleted()))
+ {
+ checkSubscriptionsNotAheadOfDelivery(entry);
+
+ deliverAsync();
+ }
+
+
+ try
+ {
+ _managedObject.checkForNotification(entry.getMessage());
+ }
+ catch (JMException e)
+ {
+ throw new AMQException("Unable to get notification from manage queue: " + e, e);
+ }
+
+
+ return entry;
+
+ }
+
+ private void deliverToSubscription(final Subscription sub, final QueueEntry entry)
+ throws AMQException
+ {
+
+ sub.getSendLock();
+ try
+ {
+ if(subscriptionReadyAndHasInterest(sub, entry)
+ && !sub.isSuspended())
+ {
+ if( !sub.wouldSuspend(entry))
+ {
+ if(!sub.isBrowser() && !entry.acquire(sub))
+ {
+ // restore credit here that would have been taken away by wouldSuspend since we didn't manage
+ // to acquire the entry for this subscription
+ sub.restoreCredit(entry);
+ }
+ else
+ {
+
+ deliverMessage(sub, entry);
+
+ }
+ }
+ }
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
+ }
+
+ protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry)
+ {
+ // This method is only required for queues which mess with ordering
+ // Simple Queues don't :-)
+ }
+
+ private void incrementQueueSize(final AMQMessage message)
+ {
+ getAtomicQueueSize().addAndGet(message.getSize());
+ }
+
+ private void incrementQueueCount()
+ {
+ getAtomicQueueCount().incrementAndGet();
+ }
+
+ private void deliverMessage(final Subscription sub, final QueueEntry entry)
+ throws AMQException
+ {
+ _deliveredMessages.incrementAndGet();
+ sub.send(entry);
+
+ }
+
+ private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry)
+ {
+
+ // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no
+ // interest in.
+ QueueEntry node = sub.getLastSeenEntry();
+ while(node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node)) )
+ {
+
+ QueueEntry newNode = _entries.next(node);
+ if(newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
+ node = sub.getLastSeenEntry();
+ }
+ else
+ {
+ node = null;
+ break;
+ }
+
+ }
+
+
+ if(node == entry)
+ {
+ // If the first entry that subscription can process is the one we are trying to deliver to it, then we are
+ // good
+ return true;
+ }
+ else
+ {
+ // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing
+ // no-one else has updated it to something furhter on in the list
+ //TODO - check
+ //updateLastSeenEntry(sub, entry);
+ return false;
+ }
+
+ }
+
+ private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry)
+ {
+ QueueEntry node = sub.getLastSeenEntry();
+
+ if(node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry))
+ {
+ do
+ {
+ if(sub.setLastSeenEntry(node,entry))
+ {
+ return;
+ }
+ else
+ {
+ node = sub.getLastSeenEntry();
+ }
+ } while (node != null && entry.compareTo(node) < 0);
+ }
+
+ }
+
+ public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException
+ {
+
+ SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator();
+ // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards
+ while(subscriberIter.advance())
+ {
+ Subscription sub = subscriberIter.getNode().getSubscription();
+
+ // we don't make browsers send the same stuff twice
+ if(!sub.isBrowser())
+ {
+ updateLastSeenEntry(sub, entry);
+ }
+ }
+
+
+ deliverAsync();
+
+
+ }
+
+ public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException
+ {
+ decrementQueueCount();
+ decrementQueueSize(entry);
+ if(entry.acquiredBySubscription())
+ {
+ _deliveredMessages.decrementAndGet();
+ }
+
+ try
+ {
+ AMQMessage msg = entry.getMessage();
+ if(isDurable() && msg.isPersistent())
+ {
+ _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId());
+ }
+ //entry.dispose(storeContext);
+
+ }
+ catch (MessageCleanupException e)
+ {
+ // Message was dequeued, but could not then be deleted
+ // though it is no longer referenced. This should be very
+ // rare and can be detected and cleaned up on recovery or
+ // done through some form of manual intervention.
+ _logger.error(e, e);
+ }
+ catch (AMQException e)
+ {
+ throw new FailedDequeueException(_name.toString(), e);
+ }
+
+
+ }
+
+ private void decrementQueueSize(final QueueEntry entry)
+ {
+ getAtomicQueueSize().addAndGet(-entry.getMessage().getSize());
+ }
+
+ void decrementQueueCount()
+ {
+ getAtomicQueueCount().decrementAndGet();
+ }
+
+ public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException
+ {
+ /* TODO : This is wrong as the subscription may be suspended, we should instead change the state of the message
+ entry to resend and move back the subscription pointer. */
+
+ subscription.getSendLock();
+ try
+ {
+ if(!subscription.isClosed())
+ {
+ deliverMessage(subscription, entry);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ finally
+ {
+ subscription.releaseSendLock();
+ }
+ }
+
+
+
+
+
+ public int getConsumerCount()
+ {
+ return _subscriptionList.size();
+ }
+
+ public int getActiveConsumerCount()
+ {
+ return _activeSubscriberCount.get();
+ }
+
+ public boolean isUnused()
+ {
+ return getConsumerCount() == 0;
+ }
+
+ public boolean isEmpty()
+ {
+ return getMessageCount() == 0;
+ }
+
+ public int getMessageCount()
+ {
+ return getAtomicQueueCount().get();
+ }
+
+ public long getQueueDepth()
+ {
+ return getAtomicQueueSize().get();
+ }
+
+ public int getUndeliveredMessageCount()
+ {
+ int count = getMessageCount() - _deliveredMessages.get();
+ if(count < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return count;
+ }
+ }
+
+
+ public long getReceivedMessageCount()
+ {
+ return _totalMessagesReceived.get();
+ }
+
+ public long getOldestMessageArrivalTime()
+ {
+ QueueEntry entry = getOldestQueueEntry();
+ return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime();
+ }
+
+ protected QueueEntry getOldestQueueEntry()
+ {
+ return _entries.next(_entries.getHead());
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted.get();
+ }
+
+
+
+ public List<QueueEntry> getMessagesOnTheQueue()
+ {
+ ArrayList<QueueEntry> entryList = new ArrayList<QueueEntry>();
+ QueueEntryIterator queueListIterator = _entries.iterator();
+ while(queueListIterator.advance())
+ {
+ QueueEntry node = queueListIterator.getNode();
+ if(node != null && !node.isDeleted())
+ {
+ entryList.add(node);
+ }
+ }
+ return entryList;
+
+ }
+
+ public void stateChange(Subscription sub, Subscription.State oldState, Subscription.State newState)
+ {
+ if(oldState == Subscription.State.ACTIVE && newState != Subscription.State.ACTIVE)
+ {
+ _activeSubscriberCount.decrementAndGet();
+
+ }
+ else if(newState == Subscription.State.ACTIVE)
+ {
+ if(oldState != Subscription.State.ACTIVE)
+ {
+ _activeSubscriberCount.incrementAndGet();
+
+ }
+ deliverAsync(sub);
+ }
+ }
+
+ public int compareTo(final AMQQueue o)
+ {
+ return _name.compareTo(o.getName());
+ }
+
+ public AtomicInteger getAtomicQueueCount()
+ {
+ return _atomicQueueCount;
+ }
+
+ public AtomicLong getAtomicQueueSize()
+ {
+ return _atomicQueueSize;
+ }
+
+ private boolean isExclusiveSubscriber()
+ {
+ return _exclusiveSubscriber != null;
+ }
+
+ private void setExclusiveSubscriber(Subscription exclusiveSubscriber)
+ {
+ _exclusiveSubscriber = exclusiveSubscriber;
+ }
+
+ public static interface QueueEntryFilter
+ {
+ public boolean accept(QueueEntry entry);
+
+ public boolean filterComplete();
+ }
+
+
+
+ public List<QueueEntry> getMessagesOnTheQueue(final long fromMessageId, final long toMessageId)
+ {
+ return getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+
+ public boolean accept(QueueEntry entry)
+ {
+ final long messageId = entry.getMessage().getMessageId();
+ return messageId >= fromMessageId && messageId <= toMessageId;
+ }
+
+ public boolean filterComplete()
+ {
+ return false;
+ }
+ });
+ }
+
+ public QueueEntry getMessageOnTheQueue(final long messageId)
+ {
+ List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+ private boolean _complete;
+
+ public boolean accept(QueueEntry entry)
+ {
+ _complete = entry.getMessage().getMessageId() == messageId;
+ return _complete;
+ }
+
+ public boolean filterComplete()
+ {
+ return _complete;
+ }
+ });
+ return entries.isEmpty() ? null : entries.get(0);
+ }
+
+
+ public List<QueueEntry> getMessagesOnTheQueue(QueueEntryFilter filter)
+ {
+ ArrayList<QueueEntry> entryList = new ArrayList<QueueEntry>();
+ QueueEntryIterator queueListIterator = _entries.iterator();
+ while(queueListIterator.advance() && !filter.filterComplete())
+ {
+ QueueEntry node = queueListIterator.getNode();
+ if(!node.isDeleted() && filter.accept(node))
+ {
+ entryList.add(node);
+ }
+ }
+ return entryList;
+
+ }
+
+
+ public void moveMessagesToAnotherQueue(final long fromMessageId,
+ final long toMessageId,
+ String queueName,
+ StoreContext storeContext)
+ {
+
+ AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
+ MessageStore store = getVirtualHost().getMessageStore();
+
+
+ List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+
+ public boolean accept(QueueEntry entry)
+ {
+ final long messageId = entry.getMessage().getMessageId();
+ return (messageId >= fromMessageId)
+ && (messageId <= toMessageId)
+ && entry.acquire();
+ }
+
+ public boolean filterComplete()
+ {
+ return false;
+ }
+ });
+
+
+ try
+ {
+ store.beginTran(storeContext);
+
+ // Move the messages in on the message store.
+ for (QueueEntry entry : entries)
+ {
+ AMQMessage message = entry.getMessage();
+
+ if(message.isPersistent() && toQueue.isDurable())
+ {
+ store.enqueueMessage(storeContext, toQueue, message.getMessageId());
+ }
+ // dequeue does not decrement the refence count
+ entry.dequeue(storeContext);
+ }
+
+ // Commit and flush the move transcations.
+ try
+ {
+ store.commitTran(storeContext);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
+ }
+ }
+ catch (AMQException e)
+ {
+ try
+ {
+ store.abortTran(storeContext);
+ }
+ catch (AMQException rollbackEx)
+ {
+ _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx);
+ }
+ throw new RuntimeException(e);
+ }
+
+ try
+ {
+ for (QueueEntry entry : entries)
+ {
+ toQueue.enqueue(storeContext, entry.getMessage());
+
+ }
+ }
+ catch (MessageCleanupException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+
+ }
+
+ public void copyMessagesToAnotherQueue(final long fromMessageId,
+ final long toMessageId,
+ String queueName,
+ final StoreContext storeContext)
+ {
+ AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
+ MessageStore store = getVirtualHost().getMessageStore();
+
+
+ List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+
+ public boolean accept(QueueEntry entry)
+ {
+ final long messageId = entry.getMessage().getMessageId();
+ if((messageId >= fromMessageId)
+ && (messageId <= toMessageId))
+ {
+ if(!entry.isDeleted())
+ {
+ return entry.getMessage().incrementReference();
+ }
+ }
+
+ return false;
+ }
+
+ public boolean filterComplete()
+ {
+ return false;
+ }
+ });
+
+ try
+ {
+ store.beginTran(storeContext);
+
+ // Move the messages in on the message store.
+ for (QueueEntry entry : entries)
+ {
+ AMQMessage message = entry.getMessage();
+
+ if(message.isReferenced() && message.isPersistent() && toQueue.isDurable())
+ {
+ store.enqueueMessage(storeContext, toQueue, message.getMessageId());
+ }
+ }
+
+ // Commit and flush the move transcations.
+ try
+ {
+ store.commitTran(storeContext);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
+ }
+ }
+ catch (AMQException e)
+ {
+ try
+ {
+ store.abortTran(storeContext);
+ }
+ catch (AMQException rollbackEx)
+ {
+ _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx);
+ }
+ throw new RuntimeException(e);
+ }
+
+ try
+ {
+ for (QueueEntry entry : entries)
+ {
+ if(entry.getMessage().isReferenced())
+ {
+ toQueue.enqueue(storeContext, entry.getMessage());
+ }
+ }
+ }
+ catch (MessageCleanupException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+
+ }
+
+ public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext)
+ {
+
+ try
+ {
+ QueueEntryIterator queueListIterator = _entries.iterator();
+
+
+ while(queueListIterator.advance())
+ {
+ QueueEntry node = queueListIterator.getNode();
+
+ final long messageId = node.getMessage().getMessageId();
+
+ if((messageId >= fromMessageId)
+ && (messageId <= toMessageId)
+ && !node.isDeleted()
+ && node.acquire())
+ {
+ node.discard(storeContext);
+ }
+
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ // ------ Management functions
+
+
+ public void deleteMessageFromTop(StoreContext storeContext) throws AMQException
+ {
+ QueueEntryIterator queueListIterator = _entries.iterator();
+ boolean noDeletes = true;
+
+ while(noDeletes && queueListIterator.advance() )
+ {
+ QueueEntry node = queueListIterator.getNode();
+ if(!node.isDeleted() && node.acquire())
+ {
+ node.discard(storeContext);
+ noDeletes = false;
+ }
+
+ }
+ }
+
+ public long clearQueue(StoreContext storeContext) throws AMQException
+ {
+
+ QueueEntryIterator queueListIterator = _entries.iterator();
+ long count = 0;
+
+ while(queueListIterator.advance())
+ {
+ QueueEntry node = queueListIterator.getNode();
+ if(!node.isDeleted() && node.acquire())
+ {
+ node.discard(storeContext);
+ count++;
+ }
+
+ }
+ return count;
+
+ }
+
+
+ public void addQueueDeleteTask(final Task task)
+ {
+ _deleteTaskList.add(task);
+ }
+
+ public int delete() throws AMQException
+ {
+ if (!_deleted.getAndSet(true))
+ {
+
+ SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator();
+
+ while (subscriptionIter.advance())
+ {
+ Subscription s = subscriptionIter.getNode().getSubscription();
+ if(s != null)
+ {
+ s.queueDeleted(this);
+ }
+ }
+
+ _bindings.deregister();
+ _virtualHost.getQueueRegistry().unregisterQueue(_name);
+
+
+ _managedObject.unregister();
+ for (Task task : _deleteTaskList)
+ {
+ task.doTask(this);
+ }
+
+ _deleteTaskList.clear();
+ ReferenceCountingExecutorService.getInstance().releaseExecutorService();
+ }
+ return getMessageCount();
+
+ }
+
+
+ public void deliverAsync()
+ {
+ _stateChangeCount.incrementAndGet();
+
+ Runner runner = new Runner();
+
+ if(_asynchronousRunner.compareAndSet(null,runner))
+ {
+ _asyncDelivery.execute(runner);
+ }
+ }
+
+ public void deliverAsync(Subscription sub)
+ {
+ _asyncDelivery.execute(new SubFlushRunner(sub));
+ }
+
+ private class Runner implements ReadWriteRunnable
+ {
+ public void run()
+ {
+ try
+ {
+ processQueue(this);
+ }
+ catch (AMQException e)
+ {
+ _logger.error(e);
+ }
+
+ }
+
+ public boolean isRead()
+ {
+ return false;
+ }
+
+ public boolean isWrite()
+ {
+ return true;
+ }
+ }
+
+
+ private class SubFlushRunner implements ReadWriteRunnable
+ {
+ private final Subscription _sub;
+
+
+ public SubFlushRunner(Subscription sub)
+ {
+ _sub = sub;
+ }
+
+ public void run()
+ {
+ boolean complete = false;
+ try
+ {
+ complete = flushSubscription(_sub, MAX_ASYNC_DELIVERIES);
+
+ }
+ catch (AMQException e)
+ {
+ _logger.error(e);
+ }
+ if(!complete && !_sub.isSuspended())
+ {
+ _asyncDelivery.execute(this);
+ }
+
+ }
+
+ public boolean isRead()
+ {
+ return false;
+ }
+
+ public boolean isWrite()
+ {
+ return true;
+ }
+ }
+
+ public void flushSubscription(Subscription sub) throws AMQException
+ {
+ flushSubscription(sub, Long.MAX_VALUE);
+ }
+
+ public boolean flushSubscription(Subscription sub, long deliveries) throws AMQException
+ {
+ boolean atTail = false;
+ boolean advanced;
+
+ while(!sub.isSuspended() && !atTail && deliveries != 0)
+ {
+
+ advanced = false;
+ sub.getSendLock();
+ try
+ {
+ if(sub.isActive())
+ {
+ QueueEntry node = moveSubscriptionToNextNode(sub);
+ if(!(node.isAcquired() || node.isDeleted()))
+ {
+ if(!sub.isSuspended())
+ {
+ if(sub.hasInterest(node))
+ {
+ if(!sub.wouldSuspend(node))
+ {
+ if(!sub.isBrowser() && !node.acquire(sub))
+ {
+ sub.restoreCredit(node);
+
+ }
+ else
+ {
+ deliveries--;
+ deliverMessage(sub, node);
+
+ if(sub.isBrowser())
+ {
+ QueueEntry newNode = _entries.next(node);
+
+ if(newNode != null)
+ {
+ advanced = true;
+ sub.setLastSeenEntry(node, newNode);
+ node = sub.getLastSeenEntry();
+ }
+ }
+ }
+
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // this subscription is not interested in this node so we can skip over it
+ QueueEntry newNode = _entries.next(node);
+ if(newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
+ }
+ }
+ }
+
+ }
+ atTail = (_entries.next(node) == null) && !advanced;
+
+ }
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
+
+ }
+
+ // if there's (potentially) more than one subscription the others will potentially not have been advanced to the
+ // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc
+ // which would give us memory "leak".
+
+ if(!isExclusiveSubscriber())
+ {
+ advanceAllSubscriptions();
+ }
+
+ if(atTail && sub.isAutoClose())
+ {
+ unregisterSubscription(sub);
+
+ ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter();
+ converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag());
+ }
+
+ return atTail;
+ }
+
+ protected void advanceAllSubscriptions() throws AMQException
+ {
+ SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator();
+ while(subscriberIter.advance())
+ {
+ SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode();
+ Subscription sub = subNode.getSubscription();
+ moveSubscriptionToNextNode(sub);
+ }
+ }
+
+ private QueueEntry moveSubscriptionToNextNode(final Subscription sub)
+ throws AMQException
+ {
+ QueueEntry node = sub.getLastSeenEntry();
+
+ while(node != null && (node.isAcquired() || node.isDeleted() || node.expired()))
+ {
+ if(!node.isAcquired() && !node.isDeleted() && node.expired())
+ {
+ if(node.acquire())
+ {
+ final StoreContext reapingStoreContext = new StoreContext();
+ node.discard(reapingStoreContext);
+ }
+ }
+ QueueEntry newNode = _entries.next(node);
+ if(newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
+ node = sub.getLastSeenEntry();
+ }
+ else
+ {
+ break;
+ }
+
+ }
+ return node;
+ }
+
+
+ private void processQueue(Runnable runner) throws AMQException
+ {
+ long stateChangeCount;
+ long previousStateChangeCount = Long.MIN_VALUE;
+ boolean deliveryIncomplete = true;
+
+ int extraLoops = 1;
+ int deliveries = MAX_ASYNC_DELIVERIES;
+
+ _asynchronousRunner.compareAndSet(runner,null);
+
+ while(deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete ) && _asynchronousRunner.compareAndSet(null,runner))
+ {
+ // we want to have one extra loop after every subscription has reached the point where it cannot move
+ // further, just in case the advance of one subscription in the last loop allows a different subscription to
+ // move forward in the next iteration
+
+ if(previousStateChangeCount != stateChangeCount)
+ {
+ extraLoops = 1;
+ }
+
+ previousStateChangeCount = stateChangeCount;
+ deliveryIncomplete = _subscriptionList.size() != 0;
+ boolean done = true;
+
+
+ SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator();
+ //iterate over the subscribers and try to advance their pointer
+ while(subscriptionIter.advance())
+ {
+ Subscription sub = subscriptionIter.getNode().getSubscription();
+ if(sub != null)
+ {
+ sub.getSendLock();
+ try
+ {
+ QueueEntry node = moveSubscriptionToNextNode(sub);
+
+ if(node != null && sub.isActive())
+ {
+ boolean advanced = false;
+ boolean subActive = false;
+
+ if(!(node.isAcquired() || node.isDeleted()))
+ {
+ if(!sub.isSuspended())
+ {
+ subActive = true;
+ if(sub.hasInterest(node))
+ {
+ if(!sub.wouldSuspend(node))
+ {
+ if(!sub.isBrowser() && !node.acquire(sub))
+ {
+ sub.restoreCredit(node);
+
+ }
+ else
+ {
+ deliverMessage(sub, node);
+ deliveries--;
+
+ if(sub.isBrowser())
+ {
+ QueueEntry newNode = _entries.next(node);
+
+ if(newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
+ node = sub.getLastSeenEntry();
+ advanced = true;
+ }
+
+
+ }
+ }
+ done = false;
+ }
+ else
+ {
+ node.addStateChangeListener(new QueueEntryListener(sub,node));
+ }
+ }
+ else
+ {
+ // this subscription is not interested in this node so we can skip over it
+ QueueEntry newNode = _entries.next(node);
+ if(newNode != null)
+ {
+ sub.setLastSeenEntry(node, newNode);
+ }
+ }
+ }
+ }
+ final boolean atTail = (_entries.next(node) == null);
+
+ done = done && (!subActive || atTail);
+
+ if(atTail && !advanced && sub.isAutoClose())
+ {
+ unregisterSubscription(sub);
+
+ ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter();
+ converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag());
+
+ }
+
+ }
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
+ }
+ if(done)
+ {
+ if(extraLoops == 0)
+ {
+ deliveryIncomplete = false;
+ }
+ else
+ {
+ extraLoops--;
+ }
+ }
+ else
+ {
+ extraLoops = 1;
+ }
+ }
+
+
+
+ _asynchronousRunner.set(null);
+ }
+
+ // If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit
+ // therefore we should schedule this runner again (unless someone beats us to it :-) ).
+ if(deliveries == 0 && _asynchronousRunner.compareAndSet(null,runner))
+ {
+ _asyncDelivery.execute(runner);
+ }
+ }
+
+
+ public void removeExpiredIfNoSubscribers() throws AMQException
+ {
+
+ final StoreContext storeContext = new StoreContext();
+
+ QueueEntryIterator queueListIterator = _entries.iterator();
+
+ while(queueListIterator.advance())
+ {
+ QueueEntry node = queueListIterator.getNode();
+ if(!node.isDeleted() && node.expired() && node.acquire())
+ {
+
+ node.discard(storeContext);
+ }
+
+ }
+
+ }
+
+
+ public long getMinimumAlertRepeatGap()
+ {
+ return _minimumAlertRepeatGap;
+ }
+
+ public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap)
+ {
+ _minimumAlertRepeatGap = minimumAlertRepeatGap;
+ }
+
+ public long getMaximumMessageAge()
+ {
+ return _maximumMessageAge;
+ }
+
+ public void setMaximumMessageAge(long maximumMessageAge)
+ {
+ _maximumMessageAge = maximumMessageAge;
+ if(maximumMessageAge == 0L)
+ {
+ _notificationChecks.remove(NotificationCheck.MESSAGE_AGE_ALERT);
+ }
+ else
+ {
+ _notificationChecks.add(NotificationCheck.MESSAGE_AGE_ALERT);
+ }
+ }
+
+ public long getMaximumMessageCount()
+ {
+ return _maximumMessageCount;
+ }
+
+ public void setMaximumMessageCount(final long maximumMessageCount)
+ {
+ _maximumMessageCount = maximumMessageCount;
+ if(maximumMessageCount == 0L)
+ {
+ _notificationChecks.remove(NotificationCheck.MESSAGE_COUNT_ALERT);
+ }
+ else
+ {
+ _notificationChecks.add(NotificationCheck.MESSAGE_COUNT_ALERT);
+ }
+
+
+
+ }
+
+ public long getMaximumQueueDepth()
+ {
+ return _maximumQueueDepth;
+ }
+
+ // Sets the queue depth, the max queue size
+ public void setMaximumQueueDepth(final long maximumQueueDepth)
+ {
+ _maximumQueueDepth = maximumQueueDepth;
+ if(maximumQueueDepth == 0L)
+ {
+ _notificationChecks.remove(NotificationCheck.QUEUE_DEPTH_ALERT);
+ }
+ else
+ {
+ _notificationChecks.add(NotificationCheck.QUEUE_DEPTH_ALERT);
+ }
+
+ }
+
+ public long getMaximumMessageSize()
+ {
+ return _maximumMessageSize;
+ }
+
+ public void setMaximumMessageSize(final long maximumMessageSize)
+ {
+ _maximumMessageSize = maximumMessageSize;
+ if(maximumMessageSize == 0L)
+ {
+ _notificationChecks.remove(NotificationCheck.MESSAGE_SIZE_ALERT);
+ }
+ else
+ {
+ _notificationChecks.add(NotificationCheck.MESSAGE_SIZE_ALERT);
+ }
+ }
+
+
+ public Set<NotificationCheck> getNotificationChecks()
+ {
+ return _notificationChecks;
+ }
+
+ public ManagedObject getManagedObject()
+ {
+ return _managedObject;
+ }
+
+ private final class QueueEntryListener implements QueueEntry.StateChangeListener
+ {
+ private final QueueEntry _entry;
+ private final Subscription _sub;
+
+ public QueueEntryListener(final Subscription sub, final QueueEntry entry)
+ {
+ _entry = entry;
+ _sub = sub;
+ }
+
+ public boolean equals(Object o)
+ {
+ return _entry == ((QueueEntryListener)o)._entry && _sub == ((QueueEntryListener)o)._sub;
+ }
+
+ public int hashCode()
+ {
+ return System.identityHashCode(_entry) ^ System.identityHashCode(_sub);
+ }
+
+ public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState)
+ {
+ entry.removeStateChangeListener(this);
+ deliverAsync(_sub);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
new file mode 100644
index 0000000000..a46c5ae2e8
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
@@ -0,0 +1,178 @@
+package org.apache.qpid.server.queue;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class SimpleQueueEntryList implements QueueEntryList
+{
+ private final QueueEntryImpl _head;
+
+ private volatile QueueEntryImpl _tail;
+
+ static final AtomicReferenceFieldUpdater<SimpleQueueEntryList, QueueEntryImpl>
+ _tailUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail");
+
+
+ private final AMQQueue _queue;
+
+ static final AtomicReferenceFieldUpdater<QueueEntryImpl, QueueEntryImpl>
+ _nextUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (QueueEntryImpl.class, QueueEntryImpl.class, "_next");
+
+
+
+
+
+ public SimpleQueueEntryList(AMQQueue queue)
+ {
+ _queue = queue;
+ _head = new QueueEntryImpl(this);
+ _tail = _head;
+ }
+
+ void advanceHead()
+ {
+ QueueEntryImpl head = _head.nextNode();
+ while(head._next != null && head.isDeleted())
+ {
+
+ final QueueEntryImpl newhead = head.nextNode();
+ if(newhead != null)
+ {
+ _nextUpdater.compareAndSet(_head,head, newhead);
+ }
+ head = _head.nextNode();
+ }
+ }
+
+
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+
+ public QueueEntry add(AMQMessage message)
+ {
+ QueueEntryImpl node = new QueueEntryImpl(this, message);
+ for (;;)
+ {
+ QueueEntryImpl tail = _tail;
+ QueueEntryImpl next = tail.nextNode();
+ if (tail == _tail)
+ {
+ if (next == null)
+ {
+ node.setEntryId(tail.getEntryId()+1);
+ if (_nextUpdater.compareAndSet(tail, null, node))
+ {
+ _tailUpdater.compareAndSet(this, tail, node);
+
+ return node;
+ }
+ }
+ else
+ {
+ _tailUpdater.compareAndSet(this,tail, next);
+ }
+ }
+ }
+ }
+
+ public QueueEntry next(QueueEntry node)
+ {
+ return ((QueueEntryImpl)node).getNext();
+ }
+
+
+ public class QueueEntryIteratorImpl implements QueueEntryIterator
+ {
+
+ private QueueEntryImpl _lastNode;
+
+ QueueEntryIteratorImpl(QueueEntryImpl startNode)
+ {
+ _lastNode = startNode;
+ }
+
+
+ public boolean atTail()
+ {
+ return _lastNode.nextNode() == null;
+ }
+
+ public QueueEntry getNode()
+ {
+
+ return _lastNode;
+
+ }
+
+ public boolean advance()
+ {
+
+ if(!atTail())
+ {
+ QueueEntryImpl nextNode = _lastNode.nextNode();
+ while(nextNode.isDeleted() && nextNode.nextNode() != null)
+ {
+ nextNode = nextNode.nextNode();
+ }
+ _lastNode = nextNode;
+ return true;
+
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+
+ public QueueEntryIterator iterator()
+ {
+ return new QueueEntryIteratorImpl(_head);
+ }
+
+
+ public QueueEntry getHead()
+ {
+ return _head;
+ }
+
+ static class Factory implements QueueEntryListFactory
+ {
+
+ public QueueEntryList createQueueEntryList(AMQQueue queue)
+ {
+ return new SimpleQueueEntryList(queue);
+ }
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java
deleted file mode 100644
index 05cd461582..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.Queue;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.common.AMQPFilterTypes;
-import org.apache.qpid.common.ClientProperties;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.filter.FilterManager;
-import org.apache.qpid.server.filter.FilterManagerFactory;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize;
-import org.apache.qpid.util.MessageQueue;
-import org.apache.qpid.util.ConcurrentLinkedMessageQueueAtomicSize;
-
-/**
- * Encapsulation of a supscription to a queue. <p/> Ties together the protocol session of a subscriber, the consumer tag
- * that was given out by the broker and the channel id. <p/>
- */
-public class SubscriptionImpl implements Subscription
-{
-
- private static final Logger _suspensionlogger = Logger.getLogger("Suspension");
- private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class);
-
- public final AMQChannel channel;
-
- public final AMQProtocolSession protocolSession;
-
- public final AMQShortString consumerTag;
-
- private final Object _sessionKey;
-
- private MessageQueue<QueueEntry> _messages;
-
- private Queue<QueueEntry> _resendQueue;
-
- private final boolean _noLocal;
-
- /** True if messages need to be acknowledged */
- private final boolean _acks;
- private FilterManager _filters;
- private final boolean _isBrowser;
- private final Boolean _autoClose;
- private boolean _sentClose = false;
-
- private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString();
-
- private AMQQueue _queue;
- private final AtomicBoolean _sendLock = new AtomicBoolean(false);
-
-
- public static class Factory implements SubscriptionFactory
- {
- public Subscription createSubscription(int channel, AMQProtocolSession protocolSession,
- AMQShortString consumerTag, boolean acks, FieldTable filters,
- boolean noLocal, AMQQueue queue) throws AMQException
- {
- return new SubscriptionImpl(channel, protocolSession, consumerTag, acks, filters, noLocal, queue);
- }
-
- public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag)
- throws AMQException
- {
- return new SubscriptionImpl(channel, protocolSession, consumerTag, false, null, false, null);
- }
- }
-
- public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession,
- AMQShortString consumerTag, boolean acks)
- throws AMQException
- {
- this(channelId, protocolSession, consumerTag, acks, null, false, null);
- }
-
- public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession,
- AMQShortString consumerTag, boolean acks, FieldTable filters,
- boolean noLocal, AMQQueue queue)
- throws AMQException
- {
- AMQChannel channel = protocolSession.getChannel(channelId);
- if (channel == null)
- {
- throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session");
- }
-
- this.channel = channel;
- this.protocolSession = protocolSession;
- this.consumerTag = consumerTag;
- _sessionKey = protocolSession.getKey();
- _acks = acks;
- _noLocal = noLocal;
- _queue = queue;
-
- _filters = FilterManagerFactory.createManager(filters);
-
-
- if (_filters != null)
- {
- Object isBrowser = filters.get(AMQPFilterTypes.NO_CONSUME.getValue());
- if (isBrowser != null)
- {
- _isBrowser = (Boolean) isBrowser;
- }
- else
- {
- _isBrowser = false;
- }
- }
- else
- {
- _isBrowser = false;
- }
-
-
- if (_filters != null)
- {
- Object autoClose = filters.get(AMQPFilterTypes.AUTO_CLOSE.getValue());
- if (autoClose != null)
- {
- _autoClose = (Boolean) autoClose;
- }
- else
- {
- _autoClose = false;
- }
- }
- else
- {
- _autoClose = false;
- }
-
-
- if (filtersMessages())
- {
- _messages = new ConcurrentLinkedMessageQueueAtomicSize<QueueEntry>();
- }
- else
- {
- // Reference the DeliveryManager
- _messages = null;
- }
- }
-
-
- public SubscriptionImpl(int channel, AMQProtocolSession protocolSession,
- AMQShortString consumerTag)
- throws AMQException
- {
- this(channel, protocolSession, consumerTag, false);
- }
-
- public boolean equals(Object o)
- {
- return (o instanceof SubscriptionImpl) && equals((SubscriptionImpl) o);
- }
-
- /**
- * Equality holds if the session matches and the channel and consumer tag are the same.
- *
- * @param psc The subscriptionImpl to compare
- *
- * @return equality
- */
- private boolean equals(SubscriptionImpl psc)
- {
- return _sessionKey.equals(psc._sessionKey)
- && psc.channel == channel
- && psc.consumerTag.equals(consumerTag);
- }
-
- public int hashCode()
- {
- return _sessionKey.hashCode();
- }
-
- public String toString()
- {
- String subscriber = "[channel=" + channel +
- ", consumerTag=" + consumerTag +
- ", session=" + protocolSession.getKey() +
- ", resendQueue=" + (_resendQueue != null);
-
- if (_resendQueue != null)
- {
- subscriber += ", resendSize=" + _resendQueue.size();
- }
-
-
- return subscriber + "]";
- }
-
- /**
- * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
- * thread safe.
- *
- * @param msg The message to send
- * @param queue the Queue it has been sent from
- *
- * @throws AMQException
- */
- public void send(QueueEntry msg, AMQQueue queue) throws AMQException
- {
- if (msg != null)
- {
- if (_isBrowser)
- {
- sendToBrowser(msg, queue);
- }
- else
- {
- sendToConsumer(channel.getStoreContext(), msg, queue);
- }
- }
- else
- {
- _logger.error("Attempt to send Null message", new NullPointerException());
- }
- }
-
- private void sendToBrowser(QueueEntry msg, AMQQueue queue) throws AMQException
- {
- // We don't decrement the reference here as we don't want to consume the message
- // but we do want to send it to the client.
-
- synchronized (channel)
- {
- long deliveryTag = channel.getNextDeliveryTag();
-
- if (_sendLock.get())
- {
- _logger.error("Sending " + msg + " when subscriber(" + this + ") is closed!");
- }
-
- protocolSession.getProtocolOutputConverter().writeDeliver(msg.getMessage(), channel.getChannelId(), deliveryTag, consumerTag);
- }
- }
-
- private void sendToConsumer(StoreContext storeContext, QueueEntry entry, AMQQueue queue)
- throws AMQException
- {
- try
- { // if we do not need to wait for client acknowledgements
- // we can decrement the reference count immediately.
-
- // By doing this _before_ the send we ensure that it
- // doesn't get sent if it can't be dequeued, preventing
- // duplicate delivery on recovery.
-
- // The send may of course still fail, in which case, as
- // the message is unacked, it will be lost.
- final AMQMessage message = entry.getMessage();
-
- if (!_acks)
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("No ack mode so dequeuing message immediately: " + message.getMessageId());
- }
- queue.dequeue(storeContext, entry);
- }
-
- final ProtocolOutputConverter outputConverter = protocolSession.getProtocolOutputConverter();
- final int channelId = channel.getChannelId();
-
- synchronized (channel)
- {
- final long deliveryTag = channel.getNextDeliveryTag();
-
-
- if (_acks)
- {
- channel.addUnacknowledgedMessage(entry, deliveryTag, consumerTag);
- }
-
- outputConverter.writeDeliver(message, channelId, deliveryTag, consumerTag);
-
-
- }
- if (!_acks)
- {
- message.decrementReference(storeContext);
- }
- }
- finally
- {
- //Only set delivered if it actually was writen successfully..
- // using a try->finally would set it even if an error occured.
- // Is this what we want?
-
- entry.setDeliveredToConsumer();
- }
- }
-
- public boolean isSuspended()
- {
-// if (_suspensionlogger.isInfoEnabled())
-// {
-// if (channel.isSuspended())
-// {
-// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") channel's is susupended");
-// }
-// if (_sendLock.get())
-// {
-// _suspensionlogger.debug("Subscription(" + debugIdentity() + ") has sendLock set so closing.");
-// }
-// }
- return channel.isSuspended() || _sendLock.get();
- }
-
- /**
- * Callback indicating that a queue has been deleted.
- *
- * @param queue The queue to delete
- */
- public void queueDeleted(AMQQueue queue) throws AMQException
- {
- channel.queueDeleted(queue);
- }
-
- public boolean filtersMessages()
- {
- return _filters != null || _noLocal;
- }
-
- public boolean hasInterest(QueueEntry entry)
- {
- //check that the message hasn't been rejected
- if (entry.isRejectedBy(this))
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity());
- }
-// return false;
- }
-
-
-
- //todo - client id should be recoreded and this test removed but handled below
- if (_noLocal)
- {
-
- final AMQProtocolSession publisher = entry.getMessage().getPublisher();
- if(publisher != null)
-
- {
- // We don't want local messages so check to see if message is one we sent
- Object localInstance;
- Object msgInstance;
-
- if ((protocolSession.getClientProperties() != null) &&
- (localInstance = protocolSession.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null)
- {
-
- if ((publisher.getClientProperties() != null) &&
- (msgInstance = publisher.getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null)
- {
- if (localInstance == msgInstance || localInstance.equals(msgInstance))
- {
- // if (_logger.isTraceEnabled())
- // {
- // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" +
- // msg.debugIdentity() + ")");
- // }
- return false;
- }
- }
- }
- else
- {
-
- localInstance = protocolSession.getClientIdentifier();
- //todo - client id should be recoreded and this test removed but handled here
-
- msgInstance = publisher.getClientIdentifier();
- if (localInstance == msgInstance || ((localInstance != null) && localInstance.equals(msgInstance)))
- {
- // if (_logger.isTraceEnabled())
- // {
- // _logger.trace("(" + debugIdentity() + ") has no interest as it is a local message(" +
- // msg.debugIdentity() + ")");
- // }
- return false;
- }
- }
-
- }
- }
-
-
- return checkFilters(entry);
-
- }
-
- private String id = String.valueOf(System.identityHashCode(this));
-
- private String debugIdentity()
- {
- return id;
- }
-
- private boolean checkFilters(QueueEntry msg)
- {
- return (_filters == null) || _filters.allAllow(msg.getMessage());
- }
-
- public Queue<QueueEntry> getPreDeliveryQueue()
- {
- return _messages;
- }
-
- public void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst)
- {
- if (_messages != null)
- {
- if (deliverFirst)
- {
- _messages.pushHead(msg);
- }
- else
- {
- _messages.offer(msg);
- }
- }
- }
-
- private boolean isAutoClose()
- {
- return _autoClose;
- }
-
- public void close()
- {
- boolean closed = false;
- synchronized (_sendLock)
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Setting SendLock true:" + debugIdentity());
- }
-
- closed = _sendLock.getAndSet(true);
- }
-
- if (closed)
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Called close() on a closed subscription");
- }
-
- return;
- }
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Closing subscription (" + debugIdentity() + "):" + this);
- }
-
- if (_resendQueue != null && !_resendQueue.isEmpty())
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Requeuing closing subscription (" + debugIdentity() + "):" + this);
- }
- requeue();
- }
-
- //remove references in PDQ
- if (_messages != null)
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Clearing PDQ (" + debugIdentity() + "):" + this);
- }
-
- _messages.clear();
- }
- }
-
- private void autoclose()
- {
- close();
-
- if (_autoClose && !_sentClose)
- {
- _logger.info("Closing autoclose subscription (" + debugIdentity() + "):" + this);
-
- boolean unregisteredOK = false;
- try
- {
- unregisteredOK = channel.unsubscribeConsumer(protocolSession, consumerTag);
- }
- catch (AMQException e)
- {
- // Occurs if we cannot find the subscriber in the channel with protocolSession and consumerTag.
- _logger.info("Unable to UnsubscribeConsumer :" + consumerTag +" so not going to send CancelOK.");
- }
-
- if (unregisteredOK)
- {
- ProtocolOutputConverter converter = protocolSession.getProtocolOutputConverter();
- converter.confirmConsumerAutoClose(channel.getChannelId(), consumerTag);
- _sentClose = true;
- }
-
- }
- }
-
- private void requeue()
- {
- if (_queue != null)
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Requeuing :" + _resendQueue.size() + " messages");
- }
-
- while (!_resendQueue.isEmpty())
- {
- QueueEntry resent = _resendQueue.poll();
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Removed for resending:" + resent.debugIdentity());
- }
-
- resent.release();
- _queue.subscriberHasPendingResend(false, this, resent);
-
- try
- {
- channel.getTransactionalContext().deliver(resent, true);
- }
- catch (AMQException e)
- {
- _logger.error("MESSAGE LOSS : Unable to re-deliver messages", e);
- }
- }
-
- if (!_resendQueue.isEmpty())
- {
- _logger.error("[MESSAGES LOST]Unable to re-deliver messages as queue is null.");
- }
-
- _queue.subscriberHasPendingResend(false, this, null);
- }
- else
- {
- if (!_resendQueue.isEmpty())
- {
- _logger.error("Unable to re-deliver messages as queue is null.");
- }
- }
-
- // Clear the messages
- _resendQueue = null;
- }
-
-
- public boolean isClosed()
- {
- return _sendLock.get(); // This rather than _close is used to signify the subscriber is now closed.
- }
-
- public boolean isBrowser()
- {
- return _isBrowser;
- }
-
- public boolean wouldSuspend(QueueEntry msg)
- {
- return _acks && channel.wouldSuspend(msg.getMessage());
- }
-
- public Queue<QueueEntry> getResendQueue()
- {
- if (_resendQueue == null)
- {
- _resendQueue = new ConcurrentLinkedQueueAtomicSize<QueueEntry>();
- }
- return _resendQueue;
- }
-
-
- public Queue<QueueEntry> getNextQueue(Queue<QueueEntry> messages)
- {
- if (_resendQueue != null && !_resendQueue.isEmpty())
- {
- return _resendQueue;
- }
-
- if (filtersMessages())
- {
- if (isAutoClose())
- {
- if (_messages.isEmpty())
- {
- autoclose();
- return null;
- }
- }
- return _messages;
- }
- else // we want the DM queue
- {
- return messages;
- }
- }
-
- public void addToResendQueue(QueueEntry msg)
- {
- // add to our resend queue
- getResendQueue().add(msg);
-
- // Mark Queue has having content.
- if (_queue == null)
- {
- _logger.error("Queue is null won't be able to resend messages");
- }
- else
- {
- _queue.subscriberHasPendingResend(true, this, msg);
- }
- }
-
- public Object getSendLock()
- {
- return _sendLock;
- }
-
- public AMQChannel getChannel()
- {
- return channel;
- }
-
- public void start()
- {
- //Check to see if we need to autoclose
- if (filtersMessages())
- {
- if (isAutoClose())
- {
- if (_messages.isEmpty())
- {
- autoclose();
- }
- }
- }
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java
deleted file mode 100644
index bc17bcca9c..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.List;
-
-/**
- * Abstraction of actor that will determine the subscriber to whom
- * a message will be sent.
- */
-public interface SubscriptionManager
-{
- public List<Subscription> getSubscriptions();
- public boolean hasActiveSubscribers();
- public Subscription nextSubscriber(QueueEntry entry);
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java
deleted file mode 100644
index 882efd380d..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.List;
-import java.util.ListIterator;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-
-/** Holds a set of subscriptions for a queue and manages the round robin-ing of deliver etc. */
-class SubscriptionSet implements WeightedSubscriptionManager
-{
- private static final Logger _log = Logger.getLogger(SubscriptionSet.class);
-
- /** List of registered subscribers */
- private List<Subscription> _subscriptions = new CopyOnWriteArrayList<Subscription>();
-
- /** Used to control the round robin delivery of content */
- private int _currentSubscriber;
-
- private final Object _changeLock = new Object();
- private volatile boolean _exclusive;
-
-
- /** Accessor for unit tests. */
- int getCurrentSubscriber()
- {
- return _currentSubscriber;
- }
-
- public void addSubscriber(Subscription subscription)
- {
- synchronized (_changeLock)
- {
- _subscriptions.add(subscription);
- }
- }
-
- /**
- * Remove the subscription, returning it if it was found
- *
- * @param subscription
- *
- * @return null if no match was found
- */
- public Subscription removeSubscriber(Subscription subscription)
- {
- // TODO: possibly need O(1) operation here.
-
- Subscription sub = null;
- synchronized (_changeLock)
- {
- int subIndex = _subscriptions.indexOf(subscription);
-
- if (subIndex != -1)
- {
- //we can't just return the passed in subscription as it is a new object
- // and doesn't contain the stored state we need.
- //NOTE while this may be removed now anyone with an iterator will still have it in the list!!
- sub = _subscriptions.remove(subIndex);
- }
- else
- {
- _log.error("Unable to remove from index(" + subIndex + ")subscription:" + subscription);
- }
- }
- if (sub != null)
- {
- return sub;
- }
- else
- {
- debugDumpSubscription(subscription);
- return null;
- }
- }
-
- private void debugDumpSubscription(Subscription subscription)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Subscription " + subscription + " not found. Dumping subscriptions:");
- for (Subscription s : _subscriptions)
- {
- _log.debug("Subscription: " + s);
- }
- _log.debug("Subscription dump complete");
- }
- }
-
- /**
- * Return the next unsuspended subscription or null if not found. <p/> Performance note: This method can scan all
- * items twice when looking for a subscription that is not suspended. The worst case occcurs when all subscriptions
- * are suspended. However, it is does this without synchronisation and subscriptions may be added and removed
- * concurrently. Also note that because of race conditions and when subscriptions are removed between calls to
- * nextSubscriber, the IndexOutOfBoundsException also causes the scan to start at the beginning.
- */
- public Subscription nextSubscriber(QueueEntry msg)
- {
-
-
- try
- {
- final Subscription result = nextSubscriberImpl(msg);
- if (result == null)
- {
- _currentSubscriber = 0;
- return nextSubscriberImpl(msg);
- }
- else
- {
- return result;
- }
- }
- catch (IndexOutOfBoundsException e)
- {
- _currentSubscriber = 0;
- return nextSubscriber(msg);
- }
- }
-
- private Subscription nextSubscriberImpl(QueueEntry msg)
- {
- if(_exclusive)
- {
- try
- {
- Subscription subscription = _subscriptions.get(0);
- subscriberScanned();
-
- if (!(subscription.isSuspended() || subscription.wouldSuspend(msg)))
- {
- if (subscription.hasInterest(msg))
- {
- // if the queue is not empty then this client is ready to receive a message.
- //FIXME the queue could be full of sent messages.
- // Either need to clean all PDQs after sending a message
- // OR have a clean up thread that runs the PDQs expunging the messages.
- if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty())
- {
- return subscription;
- }
- }
- }
- }
- catch(IndexOutOfBoundsException e)
- {
- }
- return null;
- }
- else
- {
- if (_subscriptions.isEmpty())
- {
- return null;
- }
- final ListIterator<Subscription> iterator = _subscriptions.listIterator(_currentSubscriber);
- while (iterator.hasNext())
- {
- Subscription subscription = iterator.next();
- ++_currentSubscriber;
- subscriberScanned();
-
- if (!(subscription.isSuspended() || subscription.wouldSuspend(msg)))
- {
- if (subscription.hasInterest(msg))
- {
- // if the queue is not empty then this client is ready to receive a message.
- //FIXME the queue could be full of sent messages.
- // Either need to clean all PDQs after sending a message
- // OR have a clean up thread that runs the PDQs expunging the messages.
- if (!subscription.filtersMessages() || subscription.getPreDeliveryQueue().isEmpty())
- {
- return subscription;
- }
- }
- }
- }
-
- return null;
- }
- }
-
- /** Overridden in test classes. */
- protected void subscriberScanned()
- {
- }
-
- public boolean isEmpty()
- {
- return _subscriptions.isEmpty();
- }
-
- public List<Subscription> getSubscriptions()
- {
- return _subscriptions;
- }
-
- public boolean hasActiveSubscribers()
- {
- for (Subscription s : _subscriptions)
- {
- if (!s.isSuspended())
- {
- return true;
- }
- }
- return false;
- }
-
- public int getWeight()
- {
- int count = 0;
- for (Subscription s : _subscriptions)
- {
- if (!s.isSuspended())
- {
- count++;
- }
- }
- return count;
- }
-
- /**
- * Notification that a queue has been deleted. This is called so that the subscription can inform the channel, which
- * in turn can update its list of unacknowledged messages.
- *
- * @param queue
- */
- public void queueDeleted(AMQQueue queue) throws AMQException
- {
- for (Subscription s : _subscriptions)
- {
- s.queueDeleted(queue);
- }
- }
-
- int size()
- {
- return _subscriptions.size();
- }
-
-
- public Object getChangeLock()
- {
- return _changeLock;
- }
-
- public void setExclusive(final boolean exclusive)
- {
- _exclusive = exclusive;
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
index 373a64e2eb..3ed8b0e55c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
@@ -26,7 +26,6 @@ import java.util.LinkedList;
import java.util.List;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ContentChunk;
@@ -48,29 +47,35 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
private final MessageStore _messageStore;
+ private final Long _messageId;
private long _arrivalTime;
-
- public WeakReferenceMessageHandle(MessageStore messageStore)
+ public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore)
{
+ _messageId = messageId;
_messageStore = messageStore;
}
- public ContentHeaderBody getContentHeaderBody(StoreContext context, Long messageId) throws AMQException
+ public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException
{
ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null);
if (chb == null)
{
- MessageMetaData mmd = loadMessageMetaData(context, messageId);
+ MessageMetaData mmd = loadMessageMetaData(context);
chb = mmd.getContentHeaderBody();
}
return chb;
}
- private MessageMetaData loadMessageMetaData(StoreContext context, Long messageId)
+ public Long getMessageId()
+ {
+ return _messageId;
+ }
+
+ private MessageMetaData loadMessageMetaData(StoreContext context)
throws AMQException
{
- MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId);
+ MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId);
populateFromMessageMetaData(mmd);
return mmd;
}
@@ -82,11 +87,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
_messagePublishInfo = new WeakReference<MessagePublishInfo>(mmd.getMessagePublishInfo());
}
- public int getBodyCount(StoreContext context, Long messageId) throws AMQException
+ public int getBodyCount(StoreContext context) throws AMQException
{
if (_contentBodies == null)
{
- MessageMetaData mmd = _messageStore.getMessageMetaData(context, messageId);
+ MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId);
int chunkCount = mmd.getContentChunkCount();
_contentBodies = new ArrayList<WeakReference<ContentChunk>>(chunkCount);
for (int i = 0; i < chunkCount; i++)
@@ -97,12 +102,12 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
return _contentBodies.size();
}
- public long getBodySize(StoreContext context, Long messageId) throws AMQException
+ public long getBodySize(StoreContext context) throws AMQException
{
- return getContentHeaderBody(context, messageId).bodySize;
+ return getContentHeaderBody(context).bodySize;
}
- public ContentChunk getContentChunk(StoreContext context, Long messageId, int index) throws AMQException, IllegalArgumentException
+ public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException
{
if (index > _contentBodies.size() - 1)
{
@@ -113,7 +118,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
ContentChunk cb = wr.get();
if (cb == null)
{
- cb = _messageStore.getContentBodyChunk(context, messageId, index);
+ cb = _messageStore.getContentBodyChunk(context, _messageId, index);
_contentBodies.set(index, new WeakReference<ContentChunk>(cb));
}
return cb;
@@ -123,12 +128,11 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
* Content bodies are set <i>before</i> the publish and header frames
*
* @param storeContext
- * @param messageId
* @param contentChunk
* @param isLastContentBody
* @throws AMQException
*/
- public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException
+ public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException
{
if (_contentBodies == null && isLastContentBody)
{
@@ -142,16 +146,16 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
}
}
_contentBodies.add(new WeakReference<ContentChunk>(contentChunk));
- _messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1,
+ _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1,
contentChunk, isLastContentBody);
}
- public MessagePublishInfo getMessagePublishInfo(StoreContext context, Long messageId) throws AMQException
+ public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException
{
MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null);
if (bpb == null)
{
- MessageMetaData mmd = loadMessageMetaData(context, messageId);
+ MessageMetaData mmd = loadMessageMetaData(context);
bpb = mmd.getMessagePublishInfo();
}
@@ -168,12 +172,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
_redelivered = redelivered;
}
- public boolean isPersistent(StoreContext context, Long messageId) throws AMQException
+ public boolean isPersistent()
{
- //todo remove literal values to a constant file such as AMQConstants in common
- ContentHeaderBody chb = getContentHeaderBody(context, messageId);
- return chb.properties instanceof BasicContentHeaderProperties &&
- ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2;
+ return true;
}
/**
@@ -183,7 +184,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
* @param contentHeaderBody
* @throws AMQException
*/
- public void setPublishAndContentHeaderBody(StoreContext storeContext, Long messageId, MessagePublishInfo publishBody,
+ public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody,
ContentHeaderBody contentHeaderBody)
throws AMQException
{
@@ -199,24 +200,15 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime);
- _messageStore.storeMessageMetaData(storeContext, messageId, mmd);
+ _messageStore.storeMessageMetaData(storeContext, _messageId, mmd);
- populateFromMessageMetaData(mmd);
- }
- public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
- {
- _messageStore.removeMessage(storeContext, messageId);
- }
-
- public void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException
- {
- _messageStore.enqueueMessage(storeContext, queue.getName(), messageId);
+ populateFromMessageMetaData(mmd);
}
- public void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException
+ public void removeMessage(StoreContext storeContext) throws AMQException
{
- _messageStore.dequeueMessage(storeContext, queue.getName(), messageId);
+ _messageStore.removeMessage(storeContext, _messageId);
}
public long getArrivalTime()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java
deleted file mode 100644
index 6c71571807..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-public interface WeightedSubscriptionManager extends SubscriptionManager
-{
- public int getWeight();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index 455983c6d8..d0dcd051f0 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -94,7 +94,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
{
try
{
- _instanceMap.get(instanceID).close();
+ IApplicationRegistry instance = _instanceMap.get(instanceID);
+ if(instance != null)
+ {
+ instance.close();
+ }
}
catch (Exception e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
index 748e33ba7a..fef958000a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
@@ -61,11 +61,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
private PluginManager _pluginManager;
- public ConfigurationFileApplicationRegistry(Configuration configuration)
- {
- super(configuration);
- }
-
public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException
{
super(config(configurationURL));
@@ -81,7 +76,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
}
}
- public static final Configuration config(File url) throws ConfigurationException
+ private static final Configuration config(File url) throws ConfigurationException
{
// We have to override the interpolate methods so that
// interpolation takes place accross the entirety of the
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
index 5d439a99eb..00757a4f8c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
@@ -1,37 +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.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-
-public enum Permission
-{
- CONSUME,
- PUBLISH,
- CREATE,
- ACCESS,
- BIND,
- UNBIND,
- DELETE,
- PURGE
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+
+public enum Permission
+{
+ CONSUME,
+ PUBLISH,
+ CREATE,
+ ACCESS,
+ BIND,
+ UNBIND,
+ DELETE,
+ PURGE
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
index 126ff22d69..9b784069dd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
@@ -28,13 +28,9 @@ import org.apache.qpid.server.security.access.AccessResult;
import org.apache.qpid.server.security.access.Accessable;
import org.apache.qpid.server.security.access.Permission;
import org.apache.commons.configuration.Configuration;
-import org.apache.log4j.Logger;
public class AllowAll implements ACLPlugin
{
-
- private static final Logger _logger = ACLManager.getLogger();
-
public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters)
{
if (ACLManager.getLogger().isDebugEnabled())
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
index bd980c696c..cc22569d77 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
@@ -1,23 +1,3 @@
-/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
package org.apache.qpid.server.store;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -25,7 +5,7 @@ import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.MessageMetaData;
import org.apache.qpid.server.queue.QueueRegistry;
-
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.MessageHandleFactory;
import org.apache.qpid.server.txn.TransactionalContext;
@@ -41,7 +21,6 @@ import org.apache.log4j.Logger;
import org.apache.mina.common.ByteBuffer;
import java.io.File;
-import java.io.ByteArrayInputStream;
import java.sql.DriverManager;
import java.sql.Driver;
import java.sql.Connection;
@@ -60,6 +39,26 @@ import java.util.HashMap;
import java.util.TreeMap;
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
public class DerbyMessageStore implements MessageStore
{
@@ -68,7 +67,7 @@ public class DerbyMessageStore implements MessageStore
private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path";
- private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver";
+ private static final String DERBY_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver";
private static final String DB_VERSION_TABLE_NAME = "QPID_DB_VERSION";
@@ -92,39 +91,6 @@ public class DerbyMessageStore implements MessageStore
private String _connectionURL;
-
- private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )";
- private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )";
- private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )";
- private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )";
- private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )";
- private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )";
- private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )";
- private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )";
- private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME;
- private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME;
- private static final String SELECT_FROM_BINDINGS =
- "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?";
- private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?";
- private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?";
- private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )";
- private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?";
- private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )";
- private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?";
- private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)";
- private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?";
- private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)";
- private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?";
- private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)";
- private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)";
- private static final String SELECT_FROM_MESSAGE_META_DATA =
- "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?";
- private static final String SELECT_FROM_MESSAGE_CONTENT =
- "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?";
- private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME;
- private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?";
-
-
private enum State
{
INITIAL,
@@ -163,6 +129,10 @@ public class DerbyMessageStore implements MessageStore
createOrOpenDatabase(databasePath);
+
+
+
+
// this recovers durable queues and persistent messages
recover();
@@ -175,7 +145,7 @@ public class DerbyMessageStore implements MessageStore
{
if(DRIVER_CLASS == null)
{
- DRIVER_CLASS = (Class<Driver>) Class.forName(SQL_DRIVER_NAME);
+ DRIVER_CLASS = (Class<Driver>) Class.forName(DERBY_DRIVER_NAME);
}
}
@@ -193,7 +163,7 @@ public class DerbyMessageStore implements MessageStore
createMessageMetaDataTable(conn);
createMessageContentTable(conn);
- conn.close();
+
}
@@ -204,10 +174,10 @@ public class DerbyMessageStore implements MessageStore
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_DB_VERSION_TABLE);
+ stmt.execute("CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )");
stmt.close();
- PreparedStatement pstmt = conn.prepareStatement(INSERT_INTO_DB_VERSION);
+ PreparedStatement pstmt = conn.prepareStatement("INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )");
pstmt.setInt(1, DB_VERSION);
pstmt.execute();
pstmt.close();
@@ -221,8 +191,8 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(EXCHANGE_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
-
- stmt.execute(CREATE_EXCHANGE_TABLE);
+
+ stmt.execute("CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )");
stmt.close();
}
}
@@ -232,7 +202,7 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(QUEUE_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_QUEUE_TABLE);
+ stmt.execute("CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )");
stmt.close();
}
}
@@ -242,7 +212,8 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(BINDINGS_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_BINDINGS_TABLE);
+ stmt.execute("CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )");
+
stmt.close();
}
@@ -254,7 +225,7 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(QUEUE_ENTRY_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_QUEUE_ENTRY_TABLE);
+ stmt.execute("CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )");
stmt.close();
}
@@ -266,7 +237,7 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_MESSAGE_META_DATA_TABLE);
+ stmt.execute("CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )");
stmt.close();
}
@@ -279,7 +250,7 @@ public class DerbyMessageStore implements MessageStore
if(!tableExists(MESSAGE_CONTENT_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_MESSAGE_CONTENT_TABLE);
+ stmt.execute("CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )");
stmt.close();
}
@@ -290,7 +261,7 @@ public class DerbyMessageStore implements MessageStore
private boolean tableExists(final String tableName, final Connection conn) throws SQLException
{
- PreparedStatement stmt = conn.prepareStatement(TABLE_EXISTANCE_QUERY);
+ PreparedStatement stmt = conn.prepareStatement("SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?");
stmt.setString(1, tableName);
ResultSet rs = stmt.executeQuery();
boolean exists = rs.next();
@@ -312,6 +283,8 @@ public class DerbyMessageStore implements MessageStore
recoverExchanges();
+//
+
try
{
@@ -344,14 +317,15 @@ public class DerbyMessageStore implements MessageStore
Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE);
+ ResultSet rs = stmt.executeQuery("SELECT name, owner FROM " + QUEUE_TABLE_NAME);
Map<AMQShortString, AMQQueue> queueMap = new HashMap<AMQShortString, AMQQueue>();
while(rs.next())
{
String queueName = rs.getString(1);
String owner = rs.getString(2);
AMQShortString queueNameShortString = new AMQShortString(queueName);
- AMQQueue q = new AMQQueue(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost);
+ AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost,
+ null);
_virtualHost.getQueueRegistry().registerQueue(q);
queueMap.put(queueNameShortString,q);
@@ -379,7 +353,7 @@ public class DerbyMessageStore implements MessageStore
Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE);
+ ResultSet rs = stmt.executeQuery("SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME);
Exchange exchange;
while(rs.next())
@@ -417,7 +391,7 @@ public class DerbyMessageStore implements MessageStore
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS);
+ PreparedStatement stmt = conn.prepareStatement("SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?");
stmt.setString(1, exchange.getName().toString());
ResultSet rs = stmt.executeQuery();
@@ -450,7 +424,7 @@ public class DerbyMessageStore implements MessageStore
argumentsFT = new FieldTable(buf,arguments.length());
}
- queue.bind(bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT, exchange);
+ queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT);
}
}
}
@@ -465,7 +439,9 @@ public class DerbyMessageStore implements MessageStore
public void close() throws Exception
{
+
_closed.getAndSet(true);
+
}
public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
@@ -486,11 +462,12 @@ public class DerbyMessageStore implements MessageStore
MessageMetaData mmd = getMessageMetaData(storeContext, messageId);
try
{
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA);
+ PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?");
stmt.setLong(1,messageId);
wrapper.setRequiresCommit();
int results = stmt.executeUpdate();
+
if (results == 0)
{
if (localTx)
@@ -507,7 +484,8 @@ public class DerbyMessageStore implements MessageStore
_logger.debug("Deleted metadata for message " + messageId);
}
- stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_CONTENT);
+
+ stmt = conn.prepareStatement("DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?");
stmt.setLong(1,messageId);
results = stmt.executeUpdate();
@@ -550,7 +528,7 @@ public class DerbyMessageStore implements MessageStore
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_EXCHANGE);
+ PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )");
stmt.setString(1, exchange.getName().toString());
stmt.setString(2, exchange.getType().toString());
stmt.setShort(3, exchange.isAutoDelete() ? (short) 1 : (short) 0);
@@ -564,6 +542,7 @@ public class DerbyMessageStore implements MessageStore
if(conn != null)
{
conn.close();
+
}
}
}
@@ -582,7 +561,7 @@ public class DerbyMessageStore implements MessageStore
try
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE);
+ PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?");
stmt.setString(1, exchange.getName().toString());
int results = stmt.executeUpdate();
if(results == 0)
@@ -627,20 +606,16 @@ public class DerbyMessageStore implements MessageStore
try
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS);
+ // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob
+ PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )");
stmt.setString(1, exchange.getName().toString() );
stmt.setString(2, queue.getName().toString());
stmt.setString(3, routingKey == null ? null : routingKey.toString());
if(args != null)
{
- /* This would be the Java 6 way of setting a Blob
Blob blobArgs = conn.createBlob();
blobArgs.setBytes(0, args.getDataAsBytes());
stmt.setBlob(4, blobArgs);
- */
- byte[] bytes = args.getDataAsBytes();
- ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
- stmt.setBinaryStream(4, bis, bytes.length);
}
else
{
@@ -687,7 +662,7 @@ public class DerbyMessageStore implements MessageStore
{
conn = newConnection();
// exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS);
+ PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?");
stmt.setString(1, exchange.getName().toString() );
stmt.setString(2, queue.getName().toString());
stmt.setString(3, routingKey == null ? null : routingKey.toString());
@@ -736,7 +711,7 @@ public class DerbyMessageStore implements MessageStore
Connection conn = newConnection();
PreparedStatement stmt =
- conn.prepareStatement(INSERT_INTO_QUEUE);
+ conn.prepareStatement("INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)");
stmt.setString(1, queue.getName().toString());
stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString());
@@ -758,13 +733,13 @@ public class DerbyMessageStore implements MessageStore
private Connection newConnection() throws SQLException
{
- final Connection connection = DriverManager.getConnection(_connectionURL);
- return connection;
+ return DriverManager.getConnection(_connectionURL);
}
- public void removeQueue(AMQShortString name) throws AMQException
+ public void removeQueue(final AMQQueue queue) throws AMQException
{
+ AMQShortString name = queue.getName();
_logger.debug("public void removeQueue(AMQShortString name = " + name + "): called");
Connection conn = null;
@@ -772,7 +747,7 @@ public class DerbyMessageStore implements MessageStore
try
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE);
+ PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?");
stmt.setString(1, name.toString());
int results = stmt.executeUpdate();
@@ -808,16 +783,17 @@ public class DerbyMessageStore implements MessageStore
}
- public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
boolean localTx = getOrCreateTransaction(context);
Connection conn = getConnection(context);
ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
+ AMQShortString name = queue.getName();
try
{
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY);
+ PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)");
stmt.setString(1,name.toString());
stmt.setLong(2,messageId);
stmt.executeUpdate();
@@ -848,16 +824,17 @@ public class DerbyMessageStore implements MessageStore
}
- public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
+ AMQShortString name = queue.getName();
boolean localTx = getOrCreateTransaction(context);
Connection conn = getConnection(context);
ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
try
{
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY);
+ PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?");
stmt.setString(1,name.toString());
stmt.setLong(2,messageId);
int results = stmt.executeUpdate();
@@ -954,18 +931,17 @@ public class DerbyMessageStore implements MessageStore
try
{
- Connection conn = connWrapper.getConnection();
if(connWrapper.requiresCommit())
{
+ Connection conn = connWrapper.getConnection();
conn.commit();
if (_logger.isDebugEnabled())
{
_logger.debug("commit tran completed");
}
-
+ conn.close();
}
- conn.close();
}
catch (SQLException e)
{
@@ -1026,25 +1002,21 @@ public class DerbyMessageStore implements MessageStore
int index,
ContentChunk contentBody,
boolean lastContentBody) throws AMQException
- {
+ {
boolean localTx = getOrCreateTransaction(context);
Connection conn = getConnection(context);
ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
try
{
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
+ PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)");
stmt.setLong(1,messageId);
stmt.setInt(2, index);
byte[] chunkData = new byte[contentBody.getSize()];
contentBody.getData().duplicate().get(chunkData);
- /* this would be the Java 6 way of doing things
Blob dataAsBlob = conn.createBlob();
dataAsBlob.setBytes(1L, chunkData);
stmt.setBlob(3, dataAsBlob);
- */
- ByteArrayInputStream bis = new ByteArrayInputStream(chunkData);
- stmt.setBinaryStream(3, bis, chunkData.length);
stmt.executeUpdate();
connWrapper.requiresCommit();
@@ -1076,7 +1048,7 @@ public class DerbyMessageStore implements MessageStore
try
{
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA);
+ PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)");
stmt.setLong(1,messageId);
stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString());
stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString());
@@ -1088,13 +1060,9 @@ public class DerbyMessageStore implements MessageStore
byte[] underlying = new byte[bodySize];
ByteBuffer buf = ByteBuffer.wrap(underlying);
headerBody.writePayload(buf);
-/*
Blob dataAsBlob = conn.createBlob();
dataAsBlob.setBytes(1L, underlying);
stmt.setBlob(6, dataAsBlob);
-*/
- ByteArrayInputStream bis = new ByteArrayInputStream(underlying);
- stmt.setBinaryStream(6,bis,underlying.length);
stmt.setInt(7, mmd.getContentChunkCount());
@@ -1128,7 +1096,7 @@ public class DerbyMessageStore implements MessageStore
try
{
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA);
+ PreparedStatement stmt = conn.prepareStatement("SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?");
stmt.setLong(1,messageId);
ResultSet rs = stmt.executeQuery();
@@ -1213,7 +1181,7 @@ public class DerbyMessageStore implements MessageStore
try
{
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
+ PreparedStatement stmt = conn.prepareStatement("SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?");
stmt.setLong(1,messageId);
stmt.setInt(2, index);
ResultSet rs = stmt.executeQuery();
@@ -1300,7 +1268,7 @@ public class DerbyMessageStore implements MessageStore
public void process() throws AMQException
{
- _queue.process(_context, _queue.createEntry(_message), false);
+ _queue.enqueue(_context, _message);
}
}
@@ -1335,7 +1303,7 @@ public class DerbyMessageStore implements MessageStore
TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null);
Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY);
+ ResultSet rs = stmt.executeQuery("SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME);
while (rs.next())
@@ -1349,7 +1317,7 @@ public class DerbyMessageStore implements MessageStore
AMQQueue queue = queues.get(queueName);
if (queue == null)
{
- queue = new AMQQueue(queueName, false, null, false, _virtualHost);
+ queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null);
_virtualHost.getQueueRegistry().registerQueue(queue);
queues.put(queueName, queue);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
index 7a6e0b011f..b02eff957e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
@@ -26,9 +26,9 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.server.queue.MessageMetaData;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.MessageMetaData;
import org.apache.qpid.server.virtualhost.VirtualHost;
import java.util.ArrayList;
@@ -126,17 +126,17 @@ public class MemoryMessageStore implements MessageStore
// Not required to do anything
}
- public void removeQueue(AMQShortString name) throws AMQException
+ public void removeQueue(final AMQQueue queue) throws AMQException
{
// Not required to do anything
}
- public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
// Not required to do anything
}
- public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
// Not required to do anything
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
index 2a83d9b649..e15e69a414 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
@@ -27,8 +27,8 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
/**
@@ -138,33 +138,30 @@ public interface MessageStore
/**
* Removes the specified queue from the persistent store.
*
- * @param name The queue to remove.
- *
+ * @param queue The queue to remove.
* @throws AMQException If the operation fails for any reason.
*/
- void removeQueue(AMQShortString name) throws AMQException;
+ void removeQueue(final AMQQueue queue) throws AMQException;
/**
* Places a message onto a specified queue, in a given transactional context.
*
* @param context The transactional context for the operation.
- * @param name The name of the queue to place the message on.
+ * @param queue The queue to place the message on.
* @param messageId The message to enqueue.
- *
* @throws AMQException If the operation fails for any reason.
*/
- void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException;
+ void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException;
/**
* Extracts a message from a specified queue, in a given transactional context.
*
* @param context The transactional context for the operation.
- * @param name The name of the queue to take the message from.
+ * @param queue The queue to place the message on.
* @param messageId The message to dequeue.
- *
* @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
*/
- void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException;
+ void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException;
/**
* Begins a transactional context.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
index 3ee49d58cf..fdb56a1a55 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
@@ -37,7 +37,7 @@ public class StoreContext
public StoreContext()
{
- _name = super.toString();
+ _name = "StoreContext";
}
public StoreContext(String name)
@@ -52,7 +52,10 @@ public class StoreContext
public void setPayload(Object payload)
{
- _logger.debug("public void setPayload(Object payload = " + payload + "): called");
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug("public void setPayload(Object payload = " + payload + "): called");
+ }
_payload = payload;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java
new file mode 100644
index 0000000000..fbc8b3af7d
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/ClientDeliveryMethod.java
@@ -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.
+*
+*/
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.AMQException;
+
+public interface ClientDeliveryMethod
+{
+ void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException;
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java
new file mode 100644
index 0000000000..e2ed4104de
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/RecordDeliveryMethod.java
@@ -0,0 +1,28 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.subscription;
+
+import org.apache.qpid.server.queue.QueueEntry;
+
+public interface RecordDeliveryMethod
+{
+ void recordMessageDelivery(final Subscription sub, final QueueEntry entry, final long deliveryTag);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
index 96ce6743ec..408defe453 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
@@ -18,46 +18,77 @@
* under the License.
*
*/
-package org.apache.qpid.server.queue;
-
-import java.util.Queue;
+package org.apache.qpid.server.subscription;
import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
public interface Subscription
{
- void send(QueueEntry msg, AMQQueue queue) throws AMQException;
- boolean isSuspended();
- void queueDeleted(AMQQueue queue) throws AMQException;
+ public static enum State
+ {
+ ACTIVE,
+ SUSPENDED,
+ CLOSED
+ }
- boolean filtersMessages();
+ public static interface StateListener
+ {
+ public void stateChange(Subscription sub, State oldState, State newState);
+ }
- boolean hasInterest(QueueEntry msg);
+ AMQQueue getQueue();
- Queue<QueueEntry> getPreDeliveryQueue();
+ QueueEntry.SubscriptionAcquiredState getOwningState();
- Queue<QueueEntry> getResendQueue();
+ void setQueue(AMQQueue queue);
- Queue<QueueEntry> getNextQueue(Queue<QueueEntry> messages);
+ AMQChannel getChannel();
- void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst);
+ AMQShortString getConsumerTag();
- void close();
+ boolean isSuspended();
+
+ boolean hasInterest(QueueEntry msg);
+
+ boolean isAutoClose();
boolean isClosed();
boolean isBrowser();
+ void close();
+
+ boolean filtersMessages();
+
+ void send(QueueEntry msg) throws AMQException;
+
+ void queueDeleted(AMQQueue queue);
+
+
boolean wouldSuspend(QueueEntry msg);
- void addToResendQueue(QueueEntry msg);
+ void getSendLock();
+ void releaseSendLock();
+
+ void resend(final QueueEntry entry) throws AMQException;
+
+ void restoreCredit(final QueueEntry queueEntry);
+
+ void setStateListener(final StateListener listener);
+
+ QueueEntry getLastSeenEntry();
+
+ boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue);
+
+
+ boolean isActive();
- Object getSendLock();
- AMQChannel getChannel();
- void start();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java
index 917f7c4e97..ce0362d73f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactory.java
@@ -18,12 +18,15 @@
* under the License.
*
*/
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.subscription;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.AMQChannel;
/**
* Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This factory
@@ -34,10 +37,23 @@ import org.apache.qpid.server.protocol.AMQProtocolSession;
*/
public interface SubscriptionFactory
{
- Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks,
- FieldTable filters, boolean noLocal, AMQQueue queue) throws AMQException;
+ Subscription createSubscription(int channel,
+ AMQProtocolSession protocolSession,
+ AMQShortString consumerTag,
+ boolean acks,
+ FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager) throws AMQException;
- Subscription createSubscription(int channel, AMQProtocolSession protocolSession, AMQShortString consumerTag)
+ Subscription createSubscription(AMQChannel channel,
+ AMQProtocolSession protocolSession,
+ AMQShortString consumerTag,
+ boolean acks,
+ FieldTable filters,
+ boolean noLocal,
+ FlowCreditManager creditManager,
+ ClientDeliveryMethod clientMethod,
+ RecordDeliveryMethod recordMethod
+ )
throws AMQException;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java
new file mode 100644
index 0000000000..5badbad642
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.subscription;
+
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactory;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.common.AMQPFilterTypes;
+
+public class SubscriptionFactoryImpl implements SubscriptionFactory
+{
+
+ /* private SubscriptionFactoryImpl()
+ {
+
+ }*/
+
+ public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, boolean acks, FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager) throws AMQException
+ {
+ AMQChannel channel = protocolSession.getChannel(channelId);
+ if (channel == null)
+ {
+ throw new AMQException(AMQConstant.NOT_FOUND, "channel :" + channelId + " not found in protocol session");
+ }
+ ClientDeliveryMethod clientMethod = channel.getClientDeliveryMethod();
+ RecordDeliveryMethod recordMethod = channel.getRecordDeliveryMethod();
+
+
+ return createSubscription(channel, protocolSession, consumerTag, acks, filters,
+ noLocal,
+ creditManager,
+ clientMethod,
+ recordMethod
+ );
+ }
+
+ public Subscription createSubscription(final AMQChannel channel,
+ final AMQProtocolSession protocolSession,
+ final AMQShortString consumerTag,
+ final boolean acks,
+ final FieldTable filters,
+ final boolean noLocal,
+ final FlowCreditManager creditManager,
+ final ClientDeliveryMethod clientMethod,
+ final RecordDeliveryMethod recordMethod
+ )
+ throws AMQException
+ {
+ boolean isBrowser;
+
+ if (filters != null)
+ {
+ Boolean isBrowserObj = (Boolean) filters.get(AMQPFilterTypes.NO_CONSUME.getValue());
+ isBrowser = (isBrowserObj != null) && isBrowserObj.booleanValue();
+ }
+ else
+ {
+ isBrowser = false;
+ }
+
+ if(isBrowser)
+ {
+ return new SubscriptionImpl.BrowserSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod);
+ }
+ else if(acks)
+ {
+ return new SubscriptionImpl.AckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod);
+ }
+ else
+ {
+ return new SubscriptionImpl.NoAckSubscription(channel, protocolSession, consumerTag, filters, noLocal, creditManager, clientMethod, recordMethod);
+ }
+ }
+
+
+ public static final SubscriptionFactoryImpl INSTANCE = new SubscriptionFactoryImpl();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
new file mode 100644
index 0000000000..556b87590c
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -0,0 +1,605 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.subscription;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.common.ClientProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.filter.FilterManager;
+import org.apache.qpid.server.filter.FilterManagerFactory;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.store.StoreContext;
+
+/**
+ * Encapsulation of a supscription to a queue. <p/> Ties together the protocol session of a subscriber, the consumer tag
+ * that was given out by the broker and the channel id. <p/>
+ */
+public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener
+{
+
+ private StateListener _stateListener = new StateListener()
+ {
+
+ public void stateChange(Subscription sub, State oldState, State newState)
+ {
+
+ }
+ };
+
+
+ private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE);
+ private final AtomicReference<QueueEntry> _queueContext = new AtomicReference<QueueEntry>(null);
+ private final ClientDeliveryMethod _deliveryMethod;
+ private final RecordDeliveryMethod _recordMethod;
+
+ private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
+ private final Lock _stateChangeLock;
+
+ static final class BrowserSubscription extends SubscriptionImpl
+ {
+ public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager,
+ ClientDeliveryMethod deliveryMethod,
+ RecordDeliveryMethod recordMethod)
+ throws AMQException
+ {
+ super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
+ }
+
+
+ public boolean isBrowser()
+ {
+ return true;
+ }
+
+ /**
+ * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
+ * thread safe.
+ *
+ * @param msg The message to send
+ * @throws AMQException
+ */
+ public void send(QueueEntry msg) throws AMQException
+ {
+ // We don't decrement the reference here as we don't want to consume the message
+ // but we do want to send it to the client.
+
+ synchronized (getChannel())
+ {
+ long deliveryTag = getChannel().getNextDeliveryTag();
+ sendToClient(msg, deliveryTag);
+ }
+
+ }
+ }
+
+ public static class NoAckSubscription extends SubscriptionImpl
+ {
+ public NoAckSubscription(AMQChannel channel, AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager,
+ ClientDeliveryMethod deliveryMethod,
+ RecordDeliveryMethod recordMethod)
+ throws AMQException
+ {
+ super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
+ }
+
+
+ public boolean isBrowser()
+ {
+ return false;
+ }
+
+ /**
+ * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
+ * thread safe.
+ *
+ * @param entry The message to send
+ * @throws AMQException
+ */
+ public void send(QueueEntry entry) throws AMQException
+ {
+
+ StoreContext storeContext = getChannel().getStoreContext();
+ try
+ { // if we do not need to wait for client acknowledgements
+ // we can decrement the reference count immediately.
+
+ // By doing this _before_ the send we ensure that it
+ // doesn't get sent if it can't be dequeued, preventing
+ // duplicate delivery on recovery.
+
+ // The send may of course still fail, in which case, as
+ // the message is unacked, it will be lost.
+ entry.dequeue(storeContext);
+
+
+ synchronized (getChannel())
+ {
+ long deliveryTag = getChannel().getNextDeliveryTag();
+
+ sendToClient(entry, deliveryTag);
+
+ }
+ entry.dispose(storeContext);
+ }
+ finally
+ {
+ //Only set delivered if it actually was writen successfully..
+ // using a try->finally would set it even if an error occured.
+ // Is this what we want?
+
+ entry.setDeliveredToSubscription();
+ }
+ }
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return false;
+ }
+
+ }
+
+ static final class AckSubscription extends SubscriptionImpl
+ {
+ public AckSubscription(AMQChannel channel, AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, FieldTable filters,
+ boolean noLocal, FlowCreditManager creditManager,
+ ClientDeliveryMethod deliveryMethod,
+ RecordDeliveryMethod recordMethod)
+ throws AMQException
+ {
+ super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
+ }
+
+ public boolean isBrowser()
+ {
+ return false;
+ }
+
+
+ /**
+ * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
+ * thread safe.
+ *
+ * @param entry The message to send
+ * @throws AMQException
+ */
+ public void send(QueueEntry entry) throws AMQException
+ {
+
+ try
+ { // if we do not need to wait for client acknowledgements
+ // we can decrement the reference count immediately.
+
+ // By doing this _before_ the send we ensure that it
+ // doesn't get sent if it can't be dequeued, preventing
+ // duplicate delivery on recovery.
+
+ // The send may of course still fail, in which case, as
+ // the message is unacked, it will be lost.
+
+ synchronized (getChannel())
+ {
+ long deliveryTag = getChannel().getNextDeliveryTag();
+
+
+ recordMessageDelivery(entry, deliveryTag);
+ sendToClient(entry, deliveryTag);
+
+
+ }
+ }
+ finally
+ {
+ //Only set delivered if it actually was writen successfully..
+ // using a try->finally would set it even if an error occured.
+ // Is this what we want?
+
+ entry.setDeliveredToSubscription();
+ }
+ }
+
+
+ }
+
+
+ private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class);
+
+ private final AMQChannel _channel;
+
+ private final AMQShortString _consumerTag;
+
+
+ private final boolean _noLocal;
+
+ private final FlowCreditManager _creditManager;
+
+ private FilterManager _filters;
+
+ private final Boolean _autoClose;
+
+
+ private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString();
+
+ private AMQQueue _queue;
+ private final AtomicBoolean _deleted = new AtomicBoolean(false);
+
+
+
+
+ public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession,
+ AMQShortString consumerTag, FieldTable arguments,
+ boolean noLocal, FlowCreditManager creditManager,
+ ClientDeliveryMethod deliveryMethod,
+ RecordDeliveryMethod recordMethod)
+ throws AMQException
+ {
+
+ _channel = channel;
+ _consumerTag = consumerTag;
+
+ _creditManager = creditManager;
+ creditManager.addStateListener(this);
+
+ _noLocal = noLocal;
+
+
+ _filters = FilterManagerFactory.createManager(arguments);
+
+ _deliveryMethod = deliveryMethod;
+ _recordMethod = recordMethod;
+
+
+ _stateChangeLock = new ReentrantLock();
+
+
+ if (arguments != null)
+ {
+ Object autoClose = arguments.get(AMQPFilterTypes.AUTO_CLOSE.getValue());
+ if (autoClose != null)
+ {
+ _autoClose = (Boolean) autoClose;
+ }
+ else
+ {
+ _autoClose = false;
+ }
+ }
+ else
+ {
+ _autoClose = false;
+ }
+
+
+ }
+
+
+
+ public synchronized void setQueue(AMQQueue queue)
+ {
+ if(getQueue() != null)
+ {
+ throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue());
+ }
+ _queue = queue;
+ }
+
+ public String toString()
+ {
+ String subscriber = "[channel=" + _channel +
+ ", consumerTag=" + _consumerTag +
+ ", session=" + getProtocolSession().getKey() ;
+
+ return subscriber + "]";
+ }
+
+ /**
+ * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
+ * thread safe.
+ *
+ * @param msg The message to send
+ * @throws AMQException
+ */
+ abstract public void send(QueueEntry msg) throws AMQException;
+
+
+ public boolean isSuspended()
+ {
+ return !isActive() || _channel.isSuspended() || _deleted.get();
+ }
+
+ /**
+ * Callback indicating that a queue has been deleted.
+ *
+ * @param queue The queue to delete
+ */
+ public void queueDeleted(AMQQueue queue)
+ {
+ _deleted.set(true);
+// _channel.queueDeleted(queue);
+ }
+
+ public boolean filtersMessages()
+ {
+ return _filters != null || _noLocal;
+ }
+
+ public boolean hasInterest(QueueEntry entry)
+ {
+ //check that the message hasn't been rejected
+ if (entry.isRejectedBy(this))
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity());
+ }
+// return false;
+ }
+
+
+
+ //todo - client id should be recoreded and this test removed but handled below
+ if (_noLocal)
+ {
+ final Object publisherId = entry.getMessage().getPublisherClientInstance();
+
+ // We don't want local messages so check to see if message is one we sent
+ Object localInstance;
+
+ if (publisherId != null && (getProtocolSession().getClientProperties() != null) &&
+ (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null)
+ {
+ if(publisherId.equals(localInstance))
+ {
+ return false;
+ }
+ }
+ else
+ {
+
+ localInstance = getProtocolSession().getClientIdentifier();
+ //todo - client id should be recoreded and this test removed but handled here
+
+
+ if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier()))
+ {
+ return false;
+ }
+ }
+
+
+ }
+
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity());
+ }
+ return checkFilters(entry);
+
+ }
+
+ private String id = String.valueOf(System.identityHashCode(this));
+
+ private String debugIdentity()
+ {
+ return id;
+ }
+
+ private boolean checkFilters(QueueEntry msg)
+ {
+ return (_filters == null) || _filters.allAllow(msg.getMessage());
+ }
+
+ public boolean isAutoClose()
+ {
+ return _autoClose;
+ }
+
+ public FlowCreditManager getCreditManager()
+ {
+ return _creditManager;
+ }
+
+
+ public void close()
+ {
+ boolean closed = false;
+ State state = getState();
+
+ _stateChangeLock.lock();
+ try
+ {
+ while(!closed && state != State.CLOSED)
+ {
+ closed = _state.compareAndSet(state, State.CLOSED);
+ if(!closed)
+ {
+ state = getState();
+ }
+ else
+ {
+ _stateListener.stateChange(this,state, State.CLOSED);
+ }
+ }
+ _creditManager.removeListener(this);
+ }
+ finally
+ {
+ _stateChangeLock.unlock();
+ }
+
+
+ if (closed)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Called close() on a closed subscription");
+ }
+
+ return;
+ }
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing subscription (" + debugIdentity() + "):" + this);
+ }
+ }
+
+ public boolean isClosed()
+ {
+ return getState() == State.CLOSED;
+ }
+
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return !_creditManager.useCreditForMessage(msg.getMessage());//_channel.wouldSuspend(msg.getMessage());
+ }
+
+ public void getSendLock()
+ {
+ _stateChangeLock.lock();
+ }
+
+ public void releaseSendLock()
+ {
+ _stateChangeLock.unlock();
+ }
+
+ public void resend(final QueueEntry entry) throws AMQException
+ {
+ _queue.resend(entry, this);
+ }
+
+ public AMQChannel getChannel()
+ {
+ return _channel;
+ }
+
+ public AMQShortString getConsumerTag()
+ {
+ return _consumerTag;
+ }
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _channel.getProtocolSession();
+ }
+
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ public void restoreCredit(final QueueEntry queueEntry)
+ {
+ _creditManager.addCredit(1, queueEntry.getSize());
+ }
+
+
+ public void creditStateChanged(boolean hasCredit)
+ {
+
+ if(hasCredit)
+ {
+ if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
+ {
+ _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE);
+ }
+ else
+ {
+ // this is a hack to get round the issue of increasing bytes credit
+ _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE);
+ }
+ }
+ else
+ {
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
+ }
+ }
+
+ public State getState()
+ {
+ return _state.get();
+ }
+
+
+ public void setStateListener(final StateListener listener)
+ {
+ _stateListener = listener;
+ }
+
+
+ public QueueEntry getLastSeenEntry()
+ {
+ return _queueContext.get();
+ }
+
+ public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue)
+ {
+ return _queueContext.compareAndSet(expected,newvalue);
+ }
+
+
+ protected void sendToClient(final QueueEntry entry, final long deliveryTag)
+ throws AMQException
+ {
+ _deliveryMethod.deliverToClient(this,entry,deliveryTag);
+ }
+
+
+ protected void recordMessageDelivery(final QueueEntry entry, final long deliveryTag)
+ {
+ _recordMethod.recordMessageDelivery(this,entry,deliveryTag);
+ }
+
+
+ public boolean isActive()
+ {
+ return getState() == State.ACTIVE;
+ }
+
+ public QueueEntry.SubscriptionAcquiredState getOwningState()
+ {
+ return _owningState;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java
new file mode 100644
index 0000000000..3fbb6bfa4a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionList.java
@@ -0,0 +1,247 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.subscription;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.subscription.Subscription;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.nio.ByteBuffer;
+
+public class SubscriptionList
+{
+
+ private final SubscriptionNode _head = new SubscriptionNode();
+
+ private AtomicReference<SubscriptionNode> _tail = new AtomicReference<SubscriptionNode>(_head);
+ private final AMQQueue _queue;
+ private AtomicInteger _size = new AtomicInteger();
+
+
+ public final class SubscriptionNode
+ {
+ private final AtomicBoolean _deleted = new AtomicBoolean();
+ private final AtomicReference<SubscriptionNode> _next = new AtomicReference<SubscriptionNode>();
+ private final Subscription _sub;
+
+
+ public SubscriptionNode()
+ {
+
+ _sub = null;
+ _deleted.set(true);
+ }
+
+ public SubscriptionNode(final Subscription sub)
+ {
+ _sub = sub;
+ }
+
+
+ public SubscriptionNode getNext()
+ {
+
+ SubscriptionNode next = nextNode();
+ while(next != null && next.isDeleted())
+ {
+
+ final SubscriptionNode newNext = next.nextNode();
+ if(newNext != null)
+ {
+ _next.compareAndSet(next, newNext);
+ next = nextNode();
+ }
+ else
+ {
+ next = null;
+ }
+
+ }
+ return next;
+ }
+
+ private SubscriptionNode nextNode()
+ {
+ return _next.get();
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted.get();
+ }
+
+
+ public boolean delete()
+ {
+ if(_deleted.compareAndSet(false,true))
+ {
+ _size.decrementAndGet();
+ advanceHead();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+ public Subscription getSubscription()
+ {
+ return _sub;
+ }
+ }
+
+
+ public SubscriptionList(AMQQueue queue)
+ {
+ _queue = queue;
+ }
+
+ private void advanceHead()
+ {
+ SubscriptionNode head = _head.nextNode();
+ while(head._next.get() != null && head.isDeleted())
+ {
+
+ final SubscriptionNode newhead = head.nextNode();
+ if(newhead != null)
+ {
+ _head._next.compareAndSet(head, newhead);
+ }
+ head = _head.nextNode();
+ }
+ }
+
+
+ public SubscriptionNode add(Subscription sub)
+ {
+ SubscriptionNode node = new SubscriptionNode(sub);
+ for (;;)
+ {
+ SubscriptionNode tail = _tail.get();
+ SubscriptionNode next = tail.nextNode();
+ if (tail == _tail.get())
+ {
+ if (next == null)
+ {
+ if (tail._next.compareAndSet(null, node))
+ {
+ _tail.compareAndSet(tail, node);
+ _size.incrementAndGet();
+ return node;
+ }
+ }
+ else
+ {
+ _tail.compareAndSet(tail, next);
+ }
+ }
+ }
+
+ }
+
+ public boolean remove(Subscription sub)
+ {
+ SubscriptionNode node = _head.getNext();
+ while(node != null)
+ {
+ if(sub.equals(node._sub) && node.delete())
+ {
+ return true;
+ }
+ node = node.getNext();
+ }
+ return false;
+ }
+
+
+ public class SubscriptionNodeIterator
+ {
+
+ private SubscriptionNode _lastNode;
+
+ SubscriptionNodeIterator(SubscriptionNode startNode)
+ {
+ _lastNode = startNode;
+ }
+
+
+ public boolean atTail()
+ {
+ return _lastNode.nextNode() == null;
+ }
+
+ public SubscriptionNode getNode()
+ {
+
+ return _lastNode;
+
+ }
+
+ public boolean advance()
+ {
+
+ if(!atTail())
+ {
+ SubscriptionNode nextNode = _lastNode.nextNode();
+ while(nextNode.isDeleted() && nextNode.nextNode() != null)
+ {
+ nextNode = nextNode.nextNode();
+ }
+ _lastNode = nextNode;
+ return true;
+
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+
+ public SubscriptionNodeIterator iterator()
+ {
+ return new SubscriptionNodeIterator(_head);
+ }
+
+
+ public SubscriptionNode getHead()
+ {
+ return _head;
+ }
+
+ public int size()
+ {
+ return _size.get();
+ }
+
+
+
+}
+
+
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java
index 23aaf56876..b67bb98e28 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java
@@ -97,6 +97,10 @@ public class ConnectorConfiguration
defaultValue = "false")
public boolean _multiThreadNIO;
+ @Configured(path = "advanced.useWriteBiasedPool",
+ defaultValue = "false")
+ public boolean useBiasedWrites;
+
public IoAcceptor createAcceptor()
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java
deleted file mode 100644
index 988f589339..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.txn;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.NoConsumersException;
-import org.apache.qpid.server.store.StoreContext;
-
-import java.util.List;
-
-/**
- * @author Apache Software Foundation
- */
-public class CleanupMessageOperation implements TxnOp
-{
- private static final Logger _log = Logger.getLogger(CleanupMessageOperation.class);
-
- private final AMQMessage _msg;
-
- private final List<RequiredDeliveryException> _returns;
-
- public CleanupMessageOperation(AMQMessage msg, List<RequiredDeliveryException> returns)
- {
- _msg = msg;
- _returns = returns;
- }
-
- public void prepare(StoreContext context) throws AMQException
- { }
-
- public void undoPrepare()
- {
- // don't need to do anything here, if the store's txn failed
- // when processing prepare then the message was not stored
- // or enqueued on any queues and can be discarded
- }
-
- public void commit(StoreContext context)
- {
- // No-op can't be done here has this is before the message has been attempted to be delivered.
- /*try
- {
- _msg.checkDeliveredToConsumer();
- }
- catch (NoConsumersException e)
- {
- _returns.add(e);
- }*/
- }
-
- public void rollback(StoreContext context)
- {
- // NO OP
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
index 2307b94566..ad8303ec5d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
@@ -24,18 +24,16 @@ import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.ack.TxAck;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.NoConsumersException;
-import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoreContext;
-import java.util.LinkedList;
import java.util.List;
+import java.util.ArrayList;
/** A transactional context that only supports local transactions. */
public class LocalTransactionalContext implements TransactionalContext
@@ -44,7 +42,7 @@ public class LocalTransactionalContext implements TransactionalContext
private final TxnBuffer _txnBuffer = new TxnBuffer();
- private final List<DeliveryDetails> _postCommitDeliveryList = new LinkedList<DeliveryDetails>();
+ private final List<DeliveryAction> _postCommitDeliveryList = new ArrayList<DeliveryAction>();
/**
* We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are
@@ -52,81 +50,112 @@ public class LocalTransactionalContext implements TransactionalContext
*/
private TxAck _ackOp;
- private List<RequiredDeliveryException> _returnMessages;
-
- private final MessageStore _messageStore;
-
- private final StoreContext _storeContext;
-
private boolean _inTran = false;
/** Are there messages to deliver. NOT Has the message been delivered */
private boolean _messageDelivered = false;
+ private final AMQChannel _channel;
- private static class DeliveryDetails
+
+ private abstract class DeliveryAction
{
- public QueueEntry entry;
- private boolean deliverFirst;
+ abstract public void process() throws AMQException;
- public DeliveryDetails(QueueEntry entry, boolean deliverFirst)
+ }
+
+ private class RequeueAction extends DeliveryAction
+ {
+ public QueueEntry entry;
+
+ public RequeueAction(QueueEntry entry)
{
this.entry = entry;
- this.deliverFirst = deliverFirst;
+ }
+
+ public void process() throws AMQException
+ {
+ entry.requeue(getStoreContext());
+ }
+ }
+
+ private class PublishAction extends DeliveryAction
+ {
+ private final AMQQueue _queue;
+ private final AMQMessage _message;
+
+ public PublishAction(final AMQQueue queue, final AMQMessage message)
+ {
+ _queue = queue;
+ _message = message;
+ }
+
+ public void process() throws AMQException
+ {
+
+ QueueEntry entry = _queue.enqueue(getStoreContext(),_message);
+
+ if(entry.immediateAndNotDelivered())
+ {
+ getReturnMessages().add(new NoConsumersException(_message));
+ }
}
}
- public LocalTransactionalContext(MessageStore messageStore, StoreContext storeContext,
- List<RequiredDeliveryException> returnMessages)
+ public LocalTransactionalContext(final AMQChannel channel)
{
- _messageStore = messageStore;
- _storeContext = storeContext;
- _returnMessages = returnMessages;
- // _txnBuffer.enlist(new StoreMessageOperation(messageStore));
+ _channel = channel;
}
public StoreContext getStoreContext()
{
- return _storeContext;
+ return _channel.getStoreContext();
}
+ public List<RequiredDeliveryException> getReturnMessages()
+ {
+ return _channel.getReturnMessages();
+ }
+
+ public MessageStore getMessageStore()
+ {
+ return _channel.getMessageStore();
+ }
+
+
public void rollback() throws AMQException
{
- _txnBuffer.rollback(_storeContext);
+ _txnBuffer.rollback(getStoreContext());
// Hack to deal with uncommitted non-transactional writes
- if (_messageStore.inTran(_storeContext))
+ if (getMessageStore().inTran(getStoreContext()))
{
- _messageStore.abortTran(_storeContext);
+ getMessageStore().abortTran(getStoreContext());
_inTran = false;
}
_postCommitDeliveryList.clear();
}
- public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException
+ public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException
{
// A publication will result in the enlisting of several
// TxnOps. The first is an op that will store the message.
// Following that (and ordering is important), an op will
// be added for every queue onto which the message is
- // enqueued. Finally a cleanup op will be added to decrement
- // the reference associated with the routing.
- // message.incrementReference();
- _postCommitDeliveryList.add(new DeliveryDetails(entry, deliverFirst));
+ // enqueued.
+ _postCommitDeliveryList.add(new PublishAction(queue, message));
_messageDelivered = true;
- _txnBuffer.enlist(new CleanupMessageOperation(entry.getMessage(), _returnMessages));
- /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue));
- if (_log.isDebugEnabled())
- {
- _log.debug("Incrementing ref count on message and enlisting cleanup operation - id " +
- message.getMessageId());
- }
- message.incrementReference();
+
+ }
+
+ public void requeue(QueueEntry entry) throws AMQException
+ {
+ _postCommitDeliveryList.add(new RequeueAction(entry));
_messageDelivered = true;
- */
}
+
private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException
{
if (!unacknowledgedMessageMap.contains(deliveryTag))
@@ -147,10 +176,8 @@ public class LocalTransactionalContext implements TransactionalContext
// as new acks come in. If this is the first ack in the txn
// we will need to create and enlist the op.
if (_ackOp == null)
- {
-
+ {
_ackOp = new TxAck(unacknowledgedMessageMap);
-
_txnBuffer.enlist(_ackOp);
}
// update the op to include this ack request
@@ -189,7 +216,7 @@ public class LocalTransactionalContext implements TransactionalContext
_log.debug("Starting transaction on message store: " + this);
}
- _messageStore.beginTran(_storeContext);
+ getMessageStore().beginTran(getStoreContext());
_inTran = true;
}
}
@@ -212,22 +239,22 @@ public class LocalTransactionalContext implements TransactionalContext
if (_messageDelivered && _inTran)
{
- _txnBuffer.enlist(new StoreMessageOperation(_messageStore));
+ _txnBuffer.enlist(new StoreMessageOperation(getMessageStore()));
}
// fixme fail commit here ... QPID-440
try
{
- _txnBuffer.commit(_storeContext);
+ _txnBuffer.commit(getStoreContext());
}
finally
{
_messageDelivered = false;
- _inTran = _messageStore.inTran(_storeContext);
+ _inTran = getMessageStore().inTran(getStoreContext());
}
try
{
- postCommitDelivery(_returnMessages);
+ postCommitDelivery();
}
catch (AMQException e)
{
@@ -236,7 +263,7 @@ public class LocalTransactionalContext implements TransactionalContext
}
}
- private void postCommitDelivery(List<RequiredDeliveryException> returnMessages) throws AMQException
+ private void postCommitDelivery() throws AMQException
{
if (_log.isDebugEnabled())
{
@@ -245,18 +272,9 @@ public class LocalTransactionalContext implements TransactionalContext
try
{
- for (DeliveryDetails dd : _postCommitDeliveryList)
+ for (DeliveryAction dd : _postCommitDeliveryList)
{
- dd.entry.process(_storeContext, dd.deliverFirst);
-
- try
- {
- dd.entry.checkDeliveredToConsumer();
- }
- catch (NoConsumersException nce)
- {
- returnMessages.add(nce);
- }
+ dd.process();
}
}
finally
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
index cac3489f4c..18f1836185 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
@@ -22,19 +22,14 @@ package org.apache.qpid.server.txn;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.ack.UnacknowledgedMessage;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.NoConsumersException;
-import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoreContext;
@@ -49,6 +44,8 @@ public class NonTransactionalContext implements TransactionalContext
/** Where to put undeliverable messages */
private final List<RequiredDeliveryException> _returnMessages;
+
+
private final MessageStore _messageStore;
private final StoreContext _storeContext;
@@ -57,12 +54,6 @@ public class NonTransactionalContext implements TransactionalContext
private boolean _inTran;
public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel,
- List<RequiredDeliveryException> returnMessages, Set<Long> browsedAcks)
- {
- this(messageStore,storeContext,channel,returnMessages);
- }
-
- public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel,
List<RequiredDeliveryException> returnMessages)
{
_channel = channel;
@@ -97,19 +88,22 @@ public class NonTransactionalContext implements TransactionalContext
// Does not apply to this context
}
- public void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException
+ public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException
{
- try
+ QueueEntry entry = queue.enqueue(_storeContext, message);
+
+ //following check implements the functionality
+ //required by the 'immediate' flag:
+ if(entry.immediateAndNotDelivered())
{
- entry.process(_storeContext, deliverFirst);
- //following check implements the functionality
- //required by the 'immediate' flag:
- entry.checkDeliveredToConsumer();
- }
- catch (NoConsumersException e)
- {
- _returnMessages.add(e);
+ _returnMessages.add(new NoConsumersException(entry.getMessage()));
}
+
+ }
+
+ public void requeue(QueueEntry entry) throws AMQException
+ {
+ entry.requeue(_storeContext);
}
public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag,
@@ -118,7 +112,7 @@ public class NonTransactionalContext implements TransactionalContext
{
final boolean debug = _log.isDebugEnabled();
-
+ ;
if (multiple)
{
if (deliveryTag == 0)
@@ -130,7 +124,7 @@ public class NonTransactionalContext implements TransactionalContext
unacknowledgedMessageMap.size());
unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
{
- public boolean callback(UnacknowledgedMessage message) throws AMQException
+ public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException
{
if (debug)
{
@@ -140,6 +134,7 @@ public class NonTransactionalContext implements TransactionalContext
{
beginTranIfNecessary();
}
+ message.restoreCredit();
//Message has been ack so discard it. This will dequeue and decrement the reference.
message.discard(_storeContext);
@@ -159,27 +154,27 @@ public class NonTransactionalContext implements TransactionalContext
throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel");
}
- LinkedList<UnacknowledgedMessage> acked = new LinkedList<UnacknowledgedMessage>();
+ LinkedList<QueueEntry> acked = new LinkedList<QueueEntry>();
unacknowledgedMessageMap.drainTo(acked, deliveryTag);
- for (UnacknowledgedMessage msg : acked)
+ for (QueueEntry msg : acked)
{
- if (debug)
- {
- _log.debug("Discarding message: " + msg.getMessage().getMessageId());
- }
- if(msg.getMessage().isPersistent())
- {
- beginTranIfNecessary();
- }
+ if (debug)
+ {
+ _log.debug("Discarding message: " + msg.getMessage().getMessageId());
+ }
+ if(msg.getMessage().isPersistent())
+ {
+ beginTranIfNecessary();
+ }
- //Message has been ack so discard it. This will dequeue and decrement the reference.
- msg.discard(_storeContext);
+ //Message has been ack so discard it. This will dequeue and decrement the reference.
+ msg.discard(_storeContext);
}
}
}
else
{
- UnacknowledgedMessage msg;
+ QueueEntry msg;
msg = unacknowledgedMessageMap.remove(deliveryTag);
if (msg == null)
@@ -208,13 +203,11 @@ public class NonTransactionalContext implements TransactionalContext
msg.getMessage().getMessageId());
}
}
-
if(_inTran)
{
_messageStore.commitTran(_storeContext);
_inTran = false;
}
-
}
public void messageFullyReceived(boolean persistent) throws AMQException
@@ -228,6 +221,6 @@ public class NonTransactionalContext implements TransactionalContext
public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException
{
- _channel.processReturns(protocolSession);
+ _channel.processReturns();
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java
index 6016ecc1a5..647ba66fb4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java
@@ -25,6 +25,7 @@ import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.store.StoreContext;
/**
@@ -106,18 +107,26 @@ public interface TransactionalContext
void rollback() throws AMQException;
/**
- * Delivers the specified message to the specified queue. A 'deliverFirst' flag may be set if the message is a
- * redelivery, and should be placed on the front of the queue.
+ * Delivers the specified message to the specified queue.
*
* <p/>This is an 'enqueue' operation.
*
- * @param entry The message to deliver, and the queue to deliver to.
- * @param deliverFirst <tt>true</tt> to place the message on the front of the queue for redelivery, <tt>false</tt>
- * for normal FIFO message ordering.
- *
+ * @param queue
+ * @param message The message to deliver
* @throws AMQException If the message cannot be delivered for any reason.
*/
- void deliver(QueueEntry entry, boolean deliverFirst) throws AMQException;
+ void deliver(final AMQQueue queue, AMQMessage message) throws AMQException;
+
+ /**
+ * Requeues the specified message entry (message queue pair)
+ *
+ *
+ * @param queueEntry The message,queue pair
+ *
+ * @throws AMQException If the message cannot be delivered for any reason.
+ */
+ void requeue(QueueEntry queueEntry) throws AMQException;
+
/**
* Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
index 70a76dd8c2..85d804457e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
@@ -1,44 +1,44 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.virtualhost;
-
-import java.io.IOException;
-
-import org.apache.qpid.server.management.MBeanAttribute;
-
-/**
- * The management interface exposed to allow management of an Exchange.
- * @version 0.1
- */
-public interface ManagedVirtualHost
-{
- static final String TYPE = "VirtualHost";
-
- /**
- * Returns the name of the managed virtualHost.
- * @return the name of the exchange.
- * @throws java.io.IOException
- */
- @MBeanAttribute(name="Name", description= TYPE + " Name")
- String getName() throws IOException;
-
-
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.virtualhost;
+
+import java.io.IOException;
+
+import org.apache.qpid.server.management.MBeanAttribute;
+
+/**
+ * The management interface exposed to allow management of an Exchange.
+ * @version 0.1
+ */
+public interface ManagedVirtualHost
+{
+ static final String TYPE = "VirtualHost";
+
+ /**
+ * Returns the name of the managed virtualHost.
+ * @return the name of the exchange.
+ * @throws java.io.IOException
+ */
+ @MBeanAttribute(name="Name", description= TYPE + " Name")
+ String getName() throws IOException;
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
index 90dc7432b2..8b764efa42 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
@@ -71,8 +71,8 @@ public class VirtualHost implements Accessable
private ACLPlugin _accessManager;
- private Timer _houseKeepingTimer;
-
+ private final Timer _houseKeepingTimer = new Timer("Queue-housekeeping", true);
+
private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L;
public void setAccessableName(String name)
@@ -172,25 +172,22 @@ public class VirtualHost implements Accessable
_brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
_brokerMBean.register();
-
- _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true);
-
initialiseHouseKeeping(hostConfig);
}
private void initialiseHouseKeeping(final Configuration hostConfig)
{
-
+
long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD);
-
+
/* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */
- if (period != 0L)
+ if(period != 0L)
{
class RemoveExpiredMessagesTask extends TimerTask
{
public void run()
{
- for (AMQQueue q : _queueRegistry.getQueues())
+ for(AMQQueue q : _queueRegistry.getQueues())
{
try
@@ -199,7 +196,7 @@ public class VirtualHost implements Accessable
}
catch (AMQException e)
{
- _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e);
+ _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e);
throw new RuntimeException(e);
}
}
@@ -207,11 +204,11 @@ public class VirtualHost implements Accessable
}
_houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(),
- period / 2,
- period);
+ period/2,
+ period);
}
}
-
+
private void initialiseMessageStore(Configuration config) throws Exception
{
String messageStoreClass = config.getString("store.class");
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
index 9b1619c609..27917fac8a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
@@ -1,70 +1,70 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT 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.virtualhost;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-
-public class VirtualHostRegistry
-{
- private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String,VirtualHost>();
-
-
- private String _defaultVirtualHostName;
-
- public synchronized void registerVirtualHost(VirtualHost host) throws Exception
- {
- if(_registry.containsKey(host.getName()))
- {
- throw new Exception("Virtual Host with name " + host.getName() + " already registered.");
- }
- _registry.put(host.getName(),host);
- }
-
- public VirtualHost getVirtualHost(String name)
- {
- if(name == null || name.trim().length() == 0 )
- {
- name = getDefaultVirtualHostName();
- }
-
- return _registry.get(name);
- }
-
- private String getDefaultVirtualHostName()
- {
- return _defaultVirtualHostName;
- }
-
- public void setDefaultVirtualHostName(String defaultVirtualHostName)
- {
- _defaultVirtualHostName = defaultVirtualHostName;
- }
-
-
- public Collection<VirtualHost> getVirtualHosts()
- {
- return new ArrayList<VirtualHost>(_registry.values());
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.virtualhost;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+public class VirtualHostRegistry
+{
+ private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String,VirtualHost>();
+
+
+ private String _defaultVirtualHostName;
+
+ public synchronized void registerVirtualHost(VirtualHost host) throws Exception
+ {
+ if(_registry.containsKey(host.getName()))
+ {
+ throw new Exception("Virtual Host with name " + host.getName() + " already registered.");
+ }
+ _registry.put(host.getName(),host);
+ }
+
+ public VirtualHost getVirtualHost(String name)
+ {
+ if(name == null || name.trim().length() == 0 )
+ {
+ name = getDefaultVirtualHostName();
+ }
+
+ return _registry.get(name);
+ }
+
+ private String getDefaultVirtualHostName()
+ {
+ return _defaultVirtualHostName;
+ }
+
+ public void setDefaultVirtualHostName(String defaultVirtualHostName)
+ {
+ _defaultVirtualHostName = defaultVirtualHostName;
+ }
+
+
+ public Collection<VirtualHost> getVirtualHosts()
+ {
+ return new ArrayList<VirtualHost>(_registry.values());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
index edc900f401..faa7b85d58 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
@@ -25,11 +25,11 @@ import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.configuration.Configuration;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.tools.messagestore.commands.Clear;
import org.apache.qpid.tools.messagestore.commands.Command;
import org.apache.qpid.tools.messagestore.commands.Copy;
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
index a5b3a87616..0869d9a497 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
@@ -20,8 +20,8 @@
*/
package org.apache.qpid.tools.messagestore.commands;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
+import org.apache.qpid.server.queue.AMQQueue;
public class Copy extends Move
{
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
index 218d5f04ed..731f6140f9 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
@@ -24,6 +24,7 @@ import org.apache.commons.codec.binary.Hex;
import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntryImpl;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import org.apache.qpid.tools.utils.Console;
@@ -255,7 +256,7 @@ public class Dump extends Show
String title, boolean routing, boolean headers, boolean messageHeaders)
{
List<QueueEntry> single = new LinkedList<QueueEntry>();
- single.add(new QueueEntry(null,msg));
+ single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE));
List<List> routingData = super.createMessageData(null, single, headers, routing, messageHeaders);
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
index 7e21253fab..a8dd58ca83 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
@@ -21,7 +21,7 @@
package org.apache.qpid.tools.messagestore.commands;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntryImpl;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.store.StoreContext;
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
index f187e26593..5e99997863 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
@@ -20,9 +20,8 @@
*/
package org.apache.qpid.tools.messagestore.commands;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
+import org.apache.qpid.server.queue.AMQQueue;
public class Purge extends Move
{
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
index fd7d4c3f13..ff59568374 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
@@ -22,9 +22,9 @@ package org.apache.qpid.tools.messagestore.commands;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import java.util.LinkedList;
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
index a6dccf0f36..2fa017fc64 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
@@ -26,6 +26,7 @@ import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntryImpl;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
@@ -33,7 +34,6 @@ import org.apache.qpid.tools.utils.Console;
import java.util.LinkedList;
import java.util.List;
-import java.util.StringTokenizer;
public class Show extends AbstractCommand
{
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
index 2898cb38a6..3e8b1d0998 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
@@ -22,9 +22,7 @@ package org.apache.qpid.server.exchange;
import junit.framework.TestCase;
import junit.framework.Assert;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.txn.NonTransactionalContext;
@@ -33,6 +31,7 @@ import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.protocol.TestMinaProtocolSession;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
@@ -43,57 +42,51 @@ import java.util.LinkedList;
public class DestWildExchangeTest extends TestCase
{
- DestWildExchange _exchange;
+ TopicExchange _exchange;
VirtualHost _vhost;
MessageStore _store;
StoreContext _context;
+ TestMinaProtocolSession _protocolSession;
+
public void setUp() throws AMQException
{
- _exchange = new DestWildExchange();
+ _exchange = new TopicExchange();
_vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next();
_store = new MemoryMessageStore();
_context = new StoreContext();
+ _protocolSession = new TestMinaProtocolSession();
}
public void testNoRoute() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a*#b"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b"));
- AMQMessage message = new AMQMessage(0L, info, null);
+ IncomingMessage message = new IncomingMessage(0L, info, null, _protocolSession);
- try
- {
- _exchange.route(message);
- fail("Message has no route and shouldn't be routed");
- }
- catch (NoRouteException nre)
- {
- //normal
- }
+ _exchange.route(message);
Assert.assertEquals(0, queue.getMessageCount());
}
public void testDirectMatch() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("ab"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("ab"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.b"), queue, null);
- AMQMessage message = createMessage("a.b");
+ IncomingMessage message = createMessage("a.b");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -102,7 +95,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -112,8 +105,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has no route and should fail to be routed");
}
catch (AMQException nre)
@@ -126,16 +118,15 @@ public class DestWildExchangeTest extends TestCase
public void testStarMatch() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a*"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.*"), queue, null);
- AMQMessage message = createMessage("a.b");
+ IncomingMessage message = createMessage("a.b");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -144,7 +135,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -154,8 +145,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -164,7 +154,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -174,8 +164,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has no route and should fail to be routed");
}
catch (AMQException nre)
@@ -187,16 +176,15 @@ public class DestWildExchangeTest extends TestCase
public void testHashMatch() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a#"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.#"), queue, null);
- AMQMessage message = createMessage("a.b.c");
+ IncomingMessage message = createMessage("a.b.c");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -205,7 +193,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -215,8 +203,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -225,7 +212,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -235,8 +222,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -245,7 +231,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -254,8 +240,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -264,7 +249,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -274,8 +259,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has no route and should fail to be routed");
}
catch (AMQException nre)
@@ -288,16 +272,15 @@ public class DestWildExchangeTest extends TestCase
public void testMidHash() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
- AMQMessage message = createMessage("a.c.d.b");
+ IncomingMessage message = createMessage("a.c.d.b");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -306,7 +289,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -315,8 +298,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -325,7 +307,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -334,16 +316,15 @@ public class DestWildExchangeTest extends TestCase
public void testMatchafterHash() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a#"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.*.#.b.c"), queue, null);
- AMQMessage message = createMessage("a.c.b.b");
+ IncomingMessage message = createMessage("a.c.b.b");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -357,8 +338,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -367,7 +347,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -376,8 +356,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -390,8 +369,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -401,7 +379,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -411,16 +389,15 @@ public class DestWildExchangeTest extends TestCase
public void testHashAfterHash() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a#"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.*.#.b.c.#.d"), queue, null);
- AMQMessage message = createMessage("a.c.b.b.c");
+ IncomingMessage message = createMessage("a.c.b.b.c");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -434,8 +411,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -444,7 +420,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -453,16 +429,15 @@ public class DestWildExchangeTest extends TestCase
public void testHashHash() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a#"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.#.*.#.d"), queue, null);
- AMQMessage message = createMessage("a.c.b.b.c");
+ IncomingMessage message = createMessage("a.c.b.b.c");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -475,8 +450,7 @@ public class DestWildExchangeTest extends TestCase
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
}
catch (AMQException nre)
{
@@ -485,7 +459,7 @@ public class DestWildExchangeTest extends TestCase
Assert.assertEquals(1, queue.getMessageCount());
- Assert.assertEquals("Wrong message recevied", message, queue.getMessagesOnTheQueue().get(0).getMessage());
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
queue.deleteMessageFromTop(_context);
Assert.assertEquals(0, queue.getMessageCount());
@@ -494,16 +468,15 @@ public class DestWildExchangeTest extends TestCase
public void testSubMatchFails() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.b.c.d"), queue, null);
- AMQMessage message = createMessage("a.b.c");
+ IncomingMessage message = createMessage("a.b.c");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -514,18 +487,25 @@ public class DestWildExchangeTest extends TestCase
}
+ private void routeMessage(final IncomingMessage message)
+ throws AMQException
+ {
+ _exchange.route(message);
+ message.routingComplete(_store, new MessageHandleFactory());
+ message.deliverToQueues();
+ }
+
public void testMoreRouting() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.b"), queue, null);
- AMQMessage message = createMessage("a.b.c");
+ IncomingMessage message = createMessage("a.b.c");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -538,16 +518,15 @@ public class DestWildExchangeTest extends TestCase
public void testMoreQueue() throws AMQException
{
- AMQQueue queue = new AMQQueue(new AMQShortString("a"), false, null, false, _vhost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
_exchange.registerQueue(new AMQShortString("a.b"), queue, null);
- AMQMessage message = createMessage("a");
+ IncomingMessage message = createMessage("a");
try
{
- _exchange.route(message);
- message.routingComplete(_store, _context, new MessageHandleFactory());
+ routeMessage(message);
fail("Message has route and should not be routed");
}
catch (AMQException nre)
@@ -558,7 +537,7 @@ public class DestWildExchangeTest extends TestCase
}
- private AMQMessage createMessage(String s) throws AMQException
+ private IncomingMessage createMessage(String s) throws AMQException
{
MessagePublishInfo info = new PublishInfo(new AMQShortString(s));
@@ -566,8 +545,9 @@ public class DestWildExchangeTest extends TestCase
new LinkedList<RequiredDeliveryException>()
);
- AMQMessage message = new AMQMessage(0L, info, trancontext);
- message.setContentHeaderBody(new ContentHeaderBody());
+ IncomingMessage message = new IncomingMessage(0L, info, trancontext,_protocolSession);
+ message.setContentHeaderBody( new ContentHeaderBody());
+
return message;
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
index 18d8592817..2a2bc72950 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
@@ -21,8 +21,9 @@
package org.apache.qpid.server.exchange;
import junit.framework.TestCase;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.management.ManagedObject;
@@ -30,7 +31,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
-import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import java.util.ArrayList;
@@ -50,7 +50,7 @@ public class ExchangeMBeanTest extends TestCase
public void testDirectExchangeMBean() throws Exception
{
- DestNameExchange exchange = new DestNameExchange();
+ DirectExchange exchange = new DirectExchange();
exchange.initialise(_virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true);
ManagedObject managedObj = exchange.getManagedObject();
ManagedExchange mbean = (ManagedExchange)managedObj;
@@ -77,7 +77,7 @@ public class ExchangeMBeanTest extends TestCase
public void testTopicExchangeMBean() throws Exception
{
- DestWildExchange exchange = new DestWildExchange();
+ TopicExchange exchange = new TopicExchange();
exchange.initialise(_virtualHost,ExchangeDefaults.TOPIC_EXCHANGE_NAME, false, 0, true);
ManagedObject managedObj = exchange.getManagedObject();
ManagedExchange mbean = (ManagedExchange)managedObj;
@@ -132,7 +132,8 @@ public class ExchangeMBeanTest extends TestCase
IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance();
_virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
_queueRegistry = _virtualHost.getQueueRegistry();
- _queue = new AMQQueue(new AMQShortString("testQueue"), false, new AMQShortString("ExchangeMBeanTest"), false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("ExchangeMBeanTest"), false, _virtualHost,
+ null);
_queueRegistry.registerQueue(_queue);
}
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/TestMinaProtocolSession.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/TestMinaProtocolSession.java
index 0c0d8f471e..113944cf7e 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/protocol/TestMinaProtocolSession.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/TestMinaProtocolSession.java
@@ -30,9 +30,11 @@ public class TestMinaProtocolSession extends AMQMinaProtocolSession
{
public TestMinaProtocolSession() throws AMQException
{
+
super(new TestIoSession(),
ApplicationRegistry.getInstance().getVirtualHostRegistry(),
new AMQCodecFactory(true));
+
}
public ProtocolOutputConverter getProtocolOutputConverter()
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
index 65db2a6425..ca614e053a 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
@@ -32,18 +32,23 @@ import org.apache.qpid.server.txn.TransactionalContext;
import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.RequiredDeliveryException;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
import org.apache.qpid.server.protocol.TestMinaProtocolSession;
import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.mina.common.ByteBuffer;
import javax.management.Notification;
import java.util.LinkedList;
+import java.util.Collections;
/** This class tests all the alerts an AMQQueue can throw based on threshold values of different parameters */
public class AMQQueueAlertTest extends TestCase
-{
+{
private final static long MAX_MESSAGE_COUNT = 50;
private final static long MAX_MESSAGE_AGE = 250; // 0.25 sec
private final static long MAX_MESSAGE_SIZE = 2000; // 2 KB
@@ -51,13 +56,14 @@ public class AMQQueueAlertTest extends TestCase
private AMQQueue _queue;
private AMQQueueMBean _queueMBean;
private VirtualHost _virtualHost;
- private AMQMinaProtocolSession protocolSession = null;
+ private AMQMinaProtocolSession _protocolSession;
private MessageStore _messageStore = new MemoryMessageStore();
private StoreContext _storeContext = new StoreContext();
private TransactionalContext _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext,
null,
new LinkedList<RequiredDeliveryException>()
);
+ private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
/**
* Tests if the alert gets thrown when message count increases the threshold limit
@@ -66,8 +72,9 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageCountAlert() throws Exception
{
- _queue = new AMQQueue(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"),
- false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
_queueMBean = (AMQQueueMBean) _queue.getManagedObject();
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
@@ -89,8 +96,9 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageSizeAlert() throws Exception
{
- _queue = new AMQQueue(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"),
- false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
_queueMBean = (AMQQueueMBean) _queue.getManagedObject();
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
_queueMBean.setMaximumMessageSize(MAX_MESSAGE_SIZE);
@@ -114,8 +122,9 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testQueueDepthAlertNoSubscriber() throws Exception
{
- _queue = new AMQQueue(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"),
- false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
_queueMBean = (AMQQueueMBean) _queue.getManagedObject();
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
_queueMBean.setMaximumQueueDepth(MAX_QUEUE_DEPTH);
@@ -142,8 +151,9 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageAgeAlert() throws Exception
{
- _queue = new AMQQueue(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"),
- false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
_queueMBean = (AMQQueueMBean) _queue.getManagedObject();
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
_queueMBean.setMaximumMessageAge(MAX_MESSAGE_AGE);
@@ -167,18 +177,23 @@ public class AMQQueueAlertTest extends TestCase
This test sends some messages to the queue with subscribers needing message to be acknowledged.
The messages will not be acknowledged and will be required twice. Why we are checking this is because
the bug reported said that the queueDepth keeps increasing when messages are requeued.
+ // TODO - queue depth now includes unacknowledged messages so does not go down when messages are delivered
+
The QueueDepth should decrease when messages are delivered from the queue (QPID-408)
*/
public void testQueueDepthAlertWithSubscribers() throws Exception
{
- protocolSession = new TestMinaProtocolSession();
- AMQChannel channel = new AMQChannel(protocolSession, 2, _messageStore);
- protocolSession.addChannel(channel);
+ _protocolSession = new TestMinaProtocolSession();
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
// Create queue
_queue = getNewQueue();
- _queue.registerProtocolSession(protocolSession, channel.getChannelId(),
- new AMQShortString("consumer_tag"), true, null, false, false);
+ Subscription subscription =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), _protocolSession, new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(
+ subscription, false);
_queueMBean = (AMQQueueMBean) _queue.getManagedObject();
_queueMBean.setMaximumMessageCount(9999l); // Set a high value, because this is not being tested
@@ -191,13 +206,13 @@ public class AMQQueueAlertTest extends TestCase
// Check queueDepth. There should be no messages on the queue and as the subscriber is listening
// so there should be no Queue_Deoth alert raised
- assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
+ assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
Notification lastNotification = _queueMBean.getLastNotification();
- assertNull(lastNotification);
+// assertNull(lastNotification);
// Kill the subscriber and check for the queue depth values.
// Messages are unacknowledged, so those should get requeued. All messages should be on the Queue
- _queue.unregisterProtocolSession(protocolSession, channel.getChannelId(), new AMQShortString("consumer_tag"));
+ _queue.unregisterSubscription(subscription);
channel.requeue();
assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
@@ -209,29 +224,32 @@ public class AMQQueueAlertTest extends TestCase
// Connect a consumer again and check QueueDepth values. The queue should get emptied.
// Messages will get delivered but still are unacknowledged.
- _queue.registerProtocolSession(protocolSession, channel.getChannelId(),
- new AMQShortString("consumer_tag"), true, null, false, false);
- _queue.deliverAsync();
- while (_queue.getMessageCount() != 0)
+ Subscription subscription2 =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), _protocolSession, new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(
+ subscription2, false);
+
+ while (_queue.getUndeliveredMessageCount()!= 0)
{
Thread.sleep(100);
}
- assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
+// assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
// Kill the subscriber again. Now those messages should get requeued again. Check if the queue depth
// value is correct.
- _queue.unregisterProtocolSession(protocolSession, channel.getChannelId(), new AMQShortString("consumer_tag"));
+ _queue.unregisterSubscription(subscription2);
channel.requeue();
assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
- protocolSession.closeSession();
+ _protocolSession.closeSession();
// Check the clear queue
_queueMBean.clearQueue();
assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
}
- protected AMQMessage message(final boolean immediate, long size) throws AMQException
+ protected IncomingMessage message(final boolean immediate, long size) throws AMQException
{
MessagePublishInfo publish = new MessagePublishInfo()
{
@@ -264,9 +282,9 @@ public class AMQQueueAlertTest extends TestCase
ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
contentHeaderBody.bodySize = size; // in bytes
- AMQMessage message = new AMQMessage(_messageStore.getNewMessageId(), publish, _transactionalContext);
+ IncomingMessage message = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
message.setContentHeaderBody(contentHeaderBody);
- message.setPublisher(protocolSession);
+
return message;
}
@@ -276,30 +294,52 @@ public class AMQQueueAlertTest extends TestCase
super.setUp();
IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance();
_virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
+ _protocolSession = new TestMinaProtocolSession();
+
}
- private void sendMessages(long messageCount, long size) throws AMQException
+ private void sendMessages(long messageCount, final long size) throws AMQException
{
- AMQMessage[] messages = new AMQMessage[(int) messageCount];
+ IncomingMessage[] messages = new IncomingMessage[(int) messageCount];
for (int i = 0; i < messages.length; i++)
{
messages[i] = message(false, size);
- messages[i].enqueue(_queue);
- messages[i].routingComplete(_messageStore, _storeContext, new MessageHandleFactory());
+ messages[i].enqueue(Collections.singleton(_queue));
+ messages[i].routingComplete(_messageStore, new MessageHandleFactory());
+
}
for (int i = 0; i < messageCount; i++)
{
- _queue.process(_storeContext, new QueueEntry(_queue,messages[i]), false);
+ messages[i].addContentBodyFrame(new ContentChunk(){
+
+ ByteBuffer _data = ByteBuffer.allocate((int)size);
+
+ public int getSize()
+ {
+ return (int) size;
+ }
+
+ public ByteBuffer getData()
+ {
+ return _data;
+ }
+
+ public void reduceToFit()
+ {
+
+ }
+ });
+ messages[i].deliverToQueues();
}
}
private AMQQueue getNewQueue() throws AMQException
{
- return new AMQQueue(new AMQShortString("testQueue" + Math.random()),
+ return AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue" + Math.random()),
false,
new AMQShortString("AMQueueAlertTest"),
false,
- _virtualHost);
+ _virtualHost, null);
}
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
index 9b874d63e8..bf0a8a6d90 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
@@ -27,8 +27,12 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactory;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
import org.apache.qpid.server.protocol.TestMinaProtocolSession;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -44,6 +48,7 @@ import org.apache.mina.common.ByteBuffer;
import javax.management.JMException;
import java.util.LinkedList;
+import java.util.Collections;
/**
* Test class to test AMQQueueMBean attribtues and operations
@@ -58,6 +63,7 @@ public class AMQQueueMBeanTest extends TestCase
private TransactionalContext _transactionalContext;
private VirtualHost _virtualHost;
private AMQProtocolSession _protocolSession;
+ private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
public void testMessageCountTransient() throws Exception
{
@@ -73,7 +79,7 @@ public class AMQQueueMBeanTest extends TestCase
assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
_queueMBean.clearQueue();
- assertTrue(_queueMBean.getMessageCount() == 0);
+ assertEquals(0,(int)_queueMBean.getMessageCount());
assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
//Ensure that the data has been removed from the Store
@@ -116,8 +122,8 @@ public class AMQQueueMBeanTest extends TestCase
public void testConsumerCount() throws AMQException
{
- SubscriptionManager mgr = _queue.getSubscribers();
- assertFalse(mgr.hasActiveSubscribers());
+
+ assertTrue(_queue.getActiveConsumerCount() == 0);
assertTrue(_queueMBean.getActiveConsumerCount() == 0);
@@ -125,18 +131,21 @@ public class AMQQueueMBeanTest extends TestCase
AMQChannel channel = new AMQChannel(protocolSession, 1, _messageStore);
protocolSession.addChannel(channel);
- _queue.registerProtocolSession(protocolSession, 1, new AMQShortString("test"), false, null, false, false);
- assertTrue(_queueMBean.getActiveConsumerCount() == 1);
+ Subscription subscription =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), protocolSession, new AMQShortString("test"), false, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(subscription, false);
+ assertEquals(1,(int)_queueMBean.getActiveConsumerCount());
+
- SubscriptionSet _subscribers = (SubscriptionSet) mgr;
- SubscriptionFactory subscriptionFactory = new SubscriptionImpl.Factory();
+ SubscriptionFactory subscriptionFactory = SUBSCRIPTION_FACTORY;
Subscription s1 = subscriptionFactory.createSubscription(channel.getChannelId(),
protocolSession,
new AMQShortString("S1"),
false,
null,
true,
- _queue);
+ channel.getCreditManager());
Subscription s2 = subscriptionFactory.createSubscription(channel.getChannelId(),
protocolSession,
@@ -144,14 +153,14 @@ public class AMQQueueMBeanTest extends TestCase
false,
null,
true,
- _queue);
- _subscribers.addSubscriber(s1);
- _subscribers.addSubscriber(s2);
+ channel.getCreditManager());
+ _queue.registerSubscription(s1,false);
+ _queue.registerSubscription(s2,false);
assertTrue(_queueMBean.getActiveConsumerCount() == 3);
assertTrue(_queueMBean.getConsumerCount() == 3);
s1.close();
- assertTrue(_queueMBean.getActiveConsumerCount() == 2);
+ assertEquals(2, (int) _queueMBean.getActiveConsumerCount());
assertTrue(_queueMBean.getConsumerCount() == 3);
}
@@ -204,13 +213,34 @@ public class AMQQueueMBeanTest extends TestCase
}
- AMQMessage msg = message(false, false);
+ IncomingMessage msg = message(false, false);
long id = msg.getMessageId();
_queue.clearQueue(_storeContext);
- msg.enqueue(_queue);
- msg.routingComplete(_messageStore, _storeContext, new MessageHandleFactory());
- _queue.process(_storeContext, new QueueEntry(_queue, msg), false);
+ msg.enqueue(Collections.singleton(_queue));
+ msg.routingComplete(_messageStore, new MessageHandleFactory());
+
+ msg.addContentBodyFrame(new ContentChunk()
+ {
+ ByteBuffer _data = ByteBuffer.allocate((int)MESSAGE_SIZE);
+
+ public int getSize()
+ {
+ return (int) MESSAGE_SIZE;
+ }
+
+ public ByteBuffer getData()
+ {
+ return _data;
+ }
+
+ public void reduceToFit()
+ {
+
+ }
+ });
+ msg.deliverToQueues();
+// _queue.process(_storeContext, new QueueEntry(_queue, msg), false);
_queueMBean.viewMessageContent(id);
try
{
@@ -223,7 +253,7 @@ public class AMQQueueMBeanTest extends TestCase
}
}
- private AMQMessage message(final boolean immediate, boolean persistent) throws AMQException
+ private IncomingMessage message(final boolean immediate, boolean persistent) throws AMQException
{
MessagePublishInfo publish = new MessagePublishInfo()
{
@@ -258,7 +288,10 @@ public class AMQQueueMBeanTest extends TestCase
contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes
contentHeaderBody.properties = new BasicContentHeaderProperties();
((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) (persistent ? 2 : 1));
- return new AMQMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, contentHeaderBody);
+ IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
+ msg.setContentHeaderBody(contentHeaderBody);
+ return msg;
+
}
@Override
@@ -274,7 +307,8 @@ public class AMQQueueMBeanTest extends TestCase
new LinkedList<RequiredDeliveryException>()
);
- _queue = new AMQQueue(new AMQShortString("testQueue"), false, new AMQShortString("AMQueueMBeanTest"), false, _virtualHost);
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("AMQueueMBeanTest"), false, _virtualHost,
+ null);
_queueMBean = new AMQQueueMBean(_queue);
_protocolSession = new TestMinaProtocolSession();
@@ -284,19 +318,20 @@ public class AMQQueueMBeanTest extends TestCase
{
for (int i = 0; i < messageCount; i++)
{
- AMQMessage currentMessage = message(false, persistent);
- currentMessage.enqueue(_queue);
+ IncomingMessage currentMessage = message(false, persistent);
+ currentMessage.enqueue(Collections.singleton(_queue));
// route header
- currentMessage.routingComplete(_messageStore, _storeContext, new MessageHandleFactory());
+ currentMessage.routingComplete(_messageStore, new MessageHandleFactory());
// Add the body so we have somthing to test later
- currentMessage.addContentBodyFrame(_storeContext,
- _protocolSession.getMethodRegistry()
+ currentMessage.addContentBodyFrame(
+ _protocolSession.getMethodRegistry()
.getProtocolVersionMethodConverter()
.convertToContentChunk(
new ContentBody(ByteBuffer.allocate((int) MESSAGE_SIZE),
MESSAGE_SIZE)));
+ currentMessage.deliverToQueues();
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 3b51fb8db0..75e8cbe155 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -1014,6 +1014,7 @@ public abstract class AMQSession extends Closeable implements Session, QueueSess
}
}
+
/**
* Declares the named queue.
*
@@ -1031,18 +1032,40 @@ public abstract class AMQSession extends Closeable implements Session, QueueSess
public void createQueue(final AMQShortString name, final boolean autoDelete, final boolean durable,
final boolean exclusive) throws AMQException
{
+ createQueue(name, autoDelete, durable, exclusive, null);
+ }
+
+
+ /**
+ * Declares the named queue.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param name The name of the queue to declare.
+ * @param autoDelete
+ * @param durable Flag to indicate that the queue is durable.
+ * @param exclusive Flag to indicate that the queue is exclusive to this client.
+ * @param arguments Arguments used to set special properties of the queue
+ *
+ * @throws AMQException If the queue cannot be declared for any reason.
+ *
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void createQueue(final AMQShortString name, final boolean autoDelete, final boolean durable,
+ final boolean exclusive, final Map<String, Object> arguments) throws AMQException
+ {
new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
{
public Object execute() throws AMQException, FailoverException
{
- sendCreateQueue(name, autoDelete, durable, exclusive);
+ sendCreateQueue(name, autoDelete, durable, exclusive, arguments);
return null;
}
}, _connection).execute();
}
public abstract void sendCreateQueue(AMQShortString name, final boolean autoDelete, final boolean durable,
- final boolean exclusive)throws AMQException, FailoverException;
+ final boolean exclusive, final Map<String, Object> arguments)throws AMQException, FailoverException;
/**
* Creates a QueueReceiver
*
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index 4c3d768020..4f9c4edc75 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -243,13 +243,14 @@ public class AMQSession_0_10 extends AMQSession
* @param durable If set when creating a new queue,
* the queue will be marked as durable.
* @param exclusive Exclusive queues can only be used from one connection at a time.
+ * @param arguments Exclusive queues can only be used from one connection at a time.
* @throws AMQException
* @throws FailoverException
*/
public void sendCreateQueue(AMQShortString name, final boolean autoDelete, final boolean durable,
- final boolean exclusive) throws AMQException, FailoverException
+ final boolean exclusive, Map<String, Object> arguments) throws AMQException, FailoverException
{
- getQpidSession().queueDeclare(name.toString(), null, null, durable ? Option.DURABLE : Option.NO_OPTION,
+ getQpidSession().queueDeclare(name.toString(), null, arguments, durable ? Option.DURABLE : Option.NO_OPTION,
autoDelete ? Option.AUTO_DELETE : Option.NO_OPTION,
exclusive ? Option.EXCLUSIVE : Option.NO_OPTION);
// We need to sync so that we get notify of an error.
@@ -594,7 +595,7 @@ public class AMQSession_0_10 extends AMQSession
try
{
// this is done so that we can produce to a temporary queue beofre we create a consumer
- sendCreateQueue(result.getRoutingKey(), result.isAutoDelete(), result.isDurable(), result.isExclusive());
+ sendCreateQueue(result.getRoutingKey(), result.isAutoDelete(), result.isDurable(), result.isExclusive(),null);
sendQueueBind(result.getRoutingKey(), result.getRoutingKey(), new FieldTable(), result.getExchangeName(),result);
result.setQueueName(result.getRoutingKey());
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index 00aa8e4d31..e0e319250e 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -40,6 +40,8 @@ import org.apache.qpid.protocol.AMQMethodEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map;
+
public final class AMQSession_0_8 extends AMQSession
{
@@ -125,10 +127,19 @@ public final class AMQSession_0_8 extends AMQSession
handler.syncWrite(getProtocolHandler().getMethodRegistry().createTxCommitBody().generateFrame(_channelId), TxCommitOkBody.class);
}
- public void sendCreateQueue(AMQShortString name, final boolean autoDelete, final boolean durable, final boolean exclusive) throws AMQException,
+ public void sendCreateQueue(AMQShortString name, final boolean autoDelete, final boolean durable, final boolean exclusive, final Map<String, Object> arguments) throws AMQException,
FailoverException
{
- QueueDeclareBody body = getMethodRegistry().createQueueDeclareBody(getTicket(),name,false,durable,exclusive,autoDelete,false,null);
+ FieldTable table = null;
+ if(arguments != null && !arguments.isEmpty())
+ {
+ table = new FieldTable();
+ for(Map.Entry<String, Object> entry : arguments.entrySet())
+ {
+ table.setObject(entry.getKey(), entry.getValue());
+ }
+ }
+ QueueDeclareBody body = getMethodRegistry().createQueueDeclareBody(getTicket(),name,false,durable,exclusive,autoDelete,false,table);
AMQFrame queueDeclare = body.generateFrame(_channelId);
getProtocolHandler().syncWrite(queueDeclare, QueueDeclareOkBody.class);
}
@@ -412,6 +423,28 @@ public final class AMQSession_0_8 extends AMQSession
return subscriber;
}
+
+
+
+ public void setPrefecthLimits(final int messagePrefetch, final long sizePrefetch) throws AMQException
+ {
+ new FailoverRetrySupport<Object, AMQException>(
+ new FailoverProtectedOperation<Object, AMQException>()
+ {
+ public Object execute() throws AMQException, FailoverException
+ {
+
+ BasicQosBody basicQosBody = getProtocolHandler().getMethodRegistry().createBasicQosBody(sizePrefetch, messagePrefetch, false);
+
+ // todo send low water mark when protocol allows.
+ // todo Be aware of possible changes to parameter order as versions change.
+ getProtocolHandler().syncWrite(basicQosBody.generateFrame(getChannelId()), BasicQosOkBody.class);
+
+ return null;
+ }
+ }, _connection).execute();
+ }
+
class QueueDeclareOkHandler extends SpecificMethodFrameListener
{
diff --git a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
index 136b9b94b6..85ee78bd17 100644
--- a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
+++ b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
@@ -206,16 +206,27 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
MessageConsumer consumer2 = _clientSession1.createConsumer(_queue);
- for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ int msg;
+ for (msg = 0; msg < (MSG_COUNT / 2); msg++)
{
- assertTrue(_consumer1.receive(3000) != null);
+
+ final Message message = _consumer1.receive(1000);
+ if(message == null)
+ {
+ break;
+ }
+
}
- for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ _consumer1.close();
+ _clientSession1.close();
+
+ for (; msg < MSG_COUNT ; msg++)
{
- assertTrue(consumer2.receive(3000) != null);
+ assertTrue("Failed at msg id" + msg, _consumer2.receive(1000) != null);
}
+
}
else
{
diff --git a/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java b/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java
index bed80d5954..0c311b6645 100644
--- a/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java
+++ b/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java
@@ -62,7 +62,6 @@ public class FixedSizeByteBufferAllocator implements ByteBufferAllocator
private static final class FixedSizeByteBuffer extends ByteBuffer
{
private java.nio.ByteBuffer buf;
- private int refCount = 1;
private int mark = -1;
@@ -70,36 +69,14 @@ public class FixedSizeByteBufferAllocator implements ByteBufferAllocator
{
this.buf = buf;
buf.order( ByteOrder.BIG_ENDIAN );
- refCount = 1;
}
public synchronized void acquire()
{
- if( refCount <= 0 )
- {
- throw new IllegalStateException( "Already released buffer." );
- }
-
- refCount ++;
}
public void release()
{
- synchronized( this )
- {
- if( refCount <= 0 )
- {
- refCount = 0;
- throw new IllegalStateException(
- "Already released buffer. You released the buffer too many times." );
- }
-
- refCount --;
- if( refCount > 0)
- {
- return;
- }
- }
}
public java.nio.ByteBuffer buf()
@@ -157,50 +134,12 @@ public class FixedSizeByteBufferAllocator implements ByteBufferAllocator
{
if( newCapacity > capacity() )
{
- // Allocate a new buffer and transfer all settings to it.
- int pos = position();
- int limit = limit();
- ByteOrder bo = order();
-
- capacity0( newCapacity );
- buf.limit( limit );
- if( mark >= 0 )
- {
- buf.position( mark );
- buf.mark();
- }
- buf.position( pos );
- buf.order( bo );
+ throw new IllegalArgumentException();
}
return this;
}
- protected void capacity0( int requestedCapacity )
- {
- int newCapacity = MINIMUM_CAPACITY;
- while( newCapacity < requestedCapacity )
- {
- newCapacity <<= 1;
- }
-
- java.nio.ByteBuffer oldBuf = this.buf;
- java.nio.ByteBuffer newBuf;
- if( isDirect() )
- {
- newBuf = java.nio.ByteBuffer.allocateDirect( newCapacity );
- }
- else
- {
- newBuf = java.nio.ByteBuffer.allocate( newCapacity );
- }
-
- newBuf.clear();
- oldBuf.clear();
- newBuf.put( oldBuf );
- this.buf = newBuf;
- }
-
public boolean isAutoExpand()
diff --git a/java/common/src/main/java/org/apache/qpid/common/ClientProperties.java b/java/common/src/main/java/org/apache/qpid/common/ClientProperties.java
index 67f16e6a87..7371c12519 100644
--- a/java/common/src/main/java/org/apache/qpid/common/ClientProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/common/ClientProperties.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.common;
+import org.apache.qpid.framing.AMQShortString;
+
/**
* Specifies the available client property types that different clients can use to identify themselves with.
*
@@ -30,8 +32,21 @@ package org.apache.qpid.common;
*/
public enum ClientProperties
{
- instance,
- product,
- version,
- platform
+ instance("instance"),
+ product("product"),
+ version("version"),
+ platform("platform");
+
+ private final AMQShortString _amqShortString;
+
+ private ClientProperties(String name)
+ {
+ _amqShortString = new AMQShortString(name);
+ }
+
+
+ public AMQShortString toAMQShortString()
+ {
+ return _amqShortString;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
index a747aaeda7..2a248bf703 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
@@ -224,7 +224,6 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
}
}
-
/**
* Get the length of the short string
* @return length of the underlying byte array
@@ -464,13 +463,49 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
return false;
}
- if ((_hashCode != 0) && (otherString._hashCode != 0) && (_hashCode != otherString._hashCode))
+ final int hashCode = _hashCode;
+
+ final int otherHashCode = otherString._hashCode;
+
+ if ((hashCode != 0) && (otherHashCode != 0) && (hashCode != otherHashCode))
+ {
+ return false;
+ }
+
+ final int length = _length;
+
+ if(length != otherString._length)
{
return false;
}
- return (_offset == 0 && otherString._offset == 0 && _length == _data.length && otherString._length == otherString._data.length && Arrays.equals(_data,otherString._data))
- || Arrays.equals(getBytes(),otherString.getBytes());
+
+ final byte[] data = _data;
+
+ final byte[] otherData = otherString._data;
+
+ final int offset = _offset;
+
+ final int otherOffset = otherString._offset;
+
+ if(offset == 0 && otherOffset == 0 && length == data.length && length == otherData.length)
+ {
+ return Arrays.equals(data, otherData);
+ }
+ else
+ {
+ int thisIdx = offset;
+ int otherIdx = otherOffset;
+ for(int i = length; i-- != 0; )
+ {
+ if(!(data[thisIdx++] == otherData[otherIdx++]))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
@@ -718,4 +753,17 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
return false; //To change body of created methods use File | Settings | File Templates.
}
+
+ public static void main(String args[])
+ {
+ AMQShortString s = new AMQShortString("a.b.c.d.e.f.g.h.i.j.k");
+ AMQShortString s2 = s.substring(2, 7);
+
+ AMQShortStringTokenizer t = s2.tokenize((byte) '.');
+ while(t.hasMoreTokens())
+ {
+ System.err.println(t.nextToken());
+ }
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
index d6359baa0f..1ff39ca790 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
@@ -93,4 +93,24 @@ public class AMQTypedValue
{
return "[" + getType() + ": " + getValue() + "]";
}
+
+
+ public boolean equals(Object o)
+ {
+ if(o instanceof AMQTypedValue)
+ {
+ AMQTypedValue other = (AMQTypedValue) o;
+ return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value));
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public int hashCode()
+ {
+ return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode());
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index 9ba9b53b13..ed01c91804 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -74,7 +74,7 @@ public class FieldTable
buffer.skip((int) length);
}
- private AMQTypedValue getProperty(AMQShortString string)
+ public AMQTypedValue getProperty(AMQShortString string)
{
checkPropertyName(string);
@@ -891,6 +891,20 @@ public class FieldTable
return keys;
}
+ public Iterator<Map.Entry<AMQShortString, AMQTypedValue>> iterator()
+ {
+ if(_encodedForm != null)
+ {
+ return new FieldTableIterator(_encodedForm.duplicate().rewind(),(int)_encodedSize);
+ }
+ else
+ {
+ initMapIfNecessary();
+ return _properties.entrySet().iterator();
+ }
+ }
+
+
public Object get(AMQShortString key)
{
@@ -1050,6 +1064,95 @@ public class FieldTable
}
}
+ private static final class FieldTableEntry implements Map.Entry<AMQShortString, AMQTypedValue>
+ {
+ private final AMQTypedValue _value;
+ private final AMQShortString _key;
+
+ public FieldTableEntry(final AMQShortString key, final AMQTypedValue value)
+ {
+ _key = key;
+ _value = value;
+ }
+
+ public AMQShortString getKey()
+ {
+ return _key;
+ }
+
+ public AMQTypedValue getValue()
+ {
+ return _value;
+ }
+
+ public AMQTypedValue setValue(final AMQTypedValue value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean equals(Object o)
+ {
+ if(o instanceof FieldTableEntry)
+ {
+ FieldTableEntry other = (FieldTableEntry) o;
+ return (_key == null ? other._key == null : _key.equals(other._key))
+ && (_value == null ? other._value == null : _value.equals(other._value));
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public int hashCode()
+ {
+ return (getKey()==null ? 0 : getKey().hashCode())
+ ^ (getValue()==null ? 0 : getValue().hashCode());
+ }
+
+ }
+
+
+ private static final class FieldTableIterator implements Iterator<Map.Entry<AMQShortString, AMQTypedValue>>
+ {
+
+ private final ByteBuffer _buffer;
+ private int _expectedRemaining;
+
+ public FieldTableIterator(ByteBuffer buffer, int length)
+ {
+ _buffer = buffer;
+ _expectedRemaining = buffer.remaining() - length;
+ }
+
+ public boolean hasNext()
+ {
+ return (_buffer.remaining() > _expectedRemaining);
+ }
+
+ public Map.Entry<AMQShortString, AMQTypedValue> next()
+ {
+ if(hasNext())
+ {
+ final AMQShortString key = EncodingUtils.readAMQShortString(_buffer);
+ AMQTypedValue value = AMQTypedValue.readFromBuffer(_buffer);
+ return new FieldTableEntry(key, value);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+
+
public int hashCode()
{
initMapIfNecessary();
diff --git a/java/common/src/main/java/org/apache/qpid/pool/Job.java b/java/common/src/main/java/org/apache/qpid/pool/Job.java
index b2a09ac592..00da005515 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/Job.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/Job.java
@@ -50,7 +50,7 @@ import org.apache.mina.common.IoSession;
*
* @todo For better re-usability could make the completion handler optional. Only run it when one is set.
*/
-public class Job implements Runnable
+public class Job implements ReadWriteRunnable
{
/** The maximum number of events to process per run of the job. More events than this may be queued in the job. */
private final int _maxEvents;
@@ -67,18 +67,22 @@ public class Job implements Runnable
/** Holds the completion continuation, called upon completion of a run of the job. */
private final JobCompletionHandler _completionHandler;
+ private final boolean _readJob;
+
/**
* Creates a new job that aggregates many continuations together.
*
* @param session The Mina session.
* @param completionHandler The per job run, terminal continuation.
* @param maxEvents The maximum number of aggregated continuations to process per run of the job.
+ * @param readJob
*/
- Job(IoSession session, JobCompletionHandler completionHandler, int maxEvents)
+ Job(IoSession session, JobCompletionHandler completionHandler, int maxEvents, final boolean readJob)
{
_session = session;
_completionHandler = completionHandler;
_maxEvents = maxEvents;
+ _readJob = readJob;
}
/**
@@ -157,6 +161,22 @@ public class Job implements Runnable
}
}
+ public boolean isReadJob()
+ {
+ return _readJob;
+ }
+
+ public boolean isRead()
+ {
+ return _readJob;
+ }
+
+ public boolean isWrite()
+ {
+ return !_readJob;
+ }
+
+
/**
* Another interface for a continuation.
*
diff --git a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
index 2912e54662..a080cc7e04 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
@@ -60,24 +60,6 @@ import java.util.concurrent.ExecutorService;
* <td> {@link Job}, {@link Job.JobCompletionHandler}
* </table>
*
- * @todo This seems a bit bizarre. ReadWriteThreadModel creates seperate pooling filters for read and write events.
- * The pooling filters themselves batch read and write events into jobs, but hand these jobs to a common thread
- * pool for execution. So the same thread pool ends up handling read and write events, albeit with many threads
- * so there is concurrency. But why go to the trouble of seperating out the read and write events in that case?
- * Why not just batch them into jobs together? Perhaps its so that seperate thread pools could be used for these
- * stages.
- *
- * @todo Why set an event limit of 10 on the Job? This also seems bizarre, as the job can have more than 10 events in
- * it. Its just that it runs them 10 at a time, but the completion hander here checks if there are more to run
- * and trips off another batch of 10 until they are all done. Why not just have a straight forward
- * consumer/producer queue scenario without the batches of 10? So instead of having many jobs with batches of 10
- * in them, just have one queue of events and worker threads taking the next event. There will be coordination
- * between worker threads and new events arriving on the job anyway, so the simpler scenario may have the same
- * amount of contention. I can see that the batches of 10 is done, so that no job is allowed to hog the worker
- * pool for too long. I'm not convinced this fairly complex scheme will actually add anything, and it might be
- * better to encapsulate it under a Queue interface anyway, so that different queue implementations can easily
- * be substituted in.
- *
* @todo The static helper methods are pointless. Could just call new.
*/
public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionHandler
@@ -96,17 +78,20 @@ public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCo
private final int _maxEvents;
+ private final boolean _readFilter;
+
/**
* Creates a named pooling filter, on the specified shared thread pool.
*
* @param refCountingPool The thread pool reference.
* @param name The identifying name of the filter type.
*/
- public PoolingFilter(ReferenceCountingExecutorService refCountingPool, String name, int maxEvents)
+ public PoolingFilter(ReferenceCountingExecutorService refCountingPool, String name, int maxEvents, boolean readFilter)
{
_poolReference = refCountingPool;
_name = name;
_maxEvents = maxEvents;
+ _readFilter = readFilter;
}
/**
@@ -167,7 +152,6 @@ public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCo
void fireAsynchEvent(Job job, Event event)
{
- // job.acquire(); //prevents this job being removed from _jobs
job.add(event);
final ExecutorService pool = _poolReference.getPool();
@@ -201,7 +185,7 @@ public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCo
*/
public void createNewJobForSession(IoSession session)
{
- Job job = new Job(session, this, MAX_JOB_EVENTS);
+ Job job = new Job(session, this, MAX_JOB_EVENTS,_readFilter);
session.setAttribute(_name, job);
}
@@ -433,7 +417,7 @@ public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCo
*/
public AsynchReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
{
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_read_events", MAX_JOB_EVENTS));
+ super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_read_events", MAX_JOB_EVENTS),true);
}
/**
@@ -476,7 +460,7 @@ public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCo
*/
public AsynchWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
{
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_write_events", MAX_JOB_EVENTS));
+ super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_write_events", MAX_JOB_EVENTS),false);
}
/**
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java
new file mode 100644
index 0000000000..8de0f93ce9
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java
@@ -0,0 +1,432 @@
+package org.apache.qpid.pool;
+
+import java.util.AbstractQueue;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class ReadWriteJobQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable>
+{
+
+ private final AtomicInteger _count = new AtomicInteger(0);
+
+ private final ReentrantLock _takeLock = new ReentrantLock();
+
+ private final Condition _notEmpty = _takeLock.newCondition();
+
+ private final ReentrantLock _putLock = new ReentrantLock();
+
+ private final ConcurrentLinkedQueue<ReadWriteRunnable> _readJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>();
+
+ private final ConcurrentLinkedQueue<ReadWriteRunnable> _writeJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>();
+
+
+ private class ReadWriteJobIterator implements Iterator<Runnable>
+ {
+
+ private boolean _onReads;
+ private Iterator<ReadWriteRunnable> _iter = _writeJobQueue.iterator();
+
+ public boolean hasNext()
+ {
+ if(!_iter.hasNext())
+ {
+ if(_onReads)
+ {
+ _iter = _readJobQueue.iterator();
+ _onReads = true;
+ return _iter.hasNext();
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ public Runnable next()
+ {
+ if(_iter.hasNext())
+ {
+ return _iter.next();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void remove()
+ {
+ _takeLock.lock();
+ try
+ {
+ _iter.remove();
+ _count.decrementAndGet();
+ }
+ finally
+ {
+ _takeLock.unlock();
+ }
+ }
+ }
+
+ public Iterator<Runnable> iterator()
+ {
+ return new ReadWriteJobIterator();
+ }
+
+ public int size()
+ {
+ return _count.get();
+ }
+
+ public boolean offer(final Runnable runnable)
+ {
+ final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
+ final ReentrantLock putLock = _putLock;
+ putLock.lock();
+ try
+ {
+ if(job.isRead())
+ {
+ _readJobQueue.offer(job);
+ }
+ else
+ {
+ _writeJobQueue.offer(job);
+ }
+ if(_count.getAndIncrement() == 0)
+ {
+ _takeLock.lock();
+ try
+ {
+ _notEmpty.signal();
+ }
+ finally
+ {
+ _takeLock.unlock();
+ }
+ }
+ return true;
+ }
+ finally
+ {
+ putLock.unlock();
+ }
+ }
+
+ public void put(final Runnable runnable) throws InterruptedException
+ {
+ final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
+ final ReentrantLock putLock = _putLock;
+ putLock.lock();
+
+ try
+ {
+ if(job.isRead())
+ {
+ _readJobQueue.offer(job);
+ }
+ else
+ {
+ _writeJobQueue.offer(job);
+ }
+ if(_count.getAndIncrement() == 0)
+ {
+ _takeLock.lock();
+ try
+ {
+ _notEmpty.signal();
+ }
+ finally
+ {
+ _takeLock.unlock();
+ }
+ }
+
+ }
+ finally
+ {
+ putLock.unlock();
+ }
+ }
+
+
+
+ public boolean offer(final Runnable runnable, final long timeout, final TimeUnit unit) throws InterruptedException
+ {
+ final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
+ final ReentrantLock putLock = _putLock;
+ putLock.lock();
+
+ try
+ {
+ if(job.isRead())
+ {
+ _readJobQueue.offer(job);
+ }
+ else
+ {
+ _writeJobQueue.offer(job);
+ }
+ if(_count.getAndIncrement() == 0)
+ {
+ _takeLock.lock();
+ try
+ {
+ _notEmpty.signal();
+ }
+ finally
+ {
+ _takeLock.unlock();
+ }
+ }
+
+ return true;
+ }
+ finally
+ {
+ putLock.unlock();
+ }
+
+ }
+
+ public Runnable take() throws InterruptedException
+ {
+ final ReentrantLock takeLock = _takeLock;
+ takeLock.lockInterruptibly();
+ try
+ {
+ try
+ {
+ while (_count.get() == 0)
+ {
+ _notEmpty.await();
+ }
+ }
+ catch (InterruptedException ie)
+ {
+ _notEmpty.signal();
+ throw ie;
+ }
+
+ ReadWriteRunnable job = _writeJobQueue.poll();
+ if(job == null)
+ {
+ job = _readJobQueue.poll();
+ }
+ int c = _count.getAndDecrement();
+ if (c > 1)
+ {
+ _notEmpty.signal();
+ }
+ return job;
+ }
+ finally
+ {
+ takeLock.unlock();
+ }
+
+
+ }
+
+ public Runnable poll(final long timeout, final TimeUnit unit) throws InterruptedException
+ {
+ final ReentrantLock takeLock = _takeLock;
+ final AtomicInteger count = _count;
+ long nanos = unit.toNanos(timeout);
+ takeLock.lockInterruptibly();
+ ReadWriteRunnable job = null;
+ try
+ {
+
+ for (;;)
+ {
+ if (count.get() > 0)
+ {
+ job = _writeJobQueue.poll();
+ if(job == null)
+ {
+ job = _readJobQueue.poll();
+ }
+ int c = count.getAndDecrement();
+ if (c > 1)
+ {
+ _notEmpty.signal();
+ }
+ break;
+ }
+ if (nanos <= 0)
+ {
+ return null;
+ }
+ try
+ {
+ nanos = _notEmpty.awaitNanos(nanos);
+ }
+ catch (InterruptedException ie)
+ {
+ _notEmpty.signal();
+ throw ie;
+ }
+ }
+ }
+ finally
+ {
+ takeLock.unlock();
+ }
+
+ return job;
+ }
+
+ public int remainingCapacity()
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ public int drainTo(final Collection<? super Runnable> c)
+ {
+ int total = 0;
+
+ _putLock.lock();
+ _takeLock.lock();
+ try
+ {
+ ReadWriteRunnable job;
+ while((job = _writeJobQueue.peek())!= null)
+ {
+ c.add(job);
+ _writeJobQueue.poll();
+ _count.decrementAndGet();
+ total++;
+ }
+
+ while((job = _readJobQueue.peek())!= null)
+ {
+ c.add(job);
+ _readJobQueue.poll();
+ _count.decrementAndGet();
+ total++;
+ }
+
+ }
+ finally
+ {
+ _takeLock.unlock();
+ _putLock.unlock();
+ }
+ return total;
+ }
+
+ public int drainTo(final Collection<? super Runnable> c, final int maxElements)
+ {
+ int total = 0;
+
+ _putLock.lock();
+ _takeLock.lock();
+ try
+ {
+ ReadWriteRunnable job;
+ while(total<=maxElements && (job = _writeJobQueue.peek())!= null)
+ {
+ c.add(job);
+ _writeJobQueue.poll();
+ _count.decrementAndGet();
+ total++;
+ }
+
+ while(total<=maxElements && (job = _readJobQueue.peek())!= null)
+ {
+ c.add(job);
+ _readJobQueue.poll();
+ _count.decrementAndGet();
+ total++;
+ }
+
+ }
+ finally
+ {
+ _takeLock.unlock();
+ _putLock.unlock();
+ }
+ return total;
+
+ }
+
+ public Runnable poll()
+ {
+ final ReentrantLock takeLock = _takeLock;
+ takeLock.lock();
+ try
+ {
+ if(_count.get() > 0)
+ {
+ ReadWriteRunnable job = _writeJobQueue.poll();
+ if(job == null)
+ {
+ job = _readJobQueue.poll();
+ }
+ _count.decrementAndGet();
+ return job;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ finally
+ {
+ takeLock.unlock();
+ }
+
+ }
+
+ public Runnable peek()
+ {
+ final ReentrantLock takeLock = _takeLock;
+ takeLock.lock();
+ try
+ {
+ ReadWriteRunnable job = _writeJobQueue.peek();
+ if(job == null)
+ {
+ job = _readJobQueue.peek();
+ }
+ return job;
+ }
+ finally
+ {
+ takeLock.unlock();
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
new file mode 100644
index 0000000000..ad04a923e1
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
@@ -0,0 +1,27 @@
+package org.apache.qpid.pool;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public interface ReadWriteRunnable extends Runnable
+{
+ boolean isRead();
+ boolean isWrite();
+}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
index 84c9e1f465..ce9c6ae4cb 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
@@ -22,6 +22,9 @@ package org.apache.qpid.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* ReferenceCountingExecutorService wraps an ExecutorService in order to provide shared reference to it. It counts
@@ -84,6 +87,8 @@ public class ReferenceCountingExecutorService
/** Holds the number of executor threads to create. */
private int _poolSize = Integer.getInteger("amqj.read_write_pool_size", DEFAULT_POOL_SIZE);
+ private final boolean _useBiasedPool = Boolean.getBoolean("org.apache.qpid.use_write_biased_pool");
+
/**
* Retrieves the singleton instance of this reference counter.
*
@@ -105,15 +110,28 @@ public class ReferenceCountingExecutorService
*
* @return An executor service.
*/
- ExecutorService acquireExecutorService()
+ public ExecutorService acquireExecutorService()
{
synchronized (_lock)
{
if (_refCount++ == 0)
{
- _pool = Executors.newFixedThreadPool(_poolSize);
+// _pool = Executors.newFixedThreadPool(_poolSize);
+
+ // Use a job queue that biases to writes
+ if(_useBiasedPool)
+ {
+ _pool = new ThreadPoolExecutor(_poolSize, _poolSize,
+ 0L, TimeUnit.MILLISECONDS,
+ new ReadWriteJobQueue());
+ }
+ else
+ {
+ _pool = Executors.newFixedThreadPool(_poolSize);
+ }
}
+
return _pool;
}
}
@@ -122,7 +140,7 @@ public class ReferenceCountingExecutorService
* Releases a reference to a shared executor service, decrementing the reference count. If the refence count falls
* to zero, the executor service is shut down.
*/
- void releaseExecutorService()
+ public void releaseExecutorService()
{
synchronized (_lock)
{
diff --git a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
index 56eadbb3b2..fb616e2b59 100644
--- a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
+++ b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
@@ -23,10 +23,11 @@ package org.apache.qpid.management.ui;
import junit.framework.TestCase;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.DestNameExchange;
+import org.apache.qpid.server.exchange.DirectExchange;
import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueMBean;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -62,7 +63,8 @@ public class ManagementConsoleTest extends TestCase
{
// If this test fails due to changes in the broker code,
// then the constants in the Constants.java shoule be updated accordingly
- AMQQueue queue = new AMQQueue(new AMQShortString("testQueueForManagement"), false, null, false, _virtualHost);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueueForManagement"), false, null, false, _virtualHost,
+ null);
AMQManagedObject mbean = new AMQQueueMBean(queue);
MBeanInfo mbeanInfo = mbean.getMBeanInfo();
@@ -82,7 +84,7 @@ public class ManagementConsoleTest extends TestCase
{
// If this test fails due to changes in the broker code,
// then the constants in the Constants.java shoule be updated accordingly
- DestNameExchange exchange = new DestNameExchange();
+ DirectExchange exchange = new DirectExchange();
exchange.initialise(_virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true);
AMQManagedObject mbean = (AMQManagedObject)exchange.getManagedObject();
MBeanInfo mbeanInfo = mbean.getMBeanInfo();
diff --git a/java/systests/pom.xml b/java/systests/pom.xml
index 49f088ec1a..73c8fb7351 100644
--- a/java/systests/pom.xml
+++ b/java/systests/pom.xml
@@ -151,7 +151,6 @@
<MessageReturnTest>-n MessageReturnTest org.apache.qpid.server.queue.MessageReturnTest </MessageReturnTest>
<QueueDepthWithSelectorTest>-n QueueDepthWithSelectorTest org.apache.qpid.server.queue.QueueDepthWithSelectorTest </QueueDepthWithSelectorTest>
<!--<SubscriptionManagerTest>-n SubscriptionManagerTest org.apache.qpid.server.queue.SubscriptionManagerTest </SubscriptionManagerTest>-->
- <SubscriptionSetTest>-n SubscriptionSetTest org.apache.qpid.server.queue.SubscriptionSetTest </SubscriptionSetTest>
<TimeToLiveTest>-n TimeToLiveTest org.apache.qpid.server.queue.TimeToLiveTest </TimeToLiveTest>
<TxnBufferTest>-n TxnBufferTest org.apache.qpid.server.txn.TxnBufferTest </TxnBufferTest>
<!--<TxnTest>-n TxnTest org.apache.qpid.server.txn.TxnTest </TxnTest>-->
diff --git a/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java b/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java
index 2bb16aff2e..45db47a1c3 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java
@@ -26,12 +26,16 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.MessageHandleFactory;
import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.AMQMessageHandle;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.txn.TransactionalContext;
@@ -99,12 +103,16 @@ public class TxAckTest extends TestCase
private final List<Long> _unacked;
private StoreContext _storeContext = new StoreContext();
- Scenario(int messageCount, List<Long> acked, List<Long> unacked)
+ Scenario(int messageCount, List<Long> acked, List<Long> unacked) throws Exception
{
- TransactionalContext txnContext = new NonTransactionalContext(new MemoryMessageStore(),
+ TransactionalContext txnContext = new NonTransactionalContext(new TestableMemoryMessageStore(),
_storeContext, null,
new LinkedList<RequiredDeliveryException>()
);
+ AMQQueue queue =
+ AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false, null, false, new VirtualHost("", new MemoryMessageStore()),
+ null);
+
for (int i = 0; i < messageCount; i++)
{
long deliveryTag = i + 1;
@@ -138,8 +146,8 @@ public class TxAckTest extends TestCase
}
};
- TestMessage message = new TestMessage(deliveryTag, i, info, txnContext);
- _map.add(deliveryTag, new UnacknowledgedMessage(new QueueEntry(null,message), null, deliveryTag, _map));
+ TestMessage message = new TestMessage(deliveryTag, i, info, txnContext.getStoreContext());
+ _map.add(deliveryTag, queue.enqueue(new StoreContext(), message));
}
_acked = acked;
_unacked = unacked;
@@ -154,7 +162,7 @@ public class TxAckTest extends TestCase
{
for (long tag : tags)
{
- UnacknowledgedMessage u = _map.get(tag);
+ QueueEntry u = _map.get(tag);
assertTrue("Message not found for tag " + tag, u != null);
((TestMessage) u.getMessage()).assertCountEquals(expected);
}
@@ -175,7 +183,7 @@ public class TxAckTest extends TestCase
_op.consolidate();
_op.undoPrepare();
- assertCount(_acked, 1); //DTX Changed to 0, but that is wrong msg 5 is acked!
+ assertCount(_acked, 1);
assertCount(_unacked, 0);
}
@@ -195,34 +203,50 @@ public class TxAckTest extends TestCase
}
}
+ private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody)
+ {
+ final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
+ null,
+ false);
+ try
+ {
+ amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),
+ publishBody,
+ new ContentHeaderBody()
+ {
+ public int getSize()
+ {
+ return 1;
+ }
+ });
+ }
+ catch (AMQException e)
+ {
+ // won't happen
+ }
+
+
+ return amqMessageHandle;
+ }
+
+
private class TestMessage extends AMQMessage
{
private final long _tag;
private int _count;
- TestMessage(long tag, long messageId, MessagePublishInfo publishBody, TransactionalContext txnContext)
+ TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext)
+ throws AMQException
{
- super(messageId, publishBody, txnContext);
- try
- {
- setContentHeaderBody(new ContentHeaderBody()
- {
- public int getSize()
- {
- return 1;
- }
- });
- }
- catch (AMQException e)
- {
- // won't happen
- }
+ super(createMessageHandle(messageId, publishBody), storeContext, publishBody);
_tag = tag;
}
- public void incrementReference()
+
+ public boolean incrementReference()
{
_count++;
+ return true;
}
public void decrementReference(StoreContext context)
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
index 0968f0c468..adb7a7cd0c 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -24,18 +24,17 @@ import junit.framework.TestCase;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.*;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.store.SkeletonMessageStore;
import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.txn.TransactionalContext;
import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.log4j.Logger;
import java.util.*;
@@ -50,7 +49,7 @@ public class AbstractHeadersExchangeTestBase extends TestCase
/**
* Not used in this test, just there to stub out the routing calls
*/
- private MessageStore _store = new SkeletonMessageStore();
+ private MessageStore _store = new MemoryMessageStore();
private StoreContext _storeContext = new StoreContext();
@@ -94,7 +93,11 @@ public class AbstractHeadersExchangeTestBase extends TestCase
protected void route(Message m) throws AMQException
{
m.route(exchange);
- m.routingComplete(_store, _storeContext, _handleFactory);
+ m.getIncomingMessage().routingComplete(_store, _handleFactory);
+ if(m.getIncomingMessage().allContentReceived())
+ {
+ m.getIncomingMessage().deliverToQueues();
+ }
}
protected void routeAndTest(Message m, TestQueue... expected) throws AMQException
@@ -122,12 +125,12 @@ public class AbstractHeadersExchangeTestBase extends TestCase
{
if (expected.contains(q))
{
- assertTrue("Expected " + m + " to be delivered to " + q, m.isInQueue(q));
+ assertTrue("Expected " + m + " to be delivered to " + q, q.isInQueue(m));
//assert m.isInQueue(q) : "Expected " + m + " to be delivered to " + q;
}
else
{
- assertFalse("Did not expect " + m + " to be delivered to " + q, m.isInQueue(q));
+ assertFalse("Did not expect " + m + " to be delivered to " + q, q.isInQueue(m));
//assert !m.isInQueue(q) : "Did not expect " + m + " to be delivered to " + q;
}
}
@@ -234,7 +237,7 @@ public class AbstractHeadersExchangeTestBase extends TestCase
return properties;
}
- static class TestQueue extends AMQQueue
+ static class TestQueue extends SimpleAMQQueue
{
final List<HeadersExchangeTest.Message> messages = new ArrayList<HeadersExchangeTest.Message>();
@@ -248,13 +251,167 @@ public class AbstractHeadersExchangeTestBase extends TestCase
* not invoked. It is unnecessary since for this test we only care to know whether the message was
* sent to the queue; the queue processing logic is not being tested.
* @param msg
- * @param deliverFirst
* @throws AMQException
*/
- public void process(StoreContext context, QueueEntry msg, boolean deliverFirst) throws AMQException
+ @Override
+ public QueueEntry enqueue(StoreContext context, AMQMessage msg) throws AMQException
+ {
+ messages.add( new HeadersExchangeTest.Message(msg));
+ return new QueueEntry()
+ {
+
+ public AMQQueue getQueue()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQMessage getMessage()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getSize()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAcquired()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean delete()
+ {
+ return false;
+ }
+
+ public boolean isDeleted()
+ {
+ return false;
+ }
+
+ public boolean acquiredBySubscription()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setDeliveredToSubscription()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void release()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public String debugIdentity()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean immediateAndNotDelivered()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setRedelivered(boolean b)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject(Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(StoreContext storeContext) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeue(final StoreContext storeContext) throws FailedDequeueException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dispose(final StoreContext storeContext) throws MessageCleanupException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void restoreCredit()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isQueueDeleted()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int compareTo(final QueueEntry o)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+ boolean isInQueue(Message msg)
{
- messages.add(new HeadersExchangeTest.Message(msg.getMessage()));
+ return messages.contains(msg);
}
+
}
/**
@@ -262,10 +419,44 @@ public class AbstractHeadersExchangeTestBase extends TestCase
*/
static class Message extends AMQMessage
{
- private static MessageStore _messageStore = new MemoryMessageStore();
+ private class TestIncomingMessage extends IncomingMessage
+ {
+
+ public TestIncomingMessage(final long messageId,
+ final MessagePublishInfo info,
+ final TransactionalContext txnContext,
+ final AMQProtocolSession publisher)
+ {
+ super(messageId, info, txnContext, publisher);
+ }
+
+
+ public AMQMessage getUnderlyingMessage()
+ {
+ return Message.this;
+ }
+
+
+ public ContentHeaderBody getContentHeaderBody()
+ {
+ try
+ {
+ return Message.this.getContentHeaderBody();
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private IncomingMessage _incoming;
+
+ private static MessageStore _messageStore = new SkeletonMessageStore();
private static StoreContext _storeContext = new StoreContext();
+
private static TransactionalContext _txnContext = new NonTransactionalContext(_messageStore, _storeContext,
null,
new LinkedList<RequiredDeliveryException>()
@@ -278,12 +469,47 @@ public class AbstractHeadersExchangeTestBase extends TestCase
Message(String id, FieldTable headers) throws AMQException
{
- this(getPublishRequest(id), getContentHeader(headers), null);
+ this(_messageStore.getNewMessageId(),getPublishRequest(id), getContentHeader(headers), null);
+ }
+
+ public IncomingMessage getIncomingMessage()
+ {
+ return _incoming;
+ }
+
+ private Message(long messageId,
+ MessagePublishInfo publish,
+ ContentHeaderBody header,
+ List<ContentBody> bodies) throws AMQException
+ {
+ super(createMessageHandle(messageId, publish, header), _txnContext.getStoreContext(), publish);
+
+
+
+ _incoming = new TestIncomingMessage(getMessageId(),publish,_txnContext,new MockProtocolSession(_messageStore));
+ _incoming.setContentHeaderBody(header);
+
+
}
- private Message(MessagePublishInfo publish, ContentHeaderBody header, List<ContentBody> bodies) throws AMQException
+ private static AMQMessageHandle createMessageHandle(final long messageId,
+ final MessagePublishInfo publish,
+ final ContentHeaderBody header)
{
- super(_messageStore.getNewMessageId(), publish, _txnContext, header);
+
+ final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
+ _messageStore,
+ true);
+
+ try
+ {
+ amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,header);
+ }
+ catch (AMQException e)
+ {
+
+ }
+ return amqMessageHandle;
}
private Message(AMQMessage msg) throws AMQException
@@ -291,15 +517,13 @@ public class AbstractHeadersExchangeTestBase extends TestCase
super(msg);
}
+
+
void route(Exchange exchange) throws AMQException
{
- exchange.route(this);
+ exchange.route(_incoming);
}
- boolean isInQueue(TestQueue queue)
- {
- return queue.messages.contains(this);
- }
public int hashCode()
{
diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
index e4555e020e..8e7038eec3 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
@@ -28,16 +28,15 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.codec.AMQCodecFactory;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.SkeletonMessageStore;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import javax.management.JMException;
-
/**
* Test class to test MBean operations for AMQMinaProtocolSession.
*/
@@ -56,13 +55,12 @@ public class AMQProtocolSessionMBeanTest extends TestCase
// check the channel count is correct
int channelCount = _mbean.channels().size();
assertTrue(channelCount == 1);
- AMQQueue queue = new org.apache.qpid.server.queue.AMQQueue(new AMQShortString("testQueue_" + System.currentTimeMillis()),
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue_" + System.currentTimeMillis()),
false,
new AMQShortString("test"),
true,
- _protocolSession.getVirtualHost());
- AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
-
+ _protocolSession.getVirtualHost(), null);
+ AMQChannel channel = new AMQChannel(_protocolSession,2, _messageStore);
channel.setDefaultQueue(queue);
_protocolSession.addChannel(channel);
channelCount = _mbean.channels().size();
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java
index 2416442b10..bbd6deffd3 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java
@@ -23,24 +23,26 @@ package org.apache.qpid.server.queue;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.ack.UnacknowledgedMessage;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.flow.LimitlessCreditManager;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.txn.TransactionalContext;
import org.apache.qpid.server.util.NullApplicationRegistry;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
+import java.util.Collections;
/**
* Tests that acknowledgements are handled correctly.
@@ -49,7 +51,7 @@ public class AckTest extends TestCase
{
private static final Logger _log = Logger.getLogger(AckTest.class);
- private SubscriptionImpl _subscription;
+ private Subscription _subscription;
private MockProtocolSession _protocolSession;
@@ -57,9 +59,7 @@ public class AckTest extends TestCase
private StoreContext _storeContext = new StoreContext();
- private AMQChannel _channel;
-
- private SubscriptionSet _subscriptionManager;
+ private AMQChannel _channel;
private AMQQueue _queue;
@@ -75,11 +75,13 @@ public class AckTest extends TestCase
super.setUp();
_messageStore = new TestableMemoryMessageStore();
_protocolSession = new MockProtocolSession(_messageStore);
- _channel = new AMQChannel(_protocolSession, 5, _messageStore);
+ _channel = new AMQChannel(_protocolSession,5, _messageStore /*dont need exchange registry*/);
_protocolSession.addChannel(_channel);
- _subscriptionManager = new SubscriptionSet();
- _queue = new AMQQueue(new AMQShortString("myQ"), false, new AMQShortString("guest"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"), _subscriptionManager);
+
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("myQ"), false, new AMQShortString("guest"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"),
+ null);
+
}
private void publishMessages(int count) throws AMQException
@@ -92,6 +94,7 @@ public class AckTest extends TestCase
TransactionalContext txnContext = new NonTransactionalContext(_messageStore, _storeContext, null,
new LinkedList<RequiredDeliveryException>()
);
+ _queue.registerSubscription(_subscription,false);
MessageHandleFactory factory = new MessageHandleFactory();
for (int i = 1; i <= count; i++)
{
@@ -125,7 +128,8 @@ public class AckTest extends TestCase
return new AMQShortString("rk");
}
};
- AMQMessage msg = new AMQMessage(_messageStore.getNewMessageId(), publishBody, txnContext);
+ IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publishBody, txnContext,_protocolSession);
+ //IncomingMessage msg2 = null;
if (persistent)
{
BasicContentHeaderProperties b = new BasicContentHeaderProperties();
@@ -142,10 +146,14 @@ public class AckTest extends TestCase
// we increment the reference here since we are not delivering the messaging to any queues, which is where
// the reference is normally incremented. The test is easier to construct if we have direct access to the
// subscription
- msg.incrementReference();
- msg.routingComplete(_messageStore, _storeContext, factory);
+ msg.enqueue(Collections.singleton(_queue));
+ msg.routingComplete(_messageStore, factory);
+ if(msg.allContentReceived())
+ {
+ msg.deliverToQueues();
+ }
// we manually send the message to the subscription
- _subscription.send(new QueueEntry(_queue,msg), _queue);
+ //_subscription.send(new QueueEntry(_queue,msg), _queue);
}
}
@@ -155,16 +163,13 @@ public class AckTest extends TestCase
*/
public void testAckChannelAssociationTest() throws AMQException
{
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true, null, false, new LimitlessCreditManager());
final int msgCount = 10;
publishMessages(msgCount, true);
UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
assertTrue(map.size() == msgCount);
assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
-
- //DTX
- // assertTrue(_messageStore.getNumberStoredMessages() == msgCount);
Set<Long> deliveryTagSet = map.getDeliveryTags();
int i = 1;
@@ -172,15 +177,12 @@ public class AckTest extends TestCase
{
assertTrue(deliveryTag == i);
i++;
- UnacknowledgedMessage unackedMsg = map.get(deliveryTag);
+ QueueEntry unackedMsg = map.get(deliveryTag);
assertTrue(unackedMsg.getQueue() == _queue);
}
assertTrue(map.size() == msgCount);
assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
-
- //DTX
-// assertTrue(_messageStore.getNumberStoredMessages() == msgCount);
}
/**
@@ -189,15 +191,32 @@ public class AckTest extends TestCase
public void testNoAckMode() throws AMQException
{
// false arg means no acks expected
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, false);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false, null, false, new LimitlessCreditManager());
final int msgCount = 10;
publishMessages(msgCount);
UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
assertTrue(map.size() == 0);
assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
- //DTX MessageStore
-// assertTrue(_messageStore.getNumberStoredMessages() == 0);
+ assertTrue(_messageStore.getContentBodyMap().size() == 0);
+
+ }
+
+ /**
+ * Tests that in no-ack mode no messages are retained
+ */
+ public void testPersistentNoAckMode() throws AMQException
+ {
+ // false arg means no acks expected
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount, true);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+ assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
+ assertTrue(_messageStore.getContentBodyMap().size() == 0);
+
}
/**
@@ -206,7 +225,7 @@ public class AckTest extends TestCase
*/
public void testSingleAckReceivedTest() throws AMQException
{
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
final int msgCount = 10;
publishMessages(msgCount);
@@ -219,7 +238,7 @@ public class AckTest extends TestCase
for (long deliveryTag : deliveryTagSet)
{
assertTrue(deliveryTag == i);
- UnacknowledgedMessage unackedMsg = map.get(deliveryTag);
+ QueueEntry unackedMsg = map.get(deliveryTag);
assertTrue(unackedMsg.getQueue() == _queue);
// 5 is the delivery tag of the message that *should* be removed
if (++i == 5)
@@ -235,7 +254,7 @@ public class AckTest extends TestCase
*/
public void testMultiAckReceivedTest() throws AMQException
{
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
final int msgCount = 10;
publishMessages(msgCount);
@@ -248,7 +267,7 @@ public class AckTest extends TestCase
for (long deliveryTag : deliveryTagSet)
{
assertTrue(deliveryTag == i + 5);
- UnacknowledgedMessage unackedMsg = map.get(deliveryTag);
+ QueueEntry unackedMsg = map.get(deliveryTag);
assertTrue(unackedMsg.getQueue() == _queue);
++i;
}
@@ -259,7 +278,7 @@ public class AckTest extends TestCase
*/
public void testMultiAckAllReceivedTest() throws AMQException
{
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
final int msgCount = 10;
publishMessages(msgCount);
@@ -272,18 +291,19 @@ public class AckTest extends TestCase
for (long deliveryTag : deliveryTagSet)
{
assertTrue(deliveryTag == i + 5);
- UnacknowledgedMessage unackedMsg = map.get(deliveryTag);
+ QueueEntry unackedMsg = map.get(deliveryTag);
assertTrue(unackedMsg.getQueue() == _queue);
++i;
}
}
+/*
public void testPrefetchHighLow() throws AMQException
{
int lowMark = 5;
int highMark = 10;
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
_channel.setPrefetchLowMarkCount(lowMark);
_channel.setPrefetchHighMarkCount(highMark);
@@ -332,10 +352,12 @@ public class AckTest extends TestCase
assertTrue(map.size() == 0);
}
+*/
+/*
public void testPrefetch() throws AMQException
{
- _subscription = new SubscriptionImpl(5, _protocolSession, DEFAULT_CONSUMER_TAG, true);
- _channel.setPrefetchCount(5);
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ _channel.setMessageCredit(5);
assertTrue(_channel.getPrefetchCount() == 5);
@@ -360,6 +382,7 @@ public class AckTest extends TestCase
assertTrue(map.size() == 0);
}
+*/
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(AckTest.class);
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/ConcurrencyTestDisabled.java b/java/systests/src/main/java/org/apache/qpid/server/queue/ConcurrencyTestDisabled.java
deleted file mode 100644
index 4f92cc94b7..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/ConcurrencyTestDisabled.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.handler.OnCurrentThreadExecutor;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-import java.util.*;
-import java.util.concurrent.Executor;
-
-/**
- * Tests delivery in the face of concurrent incoming _messages, subscription alterations
- * and attempts to asynchronously process queued _messages.
- */
-public class ConcurrencyTestDisabled extends MessageTestHelper
-{
- private final Random random = new Random();
-
- private final int numMessages = 10;
-
- private final List<SubscriptionTestHelper> _subscribers = new ArrayList<SubscriptionTestHelper>();
- private final Set<Subscription> _active = new HashSet<Subscription>();
- private final List<QueueEntry> _messages = new ArrayList<QueueEntry>();
- private int next = 0;//index to next message to send
- private final List<QueueEntry> _received = Collections.synchronizedList(new ArrayList<QueueEntry>());
- private final Executor _executor = new OnCurrentThreadExecutor();
- private final List<Thread> _threads = new ArrayList<Thread>();
-
- private final SubscriptionSet _subscriptionMgr = new SubscriptionSet();
- private final DeliveryManager _deliveryMgr;
-
- private boolean isComplete;
- private boolean failed;
- private VirtualHost _virtualHost;
-
- public ConcurrencyTestDisabled() throws Exception
- {
-
- IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance();
- _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
- _deliveryMgr = new ConcurrentSelectorDeliveryManager(_subscriptionMgr, new AMQQueue(new AMQShortString("myQ"), false, new AMQShortString("guest"), false,
- _virtualHost));
- }
-
- public void testConcurrent1() throws InterruptedException, AMQException
- {
- initSubscriptions(10);
- initMessages(numMessages);
- initThreads(1, 4, 4, 4);
- doRun();
- check();
- }
-
- public void testConcurrent2() throws InterruptedException, AMQException
- {
- initSubscriptions(10);
- initMessages(numMessages);
- initThreads(4, 2, 2, 2);
- doRun();
- check();
- }
-
- void check()
- {
- assertFalse("Failed", failed);
-
- _deliveryMgr.processAsync(_executor);
-
- assertEquals("Did not recieve the correct number of messages", _messages.size(), _received.size());
- for(int i = 0; i < _messages.size(); i++)
- {
- assertEquals("Wrong message at " + i, _messages.get(i), _received.get(i));
- }
- }
-
- void initSubscriptions(int subscriptions)
- {
- for(int i = 0; i < subscriptions; i++)
- {
- _subscribers.add(new SubscriptionTestHelper("Subscriber" + i, _received));
- }
- }
-
- void initMessages(int messages) throws AMQException
- {
- for(int i = 0; i < messages; i++)
- {
- _messages.add(message());
- }
- }
-
- void initThreads(int senders, int subscribers, int suspenders, int processors)
- {
- addThreads(senders, senders == 1 ? new Sender() : new OrderedSender());
- addThreads(subscribers, new Subscriber());
- addThreads(suspenders, new Suspender());
- addThreads(processors, new Processor());
- }
-
- void addThreads(int count, Runnable runner)
- {
- for(int i = 0; i < count; i++)
- {
- _threads.add(new Thread(runner, runner.toString()));
- }
- }
-
- void doRun() throws InterruptedException
- {
- for(Thread t : _threads)
- {
- t.start();
- }
-
- for(Thread t : _threads)
- {
- t.join();
- }
- }
-
- private void toggle(Subscription s)
- {
- synchronized (_active)
- {
- if (_active.contains(s))
- {
- _active.remove(s);
- Subscription result = _subscriptionMgr.removeSubscriber(s);
- assertTrue("Removed subscription " + result + " but trying to remove subscription " + s,
- result != null && result.equals(s));
- }
- else
- {
- _active.add(s);
- _subscriptionMgr.addSubscriber(s);
- }
- }
- }
-
- private QueueEntry nextMessage()
- {
- synchronized (_messages)
- {
- if (next < _messages.size())
- {
- return _messages.get(next++);
- }
- else
- {
- if (!_deliveryMgr.hasQueuedMessages()) {
- isComplete = true;
- }
- return null;
- }
- }
- }
-
- private boolean randomBoolean()
- {
- return random.nextBoolean();
- }
-
- private SubscriptionTestHelper randomSubscriber()
- {
- return _subscribers.get(random.nextInt(_subscribers.size()));
- }
-
- private class Sender extends Runner
- {
- void doRun() throws Throwable
- {
- QueueEntry msg = nextMessage();
- if (msg != null)
- {
- _deliveryMgr.deliver(null, new AMQShortString(toString()), msg, false);
- }
- }
- }
-
- private class OrderedSender extends Sender
- {
- synchronized void doRun() throws Throwable
- {
- super.doRun();
- }
- }
-
- private class Suspender extends Runner
- {
- void doRun() throws Throwable
- {
- randomSubscriber().setSuspended(randomBoolean());
- }
- }
-
- private class Subscriber extends Runner
- {
- void doRun() throws Throwable
- {
- toggle(randomSubscriber());
- }
- }
-
- private class Processor extends Runner
- {
- void doRun() throws Throwable
- {
- _deliveryMgr.processAsync(_executor);
- }
- }
-
- private abstract class Runner implements Runnable
- {
- public void run()
- {
- try
- {
- while (!stop())
- {
- doRun();
- }
- }
- catch (Throwable t)
- {
- failed = true;
- t.printStackTrace();
- }
- }
-
- abstract void doRun() throws Throwable;
-
- boolean stop()
- {
- return isComplete || failed;
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(ConcurrencyTestDisabled.class);
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/DeliveryManagerTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/DeliveryManagerTest.java
deleted file mode 100644
index b33259cfba..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/DeliveryManagerTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.server.handler.OnCurrentThreadExecutor;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-
-import junit.framework.TestSuite;
-
-abstract public class DeliveryManagerTest extends MessageTestHelper
-{
- protected final SubscriptionSet _subscriptions = new SubscriptionSet();
- protected DeliveryManager _mgr;
- protected StoreContext _storeContext = new StoreContext();
- private static final AMQShortString DEFAULT_QUEUE_NAME = new AMQShortString("Me");
-
- public DeliveryManagerTest() throws Exception
- {
- }
-
- public void testStartInQueueingMode() throws AMQException
- {
- QueueEntry[] messages = new QueueEntry[10];
- for (int i = 0; i < messages.length; i++)
- {
- messages[i] = message();
- }
- int batch = messages.length / 2;
-
- for (int i = 0; i < batch; i++)
- {
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, messages[i], false);
- }
-
- SubscriptionTestHelper s1 = new SubscriptionTestHelper("1");
- SubscriptionTestHelper s2 = new SubscriptionTestHelper("2");
- _subscriptions.addSubscriber(s1);
- _subscriptions.addSubscriber(s2);
-
- for (int i = batch; i < messages.length; i++)
- {
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, messages[i], false);
- }
-
- assertTrue(s1.getMessages().isEmpty());
- assertTrue(s2.getMessages().isEmpty());
-
- _mgr.processAsync(new OnCurrentThreadExecutor());
-
- assertEquals(messages.length / 2, s1.getMessages().size());
- assertEquals(messages.length / 2, s2.getMessages().size());
-
- for (int i = 0; i < messages.length; i++)
- {
- if (i % 2 == 0)
- {
- assertTrue(s1.getMessages().get(i / 2) == messages[i]);
- }
- else
- {
- assertTrue(s2.getMessages().get(i / 2) == messages[i]);
- }
- }
- }
-
- public void testStartInDirectMode() throws AMQException
- {
- QueueEntry[] messages = new QueueEntry[10];
- for (int i = 0; i < messages.length; i++)
- {
- messages[i] = message();
- }
- int batch = messages.length / 2;
-
- SubscriptionTestHelper s1 = new SubscriptionTestHelper("1");
- _subscriptions.addSubscriber(s1);
-
- for (int i = 0; i < batch; i++)
- {
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, messages[i], false);
- }
-
- assertEquals(batch, s1.getMessages().size());
- for (int i = 0; i < batch; i++)
- {
- assertTrue(messages[i] == s1.getMessages().get(i));
- }
- s1.getMessages().clear();
- assertEquals(0, s1.getMessages().size());
-
- s1.setSuspended(true);
- for (int i = batch; i < messages.length; i++)
- {
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, messages[i], false);
- }
-
- _mgr.processAsync(new OnCurrentThreadExecutor());
- assertEquals(0, s1.getMessages().size());
- s1.setSuspended(false);
-
- _mgr.processAsync(new OnCurrentThreadExecutor());
- assertEquals(messages.length - batch, s1.getMessages().size());
-
- for (int i = batch; i < messages.length; i++)
- {
- assertTrue(messages[i] == s1.getMessages().get(i - batch));
- }
-
- }
-
- public void testNoConsumers() throws AMQException
- {
- try
- {
- QueueEntry msg = message(true);
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, msg, false);
- msg.checkDeliveredToConsumer();
- fail("expected exception did not occur");
- }
- catch (NoConsumersException m)
- {
- // ok
- }
- catch (Exception e)
- {
- fail("expected NoConsumersException, got " + e);
- }
- }
-
- public void testNoActiveConsumers() throws AMQException
- {
- try
- {
- SubscriptionTestHelper s = new SubscriptionTestHelper("A");
- _subscriptions.addSubscriber(s);
- s.setSuspended(true);
- QueueEntry msg = message(true);
- _mgr.deliver(_storeContext, DEFAULT_QUEUE_NAME, msg, false);
- msg.checkDeliveredToConsumer();
- fail("expected exception did not occur");
- }
- catch (NoConsumersException m)
- {
- // ok
- }
- catch (Exception e)
- {
- fail("expected NoConsumersException, got " + e);
- }
- }
-
- public static junit.framework.Test suite()
- {
- TestSuite suite = new TestSuite();
- return suite;
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java b/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java
index 114c8cac32..b2a4216f8d 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java
@@ -24,7 +24,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.util.NullApplicationRegistry;
@@ -39,7 +39,7 @@ import java.util.LinkedList;
class MessageTestHelper extends TestCase
{
- private final MessageStore _messageStore = new MemoryMessageStore();
+ private final MessageStore _messageStore = new SkeletonMessageStore();
private final StoreContext _storeContext = new StoreContext();
@@ -52,12 +52,12 @@ class MessageTestHelper extends TestCase
ApplicationRegistry.initialise(new NullApplicationRegistry());
}
- QueueEntry message() throws AMQException
+ QueueEntryImpl message() throws AMQException
{
return message(false);
}
- QueueEntry message(final boolean immediate) throws AMQException
+ QueueEntryImpl message(final boolean immediate) throws AMQException
{
MessagePublishInfo publish = new MessagePublishInfo()
{
@@ -87,9 +87,16 @@ class MessageTestHelper extends TestCase
return null;
}
};
-
- return new QueueEntry(null,new AMQMessage(_messageStore.getNewMessageId(), publish, _txnContext,
- new ContentHeaderBody()));
+
+ //public AMQMessage(Long messageId, AMQMessageHandle messageHandle , TransactionalContext txnConext, MessagePublishInfo info)
+ long messageId = _messageStore.getNewMessageId();
+ final AMQMessageHandle messageHandle =
+ (new MessageHandleFactory()).createMessageHandle(messageId, _messageStore, false);
+ messageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,new ContentHeaderBody());
+ AMQMessage msg = new AMQMessage(messageHandle, _txnContext.getStoreContext(), publish);
+
+
+ return new QueueEntryImpl(null,msg, Long.MIN_VALUE);
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java b/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java
index cf986e7803..a1a405c313 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java
@@ -215,6 +215,11 @@ public class MockProtocolSession implements AMQProtocolSession
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+ public ProtocolSessionIdentifier getSessionIdentifier()
+ {
+ return null;
+ }
+
public byte getProtocolMajorVersion()
{
return getProtocolVersion().getMajorVersion();
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
new file mode 100644
index 0000000000..0dbf95052f
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
@@ -0,0 +1,176 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 junit.framework.TestCase;
+import junit.framework.Assert;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+
+import javax.jms.*;
+import javax.naming.NamingException;
+import javax.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Test Case provided by client Non-functional Test NF101: heap exhaustion behaviour */
+public class PriorityTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(PriorityTest.class);
+
+
+ protected final String BROKER = "vm://:1";
+ protected final String VHOST = "/test";
+ protected final String QUEUE = "PriorityQueue";
+
+
+ private static final int MSG_COUNT = 50;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ if (usingInVMBroker())
+ {
+ TransportConnection.createVMBroker(1);
+ }
+
+
+ }
+
+ private boolean usingInVMBroker()
+ {
+ return BROKER.startsWith("vm://");
+ }
+
+ protected void tearDown() throws Exception
+ {
+ if (usingInVMBroker())
+ {
+ TransportConnection.killAllVMBrokers();
+ }
+ super.tearDown();
+ }
+
+ public void testPriority() throws JMSException, NamingException, AMQException
+ {
+ InitialContextFactory factory = new PropertiesFileInitialContextFactory();
+
+ Hashtable<String, String> env = new Hashtable<String, String>();
+
+ env.put("connectionfactory.connection", "amqp://guest:guest@PRIORITY_TEST_ID" + VHOST + "?brokerlist='" + BROKER + "'");
+ env.put("queue.queue", QUEUE);
+
+ Context context = factory.getInitialContext(env);
+
+ Connection producerConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
+
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-priorities",10);
+
+ ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+
+ Queue queue = new AMQQueue("amq.direct",QUEUE);
+
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+
+
+
+
+
+
+ producerConnection.start();
+
+
+ MessageProducer producer = producerSession.createProducer(queue);
+
+
+
+
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ producer.setPriority(msg % 10);
+ producer.send(nextMessage(msg, false, producerSession, producer));
+ }
+
+ producer.close();
+ producerSession.close();
+ producerConnection.close();
+
+
+ Connection consumerConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
+ Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = consumerSession.createConsumer(queue);
+
+
+
+
+ consumerConnection.start();
+
+ Message received;
+ //Receive Message 0
+ StringBuilder buf = new StringBuilder();
+ int receivedCount = 0;
+ Message previous = null;
+ int messageCount = 0;
+ while((received = consumer.receive(1000))!=null)
+ {
+ messageCount++;
+ if(previous != null)
+ {
+ assertTrue("Messages arrived in unexpected order " + messageCount + " " + previous.getIntProperty("msg") + " " + received.getIntProperty("msg") + " " + previous.getJMSPriority() + " " + received.getJMSPriority(), (previous.getJMSPriority() > received.getJMSPriority()) || ((previous.getJMSPriority() == received.getJMSPriority()) && previous.getIntProperty("msg") < received.getIntProperty("msg")) );
+ }
+
+ previous = received;
+ receivedCount++;
+ }
+
+ assertEquals("Incorrect number of message received", 50, receivedCount);
+
+ producerSession.close();
+ producer.close();
+
+ }
+
+ private Message nextMessage(int msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException
+ {
+ Message send = producerSession.createTextMessage("Message: " + msg);
+ send.setIntProperty("msg", msg);
+
+ return send;
+ }
+
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
index f82fec61b0..280d897852 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
@@ -81,14 +81,6 @@ public class QueueDepthWithSelectorTest extends TestCase
System.err.println("_logger.isDebug:" + _logger.isDebugEnabled() + ":" + _logger.isEnabledFor(Level.DEBUG));
System.err.println("_logger.isTrace:" + _logger.isTraceEnabled() + ":" + _logger.isEnabledFor(Level.TRACE));
- Logger csdm = Logger.getLogger(ConcurrentSelectorDeliveryManager.class);
- System.err.println("csdm.isE-Error:" + csdm.isEnabledFor(Level.ERROR));
- System.err.println("csdm.isE-Warn:" + csdm.isEnabledFor(Level.WARN));
- System.err.println("csdm.isInfo:" + csdm.isInfoEnabled() + ":" + csdm.isEnabledFor(Level.INFO));
- System.err.println("csdm.isDebug:" + csdm.isDebugEnabled() + ":" + csdm.isEnabledFor(Level.DEBUG));
- System.err.println("csdm.isTrace:" + csdm.isTraceEnabled() + ":" + csdm.isEnabledFor(Level.TRACE));
-
-
System.err.println(Logger.getRootLogger().getLoggerRepository());
if (BROKER.startsWith("vm://"))
@@ -184,9 +176,14 @@ public class QueueDepthWithSelectorTest extends TestCase
try
{
+ Thread.sleep(2000);
long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _context.lookup("queue"));
assertEquals("Session reports Queue depth not as expected", 0, queueDepth);
}
+ catch (InterruptedException e)
+ {
+ fail(e.getMessage());
+ }
catch (NamingException e)
{
fail(e.getMessage());
@@ -209,7 +206,7 @@ public class QueueDepthWithSelectorTest extends TestCase
}
- private void verifyAllMessagesRecevied() throws JMSException
+ private void verifyAllMessagesRecevied() throws Exception
{
boolean[] msgIdRecevied = new boolean[MSG_COUNT];
@@ -219,6 +216,8 @@ public class QueueDepthWithSelectorTest extends TestCase
_messages[i] = _consumer.receive(1000);
assertNotNull("should have received a message but didn't", _messages[i]);
}
+ long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _context.lookup("queue"));
+ assertEquals("Session reports Queue depth not as expected", 0, queueDepth);
//Check received messages
int msgId = 0;
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionManagerTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionManagerTest.java
deleted file mode 100644
index d3ec3c11d4..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionManagerTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import junit.framework.TestCase;
-
-public class SubscriptionManagerTest extends TestCase
-{
- private final SubscriptionSet mgr = new SubscriptionSet();
-
- public void testBasicSubscriptionManagement()
- {
- assertTrue(mgr.isEmpty());
- assertFalse(mgr.hasActiveSubscribers());
- SubscriptionTestHelper s1 = new SubscriptionTestHelper("S1");
- mgr.addSubscriber(s1);
- assertFalse(mgr.isEmpty());
- assertTrue(mgr.hasActiveSubscribers());
-
- SubscriptionTestHelper s2 = new SubscriptionTestHelper("S2");
- mgr.addSubscriber(s2);
-
- s2.setSuspended(true);
- assertFalse(mgr.isEmpty());
- assertTrue(mgr.hasActiveSubscribers());
- assertTrue(s2.isSuspended());
- assertFalse(s1.isSuspended());
-
- s1.setSuspended(true);
- assertFalse(mgr.hasActiveSubscribers());
-
- mgr.removeSubscriber(new SubscriptionTestHelper("S1"));
- assertFalse(mgr.isEmpty());
- mgr.removeSubscriber(new SubscriptionTestHelper("S2"));
- assertTrue(mgr.isEmpty());
- }
-
- public void testRoundRobin()
- {
- SubscriptionTestHelper a = new SubscriptionTestHelper("A");
- SubscriptionTestHelper b = new SubscriptionTestHelper("B");
- SubscriptionTestHelper c = new SubscriptionTestHelper("C");
- SubscriptionTestHelper d = new SubscriptionTestHelper("D");
- mgr.addSubscriber(a);
- mgr.addSubscriber(b);
- mgr.addSubscriber(c);
- mgr.addSubscriber(d);
-
- for (int i = 0; i < 3; i++)
- {
- assertEquals(a, mgr.nextSubscriber(null));
- assertEquals(b, mgr.nextSubscriber(null));
- assertEquals(c, mgr.nextSubscriber(null));
- assertEquals(d, mgr.nextSubscriber(null));
- }
-
- c.setSuspended(true);
-
- for (int i = 0; i < 3; i++)
- {
- assertEquals(a, mgr.nextSubscriber(null));
- assertEquals(b, mgr.nextSubscriber(null));
- assertEquals(d, mgr.nextSubscriber(null));
- }
-
- mgr.removeSubscriber(a);
- d.setSuspended(true);
- c.setSuspended(false);
- Subscription e = new SubscriptionTestHelper("D");
- mgr.addSubscriber(e);
-
- for (int i = 0; i < 3; i++)
- {
- assertEquals(b, mgr.nextSubscriber(null));
- assertEquals(c, mgr.nextSubscriber(null));
- assertEquals(e, mgr.nextSubscriber(null));
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(SubscriptionManagerTest.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionSetTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionSetTest.java
deleted file mode 100644
index bcf54693d3..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionSetTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.queue;
-
-import junit.framework.TestCase;
-
-public class SubscriptionSetTest extends TestCase
-{
- /**
- * A SubscriptionSet that counts the number of items scanned.
- */
- static class TestSubscriptionSet extends SubscriptionSet
- {
- private int scanned = 0;
-
- void resetScanned()
- {
- scanned = 0;
- }
-
- protected void subscriberScanned()
- {
- ++scanned;
- }
-
- int getScanned()
- {
- return scanned;
- }
- }
-
- final SubscriptionTestHelper sub1 = new SubscriptionTestHelper("1");
- final SubscriptionTestHelper sub2 = new SubscriptionTestHelper("2");
- final SubscriptionTestHelper sub3 = new SubscriptionTestHelper("3");
-
- final SubscriptionTestHelper suspendedSub1 = new SubscriptionTestHelper("sus1", true);
- final SubscriptionTestHelper suspendedSub2 = new SubscriptionTestHelper("sus2", true);
- final SubscriptionTestHelper suspendedSub3 = new SubscriptionTestHelper("sus3", true);
-
- public void testNextMessage()
- {
- SubscriptionSet ss = new SubscriptionSet();
- assertNull(ss.nextSubscriber(null));
- assertEquals(0, ss.getCurrentSubscriber());
-
- ss.addSubscriber(sub1);
- assertEquals(sub1, ss.nextSubscriber(null));
- assertEquals(1, ss.getCurrentSubscriber());
- assertEquals(sub1, ss.nextSubscriber(null));
- assertEquals(1, ss.getCurrentSubscriber());
-
- ss.addSubscriber(sub2);
- ss.addSubscriber(sub3);
-
- assertEquals(sub2, ss.nextSubscriber(null));
- assertEquals(2, ss.getCurrentSubscriber());
-
- assertEquals(sub3, ss.nextSubscriber(null));
- assertEquals(3, ss.getCurrentSubscriber());
- }
-
- public void testNextMessageWhenAllSuspended()
- {
- SubscriptionSet ss = createAllSuspendedSubscriptionSet();
- assertNull(ss.nextSubscriber(null));
- assertEquals(3, ss.getCurrentSubscriber());
-
- assertNull(ss.nextSubscriber(null));
- assertEquals(3, ss.getCurrentSubscriber());
- }
-
- private TestSubscriptionSet createAllSuspendedSubscriptionSet()
- {
- TestSubscriptionSet ss = new TestSubscriptionSet();
- ss.addSubscriber(suspendedSub1);
- ss.addSubscriber(suspendedSub2);
- ss.addSubscriber(suspendedSub3);
- return ss;
- }
-
- public void testNextMessageAfterRemove()
- {
- SubscriptionSet ss = new SubscriptionSet();
- ss.addSubscriber(suspendedSub1);
- ss.addSubscriber(suspendedSub2);
- ss.addSubscriber(sub3);
- assertEquals(sub3, ss.nextSubscriber(null));
- assertEquals(3, ss.getCurrentSubscriber());
-
- assertEquals(suspendedSub1, ss.removeSubscriber(suspendedSub1));
-
- assertEquals(sub3, ss.nextSubscriber(null)); // Current implementation handles OutOfBoundsException here.
- assertEquals(2, ss.getCurrentSubscriber());
- }
-
- public void testNextMessageOverScanning()
- {
- TestSubscriptionSet ss = new TestSubscriptionSet();
- SubscriptionTestHelper sub = new SubscriptionTestHelper("test");
- ss.addSubscriber(suspendedSub1);
- ss.addSubscriber(sub);
- ss.addSubscriber(suspendedSub3);
- assertEquals(sub, ss.nextSubscriber(null));
- assertEquals(2, ss.getCurrentSubscriber());
- assertEquals(2, ss.getScanned());
-
- ss.resetScanned();
- sub.setSuspended(true);
- assertNull(ss.nextSubscriber(null));
- assertEquals(3, ss.getCurrentSubscriber());
- // Current implementation overscans by one item here.
- assertEquals(ss.size() + 1, ss.getScanned());
- }
-
- public void testNextMessageOverscanWorstCase() {
- TestSubscriptionSet ss = createAllSuspendedSubscriptionSet();
- ss.nextSubscriber(null);
- // Scans the subscriptions twice.
- assertEquals(ss.size() * 2, ss.getScanned());
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(SubscriptionSetTest.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
index 1fa70a08d4..eed60a1a7c 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
@@ -21,6 +21,8 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.framing.AMQShortString;
import java.util.ArrayList;
import java.util.List;
@@ -54,7 +56,12 @@ public class SubscriptionTestHelper implements Subscription
return messages;
}
- public void send(QueueEntry msg, AMQQueue queue)
+ public void setQueue(AMQQueue queue)
+ {
+
+ }
+
+ public void send(QueueEntry msg)
{
messages.add(msg);
}
@@ -79,9 +86,39 @@ public class SubscriptionTestHelper implements Subscription
//no-op
}
- public Object getSendLock()
+ public void getSendLock()
+ {
+ return;
+ }
+
+ public void releaseSendLock()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void resend(final QueueEntry entry)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void restoreCredit(final QueueEntry queueEntry)
+ {
+
+ }
+
+ public void setStateListener(final StateListener listener)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public QueueEntry getLastSeenEntry()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue)
{
- return new Object();
+ return false; //To change body of implemented methods use File | Settings | File Templates.
}
public AMQChannel getChannel()
@@ -94,6 +131,26 @@ public class SubscriptionTestHelper implements Subscription
//no-op
}
+ public AMQShortString getConsumerTag()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isActive()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQQueue getQueue()
+ {
+ return null;
+ }
+
+ public QueueEntry.SubscriptionAcquiredState getOwningState()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void queueDeleted(AMQQueue queue)
{
}
@@ -108,6 +165,11 @@ public class SubscriptionTestHelper implements Subscription
return true;
}
+ public boolean isAutoClose()
+ {
+ return false;
+ }
+
public Queue<QueueEntry> getPreDeliveryQueue()
{
return null;
@@ -157,5 +219,4 @@ public class SubscriptionTestHelper implements Subscription
{
return key.toString();
}
-
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java
index 6ffa3e0e02..792744903e 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java
@@ -22,12 +22,11 @@ package org.apache.qpid.server.store;
import org.apache.commons.configuration.Configuration;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.exchange.Exchange;
@@ -130,17 +129,17 @@ public class SkeletonMessageStore implements MessageStore
return null;
}
- public void removeQueue(AMQShortString name) throws AMQException
+ public void removeQueue(final AMQQueue queue) throws AMQException
{
}
- public void enqueueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
}
- public void dequeueMessage(StoreContext context, AMQShortString name, Long messageId) throws AMQException
+ public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
{
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java b/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java
index c7984d5d33..f36e924890 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java
@@ -28,6 +28,7 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.AMQMessageHandle;
import org.apache.qpid.server.txn.NonTransactionalContext;
/**
@@ -39,6 +40,7 @@ public class TestReferenceCounting extends TestCase
private StoreContext _storeContext = new StoreContext();
+
protected void setUp() throws Exception
{
super.setUp();
@@ -50,7 +52,7 @@ public class TestReferenceCounting extends TestCase
*/
public void testMessageGetsRemoved() throws AMQException
{
- createPersistentContentHeader();
+ ContentHeaderBody chb = createPersistentContentHeader();
MessagePublishInfo info = new MessagePublishInfo()
{
@@ -81,16 +83,22 @@ public class TestReferenceCounting extends TestCase
}
};
- AMQMessage message = new AMQMessage(_store.getNewMessageId(), info,
- new NonTransactionalContext(_store, _storeContext, null, null),
- createPersistentContentHeader());
+
+ final long messageId = _store.getNewMessageId();
+ AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
+ messageHandle.setPublishAndContentHeaderBody(_storeContext,info, chb);
+ AMQMessage message = new AMQMessage(messageHandle,
+ _storeContext,info);
+
message = message.takeReference();
// we call routing complete to set up the handle
- message.routingComplete(_store, _storeContext, new MessageHandleFactory());
- assertTrue(_store.getMessageMetaDataMap().size() == 1);
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+ assertEquals(1, _store.getMessageMetaDataMap().size());
message.decrementReference(_storeContext);
- assertTrue(_store.getMessageMetaDataMap().size() == 0);
+ assertEquals(1, _store.getMessageMetaDataMap().size());
}
private ContentHeaderBody createPersistentContentHeader()
@@ -134,18 +142,25 @@ public class TestReferenceCounting extends TestCase
}
};
- AMQMessage message = new AMQMessage(_store.getNewMessageId(),
- info,
- new NonTransactionalContext(_store, _storeContext, null, null),
- createPersistentContentHeader());
+ final Long messageId = _store.getNewMessageId();
+ final ContentHeaderBody chb = createPersistentContentHeader();
+ AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
+ messageHandle.setPublishAndContentHeaderBody(_storeContext,info,chb);
+ AMQMessage message = new AMQMessage(messageHandle,
+ _storeContext,
+ info);
+
message = message.takeReference();
// we call routing complete to set up the handle
- message.routingComplete(_store, _storeContext, new MessageHandleFactory());
- assertTrue(_store.getMessageMetaDataMap().size() == 1);
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+
+ assertEquals(1, _store.getMessageMetaDataMap().size());
message = message.takeReference();
message.decrementReference(_storeContext);
- assertTrue(_store.getMessageMetaDataMap().size() == 1);
+ assertEquals(1, _store.getMessageMetaDataMap().size());
}
public static junit.framework.Test suite()
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
index 57370f490f..5659f533a1 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
@@ -110,13 +110,10 @@ public class DupsOkTest extends QpidTestCase
{
try
{
- long remainingMessages = ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue);
- fail("The queue should have 0 msgs left, seen " + _msgCount + " messages, left: "
- + remainingMessages);
- }
- catch (AMQException e)
- {
- fail("Got AMQException" + e.getMessage());
+ if(_msgCount != MSG_COUNT)
+ {
+ assertEquals("Wrong number of messages seen.", MSG_COUNT, _msgCount);
+ }
}
finally
{
@@ -124,7 +121,6 @@ public class DupsOkTest extends QpidTestCase
_awaitCompletion.countDown();
}
}
-
}
catch (JMSException e)
{
@@ -147,6 +143,11 @@ public class DupsOkTest extends QpidTestCase
fail("Unable to wait for test completion");
throw e;
}
+
+
+ // wait for the ack to get back
+ Thread.sleep(1000);
+
assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue));
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java
new file mode 100644
index 0000000000..da4f3ad0d1
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java
@@ -0,0 +1,210 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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;
+
+import org.apache.qpid.test.VMTestCase;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQSession_0_8;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.AMQException;
+import org.apache.log4j.Logger;
+
+import javax.jms.*;
+import javax.naming.NamingException;
+import java.util.Enumeration;
+
+public class FlowControlTest extends VMTestCase
+{
+ private static final Logger _logger = Logger.getLogger(FlowControlTest.class);
+
+ private Connection _clientConnection;
+ private Session _clientSession;
+ private Queue _queue;
+
+ public void setUp() throws Exception
+ {
+
+ super.setUp();
+
+
+ }
+
+ /**
+ * Simply
+ */
+ public void testBasicBytesFlowControl() throws JMSException, NamingException, AMQException
+ {
+ _queue = new AMQQueue("amq.direct","testqueue");//(Queue) _context.lookup("queue");
+
+ //Create Client
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientConnection.start();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Ensure _queue is created
+ _clientSession.createConsumer(_queue).close();
+
+ Connection producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ producerConnection.start();
+
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ BytesMessage m1 = producerSession.createBytesMessage();
+ m1.writeBytes(new byte[128]);
+ m1.setIntProperty("msg",1);
+ producer.send(m1);
+ BytesMessage m2 = producerSession.createBytesMessage();
+ m2.writeBytes(new byte[128]);
+ m2.setIntProperty("msg",2);
+ producer.send(m2);
+ BytesMessage m3 = producerSession.createBytesMessage();
+ m3.writeBytes(new byte[256]);
+ m3.setIntProperty("msg",3);
+ producer.send(m3);
+
+ producer.close();
+ producerSession.close();
+ producerConnection.close();
+
+
+ Connection consumerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+ Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ ((AMQSession_0_8)consumerSession).setPrefecthLimits(0,256);
+ MessageConsumer recv = consumerSession.createConsumer(_queue);
+ consumerConnection.start();
+
+ Message r1 = recv.receive(RECEIVE_TIMEOUT);
+ assertNotNull("First message not received", r1);
+ assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg"));
+
+ Message r2 = recv.receive(RECEIVE_TIMEOUT);
+ assertNotNull("Second message not received", r2);
+ assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg"));
+
+ Message r3 = recv.receiveNoWait();
+ assertNull("Third message incorrectly delivered", r3);
+
+ r1.acknowledge();
+
+ r3 = recv.receiveNoWait();
+ assertNull("Third message incorrectly delivered", r3);
+
+ r2.acknowledge();
+
+
+ r3 = recv.receive(RECEIVE_TIMEOUT);
+ assertNotNull("Third message not received", r3);
+ assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg"));
+
+ r3.acknowledge();
+ recv.close();
+ consumerSession.close();
+ consumerConnection.close();
+
+ }
+
+ public void testTwoConsumersBytesFlowControl() throws JMSException, NamingException, AMQException
+ {
+ _queue = new AMQQueue("amq.direct","testqueue1");//(Queue) _context.lookup("queue");
+
+ //Create Client
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientConnection.start();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Ensure _queue is created
+ _clientSession.createConsumer(_queue).close();
+
+ Connection producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ producerConnection.start();
+
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ BytesMessage m1 = producerSession.createBytesMessage();
+ m1.writeBytes(new byte[128]);
+ m1.setIntProperty("msg",1);
+ producer.send(m1);
+ BytesMessage m2 = producerSession.createBytesMessage();
+ m2.writeBytes(new byte[256]);
+ m2.setIntProperty("msg",2);
+ producer.send(m2);
+ BytesMessage m3 = producerSession.createBytesMessage();
+ m3.writeBytes(new byte[128]);
+ m3.setIntProperty("msg",3);
+ producer.send(m3);
+
+ producer.close();
+ producerSession.close();
+ producerConnection.close();
+
+
+ Connection consumerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+ Session consumerSession1 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ ((AMQSession_0_8)consumerSession1).setPrefecthLimits(0,256);
+ MessageConsumer recv1 = consumerSession1.createConsumer(_queue);
+
+ consumerConnection.start();
+
+ Message r1 = recv1.receive(RECEIVE_TIMEOUT);
+ assertNotNull("First message not received", r1);
+ assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg"));
+
+
+ Message r2 = recv1.receiveNoWait();
+ assertNull("Second message incorrectly delivered", r2);
+
+ Session consumerSession2 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ ((AMQSession_0_8)consumerSession2).setPrefecthLimits(0,256);
+ MessageConsumer recv2 = consumerSession2.createConsumer(_queue);
+
+
+ r2 = recv2.receive(100000L);//RECEIVE_TIMEOUT);
+ assertNotNull("Second message not received", r2);
+ assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg"));
+
+ Message r3 = recv2.receiveNoWait();
+ assertNull("Third message incorrectly delivered", r3);
+
+ r3 = recv1.receive(100000L);//RECEIVE_TIMEOUT);
+ assertNotNull("Third message not received", r3);
+ assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg"));
+
+
+
+ r2.acknowledge();
+ r3.acknowledge();
+ recv1.close();
+ recv2.close();
+ consumerSession1.close();
+ consumerSession2.close();
+ consumerConnection.close();
+
+ }
+
+}