summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2012-03-01 12:51:40 +0000
committerRobert Godfrey <rgodfrey@apache.org>2012-03-01 12:51:40 +0000
commit1f50bcb47f363c92f5f194fa55713e6c967a1449 (patch)
treed09de1f68f99d72772389d57e260ef7cf6c966f6
parente1126b978d046384380eeaa5a9b309618ddc7df5 (diff)
downloadqpid-python-1f50bcb47f363c92f5f194fa55713e6c967a1449.tar.gz
NO-JIRA: [AMQP 1-0 Sandbox] merging from trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rg-amqp-1-0-sandbox@1295541 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xqpid/java/bdbstore/bin/backup.sh2
-rwxr-xr-xqpid/java/bdbstore/bin/storeUpgrade.sh6
-rwxr-xr-xqpid/java/bdbstore/etc/scripts/bdbbackuptest.sh4
-rwxr-xr-xqpid/java/bdbstore/etc/scripts/bdbtest.sh4
-rw-r--r--qpid/java/bdbstore/src/main/java/backup-log4j.xml (renamed from qpid/java/bdbstore/src/resources/backup-log4j.xml)0
-rw-r--r--qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java7
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java122
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java1
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java2
-rw-r--r--qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java205
-rw-r--r--qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java1
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF3
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/build.xml2
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java28
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java38
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java12
-rwxr-xr-xqpid/java/broker/bin/msTool.sh60
-rw-r--r--qpid/java/broker/build.xml18
-rw-r--r--qpid/java/broker/etc/broker_example.acl63
-rw-r--r--qpid/java/broker/etc/config.xml7
-rw-r--r--qpid/java/broker/etc/debug.log4j.xml114
-rw-r--r--qpid/java/broker/etc/md5passwd3
-rw-r--r--qpid/java/broker/etc/mstool-log4j.xml54
-rw-r--r--qpid/java/broker/etc/qpid-server.conf25
-rw-r--r--qpid/java/broker/etc/qpid-server.conf.jpp48
-rw-r--r--qpid/java/broker/etc/qpid.passwd23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java27
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java88
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java24
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java37
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java15
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java67
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java47
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java71
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java33
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java66
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java176
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java20
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java280
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java19
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java86
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java40
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java38
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java68
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java20
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java252
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java77
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java6
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java53
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java38
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java179
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java89
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java291
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java71
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java83
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java30
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java143
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java665
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java19
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java7
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java98
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java145
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java4
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java9
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java47
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java170
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java74
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java264
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java29
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java40
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java652
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java66
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java85
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java36
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java59
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java305
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java98
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java314
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java94
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java202
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java67
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java54
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java233
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java516
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java90
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java121
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java364
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java105
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java20
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/MockConnectionConfig.java151
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java77
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java126
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java100
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java49
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java116
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/flow/WindowCreditManagerTest.java83
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java14
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java45
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java8
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java360
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java252
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java27
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java9
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java17
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java27
-rwxr-xr-xqpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java22
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java (renamed from qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTest.java)126
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java190
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java97
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java160
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java75
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java59
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java153
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java62
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java323
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java81
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java6
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java18
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java229
-rw-r--r--qpid/java/build.deps8
-rw-r--r--qpid/java/build.xml3
-rw-r--r--qpid/java/client-plugins/.gitignore21
-rwxr-xr-xqpid/java/client/src/main/java/client.bnd1
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java32
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java6
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java35
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java9
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java6
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java10
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java28
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java40
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java15
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java68
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java64
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java27
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java3
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java29
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/RejectBehaviour.java32
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java11
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java41
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties5
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java11
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/AMQConnectionUnitTest.java66
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java23
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java104
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java5
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java31
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java82
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java64
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java14
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java5
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java3
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java4
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java20
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java9
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionSettingsTest.java69
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/util/default.properties19
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties19
-rw-r--r--qpid/java/jca/README-GERONIMO.txt29
-rw-r--r--qpid/java/jca/README-JBOSS.txt168
-rw-r--r--qpid/java/jca/README.txt241
-rw-r--r--qpid/java/jca/build.xml69
-rw-r--r--qpid/java/jca/example/.gitignore2
-rw-r--r--qpid/java/jca/example/README.txt277
-rw-r--r--qpid/java/jca/example/build-geronimo-properties.xml169
-rw-r--r--qpid/java/jca/example/build-jboss-properties.xml115
-rw-r--r--qpid/java/jca/example/build-properties.xml.temp (renamed from qpid/java/systests/etc/config-systests-aclv2-settings.xml)13
-rw-r--r--qpid/java/jca/example/build.xml204
-rw-r--r--qpid/java/jca/example/conf/application.xml (renamed from qpid/java/systests/etc/virtualhosts-systests-aclv2.xml)26
-rw-r--r--qpid/java/jca/example/conf/ejb-jar.xml67
-rw-r--r--qpid/java/jca/example/conf/geronimo-application.xml151
-rw-r--r--qpid/java/jca/example/conf/geronimo-ra.xml138
-rw-r--r--qpid/java/jca/example/conf/jboss-web.xml (renamed from qpid/java/systests/etc/config-systests-aclv2.xml)24
-rw-r--r--qpid/java/jca/example/conf/jboss.xml80
-rw-r--r--qpid/java/jca/example/conf/log4j.properties18
-rw-r--r--qpid/java/jca/example/conf/qpid-jca-ds.xml123
-rw-r--r--qpid/java/jca/example/conf/web.xml52
-rw-r--r--qpid/java/jca/example/qpid-jca-example-properties.xml79
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java159
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java135
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java52
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java65
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java27
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java118
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java121
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java100
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java30
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java123
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java29
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java29
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java90
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java209
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java62
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java215
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java462
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java58
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java442
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java80
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java208
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java361
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java70
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java129
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java177
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java880
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java623
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java457
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java782
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java353
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java74
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java419
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java116
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java85
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java186
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java139
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java70
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java147
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java (renamed from qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java)19
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java62
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java911
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java1732
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java415
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java83
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java220
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java86
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java820
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java184
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java74
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java52
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java156
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java162
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java51
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java52
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java593
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java604
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java63
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java33
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java70
-rw-r--r--qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml (renamed from qpid/java/systests/etc/virtualhosts-systests-aclv2-settings.xml)41
-rwxr-xr-xqpid/java/jca/src/main/resources/META-INF/ra.xml220
-rw-r--r--qpid/java/lib/geronimo-ejb_3.0_spec-1.0.1.jarbin0 -> 32102 bytes
-rw-r--r--qpid/java/lib/geronimo-j2ee-connector_1.5_spec-2.0.0.jarbin0 -> 37477 bytes
-rw-r--r--qpid/java/lib/geronimo-jta_1.1_spec-1.1.1.jarbin0 -> 16030 bytes
-rw-r--r--qpid/java/lib/geronimo-kernel-2.2.1.jarbin0 -> 416154 bytes
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java19
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java23
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java43
-rw-r--r--qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java2
-rw-r--r--qpid/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java1
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java2
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java2
-rw-r--r--qpid/java/maven-settings.xml20
-rw-r--r--qpid/java/systests/etc/global-default.txt31
-rw-r--r--qpid/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt24
-rw-r--r--qpid/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt25
-rw-r--r--qpid/java/systests/etc/test-default.txt73
-rw-r--r--qpid/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt26
-rw-r--r--qpid/java/systests/etc/test-externalacljmx.txt35
-rw-r--r--qpid/java/systests/etc/test-logging.txt23
-rw-r--r--qpid/java/systests/etc/test2-default.txt21
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java20
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java5
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java20
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java50
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java166
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java239
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java129
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java9
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java336
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java17
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java173
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java3
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java (renamed from qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java)66
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java3
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java523
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java290
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java89
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java26
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java184
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java344
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java628
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java186
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java104
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java43
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java3
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java429
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java317
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java148
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java125
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java49
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java695
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java124
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java20
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java143
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java132
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java297
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java36
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java8
-rwxr-xr-xqpid/java/test-profiles/CPPExcludes33
-rw-r--r--qpid/java/test-profiles/CPPNoPrefetchExcludes7
-rw-r--r--qpid/java/test-profiles/Excludes12
-rwxr-xr-xqpid/java/test-profiles/Java010Excludes22
-rw-r--r--qpid/java/test-profiles/JavaExcludes10
-rw-r--r--qpid/java/test-profiles/JavaPre010Excludes1
-rw-r--r--qpid/java/test-profiles/python_tests/Java010PythonExcludes13
-rw-r--r--qpid/java/test-profiles/test_resources/ssl/java_broker_keystore.jksbin2475 -> 2474 bytes
-rw-r--r--qpid/java/tools/etc/perf-report.gnu19
-rw-r--r--qpid/java/tools/src/main/java/org/apache/qpid/tools/Clock.java20
-rw-r--r--qpid/java/tools/src/main/java/org/apache/qpid/tools/PerfTestController.java20
351 files changed, 27906 insertions, 9237 deletions
diff --git a/qpid/java/bdbstore/bin/backup.sh b/qpid/java/bdbstore/bin/backup.sh
index 22d8d52b58..b58ab16282 100755
--- a/qpid/java/bdbstore/bin/backup.sh
+++ b/qpid/java/bdbstore/bin/backup.sh
@@ -33,7 +33,7 @@ if [ -z "$QPID_HOME" ]; then
fi
VERSION=0.15
-LIBS=$QPID_HOME/lib/je-4.0.103.jar:$QPID_HOME/lib/qpid-bdbstore-$VERSION.jar:$QPID_HOME/lib/qpid-all.jar
+LIBS=$QPID_HOME/lib/opt/je-4.0.117.jar:$QPID_HOME/lib/qpid-bdbstore-$VERSION.jar:$QPID_HOME/lib/qpid-all.jar
echo "Starting Hot Backup Script"
diff --git a/qpid/java/bdbstore/bin/storeUpgrade.sh b/qpid/java/bdbstore/bin/storeUpgrade.sh
index f3b089b3d3..ffb33f7fbd 100755
--- a/qpid/java/bdbstore/bin/storeUpgrade.sh
+++ b/qpid/java/bdbstore/bin/storeUpgrade.sh
@@ -32,12 +32,8 @@ if [ -z "$QPID_HOME" ]; then
export PATH=${PATH}:${QPID_HOME}/bin
fi
-if [ -z "$BDB_HOME" ]; then
- export BDB_HOME=$(dirname $(dirname $(readlink -f $0)))
-fi
-
VERSION=0.15
-LIBS=$BDB_HOME/lib/je-4.0.103.jar:$BDB_HOME/lib/qpid-bdbstore-$VERSION.jar:$QPID_HOME/lib/qpid-all.jar
+LIBS=$QPID_HOME/lib/opt/je-4.0.117.jar:$QPID_HOME/lib/qpid-bdbstore-$VERSION.jar:$QPID_HOME/lib/qpid-all.jar
java -Xms256m -Dlog4j.configuration=BDBStoreUpgrade.log4j.xml -Xmx256m -Damqj.logging.level=warn ${JAVA_OPTS} -cp $LIBS org.apache.qpid.server.store.berkeleydb.BDBStoreUpgrade ${ARGS}
diff --git a/qpid/java/bdbstore/etc/scripts/bdbbackuptest.sh b/qpid/java/bdbstore/etc/scripts/bdbbackuptest.sh
index 2a0b72e5ad..4224f98de2 100755
--- a/qpid/java/bdbstore/etc/scripts/bdbbackuptest.sh
+++ b/qpid/java/bdbstore/etc/scripts/bdbbackuptest.sh
@@ -32,10 +32,10 @@ for arg in "$@"; do
fi
done
-VERSION=0.5
+VERSION=0.15
# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/qpid-junit-toolkit-$VERSION.jar:$QPID_HOME/lib/junit-3.8.1.jar:$QPID_HOME/lib/log4j-1.2.12.jar:$QPID_HOME/lib/qpid-systests-$VERSION.jar:$QPID_HOME/lib/qpid-perftests-$VERSION.jar:$QPID_HOME/lib/slf4j-log4j12-1.4.0.jar:$QPID_HOME/lib/qpid-bdbstore-$VERSION.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/qpid-junit-toolkit-$VERSION.jar:$QPID_HOME/lib/junit-3.8.1.jar:$QPID_HOME/lib/log4j-1.2.12.jar:$QPID_HOME/lib/qpid-systests-$VERSION.jar:$QPID_HOME/lib/qpid-perftests-$VERSION.jar:$QPID_HOME/lib/slf4j-log4j12-1.6.1.jar:$QPID_HOME/lib/qpid-bdbstore-$VERSION.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java JAVA_MEM=-Xmx256m QPID_CLASSPATH=$QPID_LIBS
diff --git a/qpid/java/bdbstore/etc/scripts/bdbtest.sh b/qpid/java/bdbstore/etc/scripts/bdbtest.sh
index eafdae9710..d53481c393 100755
--- a/qpid/java/bdbstore/etc/scripts/bdbtest.sh
+++ b/qpid/java/bdbstore/etc/scripts/bdbtest.sh
@@ -32,10 +32,10 @@ for arg in "$@"; do
fi
done
-VERSION=0.5
+VERSION=0.15
# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/qpid-junit-toolkit-$VERSION.jar:$QPID_HOME/lib/junit-3.8.1.jar:$QPID_HOME/lib/log4j-1.2.12.jar:$QPID_HOME/lib/qpid-systests-$VERSION.jar:$QPID_HOME/lib/qpid-perftests-$VERSION.jar:$QPID_HOME/lib/slf4j-log4j12-1.4.0.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/qpid-junit-toolkit-$VERSION.jar:$QPID_HOME/lib/junit-3.8.1.jar:$QPID_HOME/lib/log4j-1.2.12.jar:$QPID_HOME/lib/qpid-systests-$VERSION.jar:$QPID_HOME/lib/qpid-perftests-$VERSION.jar:$QPID_HOME/lib/slf4j-log4j12-1.6.1.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java JAVA_MEM=-Xmx256m QPID_CLASSPATH=$QPID_LIBS
diff --git a/qpid/java/bdbstore/src/resources/backup-log4j.xml b/qpid/java/bdbstore/src/main/java/backup-log4j.xml
index 6b0619f0b6..6b0619f0b6 100644
--- a/qpid/java/bdbstore/src/resources/backup-log4j.xml
+++ b/qpid/java/bdbstore/src/main/java/backup-log4j.xml
diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
index 4861e007af..8e55e79e01 100644
--- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
+++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
@@ -94,13 +94,6 @@ public class BDBUpgradeTest extends QpidBrokerTestCase
assertNotNull("QPID_WORK must be set", QPID_WORK_ORIG);
assertNotNull("QPID_HOME must be set", QPID_HOME);
- if(! isExternalBroker())
- {
- //override QPID_WORK to add the InVM port used so the store
- //output from the upgrade tool can be found by the broker
- setSystemProperty("QPID_WORK", QPID_WORK_ORIG + "/" + getPort());
- }
-
_fromDir = QPID_HOME + "/bdbstore-to-upgrade/test-store";
_toDir = getWorkDirBaseDir() + "/bdbstore/test-store";
_toDirTwice = getWorkDirBaseDir() + "/bdbstore-upgraded-twice";
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
index 78355a7501..402b991419 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
@@ -21,6 +21,7 @@ package org.apache.qpid.server.security.access.config;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
@@ -36,7 +37,7 @@ import javax.security.auth.Subject;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
-import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.log4j.Logger;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.security.Result;
import org.apache.qpid.server.security.access.ObjectProperties;
@@ -53,20 +54,15 @@ import org.apache.qpid.server.security.access.logging.AccessControlMessages;
*/
public class RuleSet
{
+ public static final Logger _logger = Logger.getLogger(RuleSet.class);
+
private static final String AT = "@";
private static final String SLASH = "/";
public static final String DEFAULT_ALLOW = "defaultallow";
public static final String DEFAULT_DENY = "defaultdeny";
- public static final String TRANSITIVE = "transitive";
- public static final String EXPAND = "expand";
- public static final String AUTONUMBER = "autonumber";
- public static final String CONTROLLED = "controlled";
- public static final String VALIDATE = "validate";
- public static final List<String> CONFIG_PROPERTIES = Arrays.asList(
- DEFAULT_ALLOW, DEFAULT_DENY, TRANSITIVE, EXPAND, AUTONUMBER, CONTROLLED
- );
+ public static final List<String> CONFIG_PROPERTIES = Arrays.asList(DEFAULT_ALLOW, DEFAULT_DENY);
private static final Integer _increment = 10;
@@ -80,7 +76,6 @@ public class RuleSet
{
// set some default configuration properties
configure(DEFAULT_DENY, Boolean.TRUE);
- configure(TRANSITIVE, Boolean.TRUE);
}
/**
@@ -139,12 +134,21 @@ public class RuleSet
// Save the rules we selected
objects.put(objectType, filtered);
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug("Cached " + objectType + " RulesList: " + filtered);
+ }
}
// Return the cached rules
- return objects.get(objectType);
- }
+ List<Rule> rules = objects.get(objectType);
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug("Returning RuleList: " + rules);
+ }
+ return rules;
+ }
public boolean isValidNumber(Integer number)
{
@@ -175,20 +179,6 @@ public class RuleSet
return false;
}
- private Permission noLog(Permission permission)
- {
- switch (permission)
- {
- case ALLOW:
- case ALLOW_LOG:
- return Permission.ALLOW;
- case DENY:
- case DENY_LOG:
- default:
- return Permission.DENY;
- }
- }
-
// TODO make this work when group membership is not known at file parse time
public void addRule(Integer number, String identity, Permission permission, Action action)
{
@@ -196,63 +186,13 @@ public class RuleSet
if (!action.isAllowed())
{
- throw new IllegalArgumentException("Action is not allowd: " + action);
+ throw new IllegalArgumentException("Action is not allowed: " + action);
}
if (ruleExists(identity, action))
{
return;
}
- // expand actions - possibly multiply number by
- if (isSet(EXPAND))
- {
- if (action.getOperation() == Operation.CREATE && action.getObjectType() == ObjectType.TOPIC)
- {
- addRule(null, identity, noLog(permission), new Action(Operation.BIND, ObjectType.EXCHANGE,
- new ObjectProperties("amq.topic", action.getProperties().get(ObjectProperties.Property.NAME))));
- ObjectProperties topicProperties = new ObjectProperties();
- topicProperties.put(ObjectProperties.Property.DURABLE, true);
- addRule(null, identity, permission, new Action(Operation.CREATE, ObjectType.QUEUE, topicProperties));
- return;
- }
- if (action.getOperation() == Operation.DELETE && action.getObjectType() == ObjectType.TOPIC)
- {
- addRule(null, identity, noLog(permission), new Action(Operation.UNBIND, ObjectType.EXCHANGE,
- new ObjectProperties("amq.topic", action.getProperties().get(ObjectProperties.Property.NAME))));
- ObjectProperties topicProperties = new ObjectProperties();
- topicProperties.put(ObjectProperties.Property.DURABLE, true);
- addRule(null, identity, permission, new Action(Operation.DELETE, ObjectType.QUEUE, topicProperties));
- return;
- }
- }
-
- // transitive action dependencies
- if (isSet(TRANSITIVE))
- {
- if (action.getOperation() == Operation.CREATE && action.getObjectType() == ObjectType.QUEUE)
- {
- ObjectProperties exchProperties = new ObjectProperties(action.getProperties());
- exchProperties.setName(ExchangeDefaults.DEFAULT_EXCHANGE_NAME);
- exchProperties.put(ObjectProperties.Property.ROUTING_KEY, action.getProperties().get(ObjectProperties.Property.NAME));
- addRule(null, identity, noLog(permission), new Action(Operation.BIND, ObjectType.EXCHANGE, exchProperties));
- if (action.getProperties().isSet(ObjectProperties.Property.AUTO_DELETE))
- {
- addRule(null, identity, noLog(permission), new Action(Operation.DELETE, ObjectType.QUEUE, action.getProperties()));
- }
- }
- else if (action.getOperation() == Operation.DELETE && action.getObjectType() == ObjectType.QUEUE)
- {
- ObjectProperties exchProperties = new ObjectProperties(action.getProperties());
- exchProperties.setName(ExchangeDefaults.DEFAULT_EXCHANGE_NAME);
- exchProperties.put(ObjectProperties.Property.ROUTING_KEY, action.getProperties().get(ObjectProperties.Property.NAME));
- addRule(null, identity, noLog(permission), new Action(Operation.UNBIND, ObjectType.EXCHANGE, exchProperties));
- }
- else if (action.getOperation() != Operation.ACCESS && action.getObjectType() != ObjectType.VIRTUALHOST)
- {
- addRule(null, identity, noLog(permission), new Action(Operation.ACCESS, ObjectType.VIRTUALHOST));
- }
- }
-
// set rule number if needed
Rule rule = new Rule(number, identity, action, permission);
if (rule.getNumber() == null)
@@ -392,24 +332,29 @@ public class RuleSet
// Create the action to check
Action action = new Action(operation, objectType, properties);
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug("Checking action: " + action);
+ }
+
// get the list of rules relevant for this request
List<Rule> rules = getRules(subject, operation, objectType);
if (rules == null)
{
- if (isSet(CONTROLLED))
+ if(_logger.isDebugEnabled())
{
- // Abstain if there are no rules for this operation
- return Result.ABSTAIN;
- }
- else
- {
- return getDefault();
+ _logger.debug("No rules found, returning default result");
}
+ return getDefault();
}
// Iterate through a filtered set of rules dealing with this identity and operation
for (Rule current : rules)
{
+ if(_logger.isDebugEnabled())
+ {
+ _logger.debug("Checking against rule: " + current);
+ }
// Check if action matches
if (action.matches(current.getAction()))
{
@@ -480,6 +425,15 @@ public class RuleSet
_config.put(key, value);
}
+ /**
+ * Returns all rules in the {@link RuleSet}. Primarily intended to support unit-testing.
+ * @return map of rules
+ */
+ public Map<Integer, Rule> getAllRules()
+ {
+ return Collections.unmodifiableMap(_rules);
+ }
+
private boolean isRelevant(final Set<Principal> principals, final Rule rule)
{
if (rule.getIdentity().equalsIgnoreCase(Rule.ALL))
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
index a7b3059262..a97b66a287 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
@@ -101,6 +101,7 @@ public class AccessControl extends AbstractPlugin
return Result.ABSTAIN;
}
+ _logger.debug("Checking " + operation + " " + objectType);
return _ruleSet.check(subject, operation, objectType, properties);
}
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
index f7db740ebc..b5c89910a6 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
@@ -45,7 +45,7 @@ public class AccessControlConfiguration extends ConfigurationPlugin
public List<String> getParentPaths()
{
- return Arrays.asList("security.aclv2", "virtualhosts.virtualhost.security.aclv2");
+ return Arrays.asList("security.acl", "virtualhosts.virtualhost.security.acl");
}
};
diff --git a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
index e16f9943ba..aa3982df71 100644
--- a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
+++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
@@ -22,12 +22,19 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.PrintWriter;
+import java.util.Map;
import junit.framework.TestCase;
import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectProperties.Property;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.access.config.ConfigurationFile;
import org.apache.qpid.server.security.access.config.PlainConfiguration;
+import org.apache.qpid.server.security.access.config.Rule;
+import org.apache.qpid.server.security.access.config.RuleSet;
/**
* These tests check that the ACL file parsing works correctly.
@@ -37,7 +44,7 @@ import org.apache.qpid.server.security.access.config.PlainConfiguration;
*/
public class PlainConfigurationTest extends TestCase
{
- public void writeACLConfig(String...aclData) throws Exception
+ private PlainConfiguration writeACLConfig(String...aclData) throws Exception
{
File acl = File.createTempFile(getClass().getName() + getName(), "acl");
acl.deleteOnExit();
@@ -51,8 +58,9 @@ public class PlainConfigurationTest extends TestCase
aclWriter.close();
// Load ruleset
- ConfigurationFile configFile = new PlainConfiguration(acl);
+ PlainConfiguration configFile = new PlainConfiguration(acl);
configFile.load();
+ return configFile;
}
public void testMissingACLConfig() throws Exception
@@ -191,4 +199,197 @@ public class PlainConfigurationTest extends TestCase
assertEquals(String.format(PlainConfiguration.PROPERTY_NO_VALUE_MSG, 1), ce.getMessage());
}
}
+
+ /**
+ * Tests interpretation of an acl rule with no object properties.
+ *
+ */
+ public void testValidRule() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL DENY-LOG user1 ACCESS VIRTUALHOST");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.ACCESS, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
+ assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl rule with object properties quoted in single quotes.
+ */
+ public void testValidRuleWithSingleQuotedProperty() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL ALLOW all CREATE EXCHANGE name = \'value\'");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "all", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.CREATE, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
+ final ObjectProperties expectedProperties = new ObjectProperties();
+ expectedProperties.setName("value");
+ assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl rule with object properties quoted in double quotes.
+ */
+ public void testValidRuleWithDoubleQuotedProperty() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL ALLOW all CREATE EXCHANGE name = \"value\"");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "all", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.CREATE, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
+ final ObjectProperties expectedProperties = new ObjectProperties();
+ expectedProperties.setName("value");
+ assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl rule with many object properties.
+ */
+ public void testValidRuleWithManyProperties() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL ALLOW admin DELETE QUEUE name=name1 owner = owner1");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "admin", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.DELETE, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.QUEUE, rule.getAction().getObjectType());
+ final ObjectProperties expectedProperties = new ObjectProperties();
+ expectedProperties.setName("name1");
+ expectedProperties.put(Property.OWNER, "owner1");
+ assertEquals("Rule has unexpected operation", expectedProperties, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl rule with object properties containing wildcards. Values containing
+ * hashes must be quoted otherwise they are interpreted as comments.
+ */
+ public void testValidRuleWithWildcardProperties() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL ALLOW all CREATE EXCHANGE routingKey = \'news.#\'",
+ "ACL ALLOW all CREATE EXCHANGE routingKey = \'news.co.#\'",
+ "ACL ALLOW all CREATE EXCHANGE routingKey = *.co.medellin");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(3, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(3, rules.size());
+ final Rule rule1 = rules.get(0);
+ assertEquals("Rule has unexpected identity", "all", rule1.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.CREATE, rule1.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule1.getAction().getObjectType());
+ final ObjectProperties expectedProperties1 = new ObjectProperties();
+ expectedProperties1.put(Property.ROUTING_KEY,"news.#");
+ assertEquals("Rule has unexpected object properties", expectedProperties1, rule1.getAction().getProperties());
+
+ final Rule rule2 = rules.get(10);
+ final ObjectProperties expectedProperties2 = new ObjectProperties();
+ expectedProperties2.put(Property.ROUTING_KEY,"news.co.#");
+ assertEquals("Rule has unexpected object properties", expectedProperties2, rule2.getAction().getProperties());
+
+ final Rule rule3 = rules.get(20);
+ final ObjectProperties expectedProperties3 = new ObjectProperties();
+ expectedProperties3.put(Property.ROUTING_KEY,"*.co.medellin");
+ assertEquals("Rule has unexpected object properties", expectedProperties3, rule3.getAction().getProperties());
+ }
+
+ /**
+ * Tests that rules are case insignificant.
+ */
+ public void testMixedCaseRuleInterpretation() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("AcL deny-LOG user1 BiND Exchange name=AmQ.dIrect");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.BIND, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
+ final ObjectProperties expectedProperties = new ObjectProperties("amq.direct");
+ assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests whitespace is supported. Note that currently the Java implementation permits comments to
+ * be introduced anywhere in the ACL, whereas the C++ supports only whitespace at the beginning of
+ * of line.
+ */
+ public void testCommentsSuppported() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("#Comment",
+ "ACL DENY-LOG user1 ACCESS VIRTUALHOST # another comment",
+ " # final comment with leading whitespace");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.ACCESS, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
+ assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl rule using mixtures of tabs/spaces as token separators.
+ *
+ */
+ public void testWhitespace() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL\tDENY-LOG\t\t user1\t \tACCESS VIRTUALHOST");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.ACCESS, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
+ assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
+ }
+
+ /**
+ * Tests interpretation of an acl utilising line continuation.
+ */
+ public void testLineContination() throws Exception
+ {
+ final PlainConfiguration config = writeACLConfig("ACL DENY-LOG user1 \\",
+ "ACCESS VIRTUALHOST");
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, Rule> rules = rs.getAllRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
+ assertEquals("Rule has unexpected operation", Operation.ACCESS, rule.getAction().getOperation());
+ assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
+ assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
+ }
+
}
diff --git a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
index bd9deac153..4d46a32f45 100644
--- a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
+++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
@@ -69,7 +69,6 @@ public class RuleSetTest extends QpidTestCase
super.setUp();
_ruleSet = new RuleSet();
- _ruleSet.configure(RuleSet.TRANSITIVE, Boolean.FALSE);
}
@Override
diff --git a/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF b/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF
index 49e90c6aad..0bd0a835e4 100644
--- a/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF
+++ b/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF
@@ -9,7 +9,8 @@ Bundle-Version: 1.0.0
Bundle-Activator: org.apache.qpid.shutdown.Activator
Import-Package: javax.management;resolution:=optional,
org.apache.log4j,
- org.osgi.framework
+ org.osgi.framework,
+ org.apache.qpid.server.management
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy
diff --git a/qpid/java/broker-plugins/experimental/shutdown/build.xml b/qpid/java/broker-plugins/experimental/shutdown/build.xml
index ec4fce374e..cb4254806b 100644
--- a/qpid/java/broker-plugins/experimental/shutdown/build.xml
+++ b/qpid/java/broker-plugins/experimental/shutdown/build.xml
@@ -20,7 +20,7 @@
-->
<project name="AMQ Broker Shutdown Plugin" default="build">
- <property name="module.depends" value="common broker broker-plugins"/>
+ <property name="module.depends" value="common broker management/common broker-plugins"/>
<property name="module.test.depends" value="test broker/test management/common client systests"/>
<property name="module.manifest" value="MANIFEST.MF"/>
<property name="module.plugin" value="true"/>
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java
index ad5e7707b6..2b7fa33784 100644
--- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java
@@ -19,11 +19,6 @@
*/
package org.apache.qpid.shutdown;
-import java.lang.management.ManagementFactory;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
import org.apache.log4j.Logger;
import org.osgi.framework.BundleActivator;
@@ -33,20 +28,17 @@ public class Activator implements BundleActivator
{
private static final Logger _logger = Logger.getLogger(Activator.class);
- private static final String SHUTDOWN_MBEAN_NAME = "org.apache.qpid:type=ShutdownMBean";
+ private Shutdown _shutdown = null;
/** @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */
public void start(BundleContext ctx) throws Exception {
- Shutdown shutdown = new Shutdown();
+ _shutdown = new Shutdown();
if (ctx != null)
{
- ctx.registerService(ShutdownMBean.class.getName(), shutdown, null);
+ ctx.registerService(ShutdownMBean.class.getName(), _shutdown, null);
}
- // MBean registration
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- ObjectName name = new ObjectName(SHUTDOWN_MBEAN_NAME);
- mbs.registerMBean(shutdown, name);
+ _shutdown.register();
_logger.info("Shutdown plugin MBean registered");
}
@@ -54,16 +46,10 @@ public class Activator implements BundleActivator
/** @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */
public void stop(BundleContext ctx) throws Exception
{
- // Unregister MBean
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- ObjectName name = new ObjectName(SHUTDOWN_MBEAN_NAME);
- try
- {
- mbs.unregisterMBean(name);
- }
- catch (InstanceNotFoundException e)
+ if (_shutdown != null)
{
- //ignore
+ _shutdown.unregister();
+ _shutdown = null;
}
_logger.info("Shutdown plugin MBean unregistered");
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java
index 9a6f85fe9c..cef4a42b64 100644
--- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java
@@ -27,21 +27,30 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import javax.management.NotCompliantMBeanException;
+
import org.apache.log4j.Logger;
+import org.apache.qpid.server.management.DefaultManagedObject;
/**
* Implementation of the JMX broker shutdown plugin.
*/
-public class Shutdown implements ShutdownMBean
+public class Shutdown extends DefaultManagedObject implements ShutdownMBean
{
+
private static final Logger _logger = Logger.getLogger(Shutdown.class);
- private static final String FORMAT = "yyyyy/MM/dd hh:mm:ss";
+ private static final String FORMAT = "yyyy/MM/dd HH:mm:ss";
private static final int THREAD_COUNT = 1;
private static final ScheduledExecutorService EXECUTOR = new ScheduledThreadPoolExecutor(THREAD_COUNT);
private final Runnable _shutdown = new SystemExiter();
+ public Shutdown() throws NotCompliantMBeanException
+ {
+ super(ShutdownMBean.class, ShutdownMBean.TYPE);
+ }
+
/** @see ShutdownMBean#shutdown() */
public void shutdown()
{
@@ -50,14 +59,22 @@ public class Shutdown implements ShutdownMBean
}
/** @see ShutdownMBean#shutdown(long) */
- public void shutdown(long delay)
+ public void shutdown(final long delay)
{
- _logger.info("Scheduled broker shutdown after " + delay + "ms");
- shutdownBroker(delay);
+ if (delay < 0)
+ {
+ _logger.info("Shutting down at user's request");
+ shutdownBroker(0);
+ }
+ else
+ {
+ _logger.info("Scheduled broker shutdown after " + delay + "ms");
+ shutdownBroker(delay);
+ }
}
/** @see ShutdownMBean#shutdownAt(String) */
- public void shutdownAt(String when)
+ public void shutdownAt(final String when)
{
Date date;
DateFormat df = new SimpleDateFormat(FORMAT);
@@ -101,4 +118,13 @@ public class Shutdown implements ShutdownMBean
System.exit(0);
}
}
+
+ /**
+ * @see org.apache.qpid.server.management.ManagedObject#getObjectInstanceName()
+ */
+ @Override
+ public String getObjectInstanceName()
+ {
+ return "Shutdown";
+ }
}
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java
index 6294f869e9..48d2eab8df 100644
--- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java
@@ -19,6 +19,9 @@
*/
package org.apache.qpid.shutdown;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
/**
* Shutdown plugin JMX MBean interface.
*
@@ -26,9 +29,12 @@ package org.apache.qpid.shutdown;
*/
public interface ShutdownMBean
{
+ static final String TYPE = "Shutdown";
+
/**
* Broker will be shut down immediately.
*/
+ @MBeanOperation(name="shutdown", description="Shut down immediately")
public void shutdown();
/**
@@ -36,12 +42,14 @@ public interface ShutdownMBean
*
* @param delay the number of ms to wait
*/
- public void shutdown(long delay);
+ @MBeanOperation(name="shutdown", description="Shutdown after the specified delay (ms)")
+ public void shutdown(@MBeanOperationParameter(name="when", description="delay (ms)")long delay);
/**
* Broker will be shutdown at the specified date and time.
*
* @param when the date and time to shutdown
*/
- public void shutdownAt(String when);
+ @MBeanOperation(name="shutdownAt", description="Shutdown at the specified date and time (yyyy/MM/dd HH:mm:ss)")
+ public void shutdownAt(@MBeanOperationParameter(name="when", description="shutdown date/time (yyyy/MM/dd HH:mm:ss)")String when);
}
diff --git a/qpid/java/broker/bin/msTool.sh b/qpid/java/broker/bin/msTool.sh
deleted file mode 100755
index e190a0a46a..0000000000
--- a/qpid/java/broker/bin/msTool.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-die() {
- if [[ $1 = -usage ]]; then
- shift
- usage=true
- else
- usage=false
- fi
- echo "$@"
- $usage && echo
- $usage && usage
- exit 1
-}
-
-cygwin=false
-if [[ "$(uname -a | fgrep Cygwin)" != "" ]]; then
- cygwin=true
-fi
-
-if [ -z "$QPID_TOOLS" ]; then
- if [ -z "$QPID_HOME" ]; then
- die "QPID_TOOLS must be set"
- else
- QPID_TOOLS=$QPID_HOME
- fi
-fi
-
-if $cygwin; then
- QPID_TOOLS=$(cygpath -w $QPID_TOOLS)
-fi
-
-# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_TOOLS/lib/qpid-all.jar
-
-# Set other variables used by the qpid-run script before calling
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_OPTS=-Dlog4j.configuration=file:$QPID_TOOLS/etc/mstool-log4j.xml \
- QPID_CLASSPATH=$QPID_LIBS
-
-. qpid-run org.apache.qpid.tools.messagestore.MessageStoreTool "$@"
diff --git a/qpid/java/broker/build.xml b/qpid/java/broker/build.xml
index 6ea2b9a63e..4a42e5cdb8 100644
--- a/qpid/java/broker/build.xml
+++ b/qpid/java/broker/build.xml
@@ -72,14 +72,26 @@
<fixcrlf srcdir="${module.release}/bin" fixlast="true" eol="dos" includes="*.bat"/>
</target>
- <target name="release-bin-other" description="copy broker-plugins into module release">
+ <target name="release-bin-other" depends="release-bin-other-bdbstore" description="copy broker-plugins into module release">
<copy todir="${module.release}/lib/plugins" failonerror="true">
<fileset dir="${build.lib}/plugins"/>
</copy>
- <!--copy optional bdbstore module if it exists -->
- <copy todir="${module.release}/lib/" failonerror="false">
+ </target>
+
+ <target name="release-bin-other-bdbstore" depends="check-bdbstore-requested" if="bdbstore-requested"
+ description="copy bdbstore items into module release">
+ <copy todir="${module.release}/lib/" failonerror="true">
<fileset file="${build.lib}/${project.name}-bdbstore-${project.version}.jar"/>
</copy>
+ <copy todir="${module.release}/bin" failonerror="true" flatten="true">
+ <fileset dir="${basedir}/../bdbstore/bin"/>
+ </copy>
+ </target>
+
+ <target name="check-bdbstore-requested">
+ <condition property="bdbstore-requested">
+ <contains string="${modules.opt}" substring="bdbstore"/>
+ </condition>
</target>
<target name="release-bin" depends="release-bin-tasks"/>
diff --git a/qpid/java/broker/etc/broker_example.acl b/qpid/java/broker/etc/broker_example.acl
new file mode 100644
index 0000000000..93955bb7f9
--- /dev/null
+++ b/qpid/java/broker/etc/broker_example.acl
@@ -0,0 +1,63 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+### EXAMPLE ACL V2 FILE
+
+### DEFINE GROUPS ###
+
+#Define a 'messaging-users' group with users 'client' and 'server' in it
+GROUP messaging-users client server
+
+### MANAGEMENT ####
+
+#Allow 'guest' to perform read operations on the Serverinformation mbean and view logger levels
+ACL ALLOW-LOG guest ACCESS METHOD component="ServerInformation"
+ACL ALLOW-LOG guest ACCESS METHOD component="LoggingManagement" name="viewEffectiveRuntimeLoggerLevels"
+
+#Allow 'admin' all management operations
+ACL ALLOW-LOG admin ALL METHOD
+
+### MESSAGING ###
+
+#Example permissions for request-response based messaging.
+
+#Allow 'messaging-users' group to connect to the virtualhost
+ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST
+
+# Client side
+# Allow the 'client' user to publish requests to the request queue and create, consume from, and delete temporary reply queues.
+ACL ALLOW-LOG client CREATE QUEUE temporary="true"
+ACL ALLOW-LOG client CONSUME QUEUE temporary="true"
+ACL ALLOW-LOG client DELETE QUEUE temporary="true"
+ACL ALLOW-LOG client BIND EXCHANGE name="amq.direct" temporary="true"
+ACL ALLOW-LOG client UNBIND EXCHANGE name="amq.direct" temporary="true"
+ACL ALLOW-LOG client PUBLISH EXCHANGE name="amq.direct" routingKey="example.RequestQueue"
+
+# Server side
+# Allow the 'server' user to create and consume from the request queue and publish a response to the temporary response queue created by
+# client.
+ACL ALLOW-LOG server CREATE QUEUE name="example.RequestQueue"
+ACL ALLOW-LOG server CONSUME QUEUE name="example.RequestQueue"
+ACL ALLOW-LOG server BIND EXCHANGE
+ACL ALLOW-LOG server PUBLISH EXCHANGE name="amq.direct" routingKey="TempQueue*"
+
+### DEFAULT ###
+
+#Deny all users from performing all operations
+ACL DENY-LOG all all
diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml
index d18e1392e6..25fda69f68 100644
--- a/qpid/java/broker/etc/config.xml
+++ b/qpid/java/broker/etc/config.xml
@@ -80,7 +80,12 @@
</principal-database>
</pd-auth-manager>
- <allow-all />
+ <!-- By default, all authenticated users have permissions to perform all actions -->
+
+ <!-- ACL Example
+ This example illustrates securing the both Management (JMX) and Messaging.
+ <acl>${conf}/broker_example.acl</acl>
+ -->
<msg-auth>false</msg-auth>
</security>
diff --git a/qpid/java/broker/etc/debug.log4j.xml b/qpid/java/broker/etc/debug.log4j.xml
deleted file mode 100644
index fc0bd9f34f..0000000000
--- a/qpid/java/broker/etc/debug.log4j.xml
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- --><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="null" threshold="null">
- <appender class="org.apache.log4j.QpidCompositeRollingAppender" name="ArchivingFileAppender">
- <!-- Ensure that logs allways have the dateFormat set-->
- <param name="StaticLogFileName" value="false"/>
- <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
- <param name="Append" value="false"/>
- <!-- Change the direction so newer files have bigger numbers -->
- <!-- So log.1 is written then log.2 etc This prevents a lot of file renames at log rollover -->
- <param name="CountDirection" value="1"/>
- <!-- Use default 10MB -->
- <!--param name="MaxFileSize" value="100000"/-->
- <param name="DatePattern" value="'.'yyyy-MM-dd-HH-mm"/>
- <!-- Unlimited number of backups -->
- <param name="MaxSizeRollBackups" value="-1"/>
- <!-- Compress(gzip) the backup files-->
- <param name="CompressBackupFiles" value="true"/>
- <!-- Compress the backup files using a second thread -->
- <param name="CompressAsync" value="true"/>
- <!-- Start at zero numbered files-->
- <param name="ZeroBased" value="true"/>
- <!-- Backup Location -->
- <param name="backupFilesToPath" value="${QPID_WORK}/backup/log"/>
-
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <appender class="org.apache.log4j.FileAppender" name="FileAppender">
- <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
- <param name="Append" value="false"/>
-
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <appender class="org.apache.log4j.FileAppender" name="AlertFile">
- <param name="File" value="${QPID_WORK}/log/alert.log"/>
- <param name="Append" value="false"/>
-
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <appender class="org.apache.log4j.ConsoleAppender" name="STDOUT">
-
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <category additivity="true" name="Qpid.Broker">
- <priority value="debug"/>
- <appender-ref ref="AlertFile"/>
- <!--appender-ref ref="STDOUT"/-->
- </category>
-
-
- <category additivity="true" name="org.apache.qpid.server.queue.AMQQueueMBean">
- <priority value="info"/>
- <appender-ref ref="AlertFile"/>
- </category>
-
-
- <!-- Provide warnings to standard output -->
- <!--category additivity="true" name="org.apache.qpid">
- <priority value="warn"/>
- <appender-ref ref="STDOUT"/>
- </category-->
-
-
- <!-- Additional level settings for debugging -->
- <!-- Each class in the Broker is a category that can have its logging level adjusted. -->
- <!-- This will provide more details if available about that classes processing. -->
- <!--category additivity="true" name="org.apache.qpid.server.txn">
- <priority value="debug"/>
- </category>-->
-
- <!--<category additivity="true" name="org.apache.qpid.server.store">
- <priority value="debug"/>
- </category-->
-
- <!-- Log all info events to file -->
- <root>
- <priority value="debug"/>
- <appender-ref ref="STDOUT"/>
- <!--appender-ref ref="FileAppender"/-->
- </root>
-
-</log4j:configuration>
diff --git a/qpid/java/broker/etc/md5passwd b/qpid/java/broker/etc/md5passwd
index 6a149919de..59354a21f5 100644
--- a/qpid/java/broker/etc/md5passwd
+++ b/qpid/java/broker/etc/md5passwd
@@ -17,5 +17,6 @@
# under the License.
#
guest:CE4DQ6BIb/BVMN9scFyLtA==
+client:CE4DQ6BIb/BVMN9scFyLtA==
+server:CE4DQ6BIb/BVMN9scFyLtA==
admin:ISMvKXpXpadDiUoOSoAfww==
-user:aBzonUodYLhwSa8s9A10sA==
diff --git a/qpid/java/broker/etc/mstool-log4j.xml b/qpid/java/broker/etc/mstool-log4j.xml
deleted file mode 100644
index 8c46010e2d..0000000000
--- a/qpid/java/broker/etc/mstool-log4j.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-
- <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
-
- <layout class="org.apache.log4j.PatternLayout">
- <!--param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/-->
- <param name="ConversionPattern" value="%d %-5p [%t] (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <category name="org.apache.qpid.tools">
- <priority value="info"/>
- </category>
-
- <category name="org.apache.qpid">
- <priority value="error"/>
- </category>
-
- <category name="org.apache.qpid.server.security">
- <priority value="error"/>
- </category>
-
- <category name="org.apache.qpid.server.management">
- <priority value="error"/>
- </category>
-
-
- <root>
- <priority value="info"/>
- <appender-ref ref="STDOUT"/>
- </root>
-</log4j:configuration>
diff --git a/qpid/java/broker/etc/qpid-server.conf b/qpid/java/broker/etc/qpid-server.conf
deleted file mode 100644
index 8a16849b04..0000000000
--- a/qpid/java/broker/etc/qpid-server.conf
+++ /dev/null
@@ -1,25 +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.
-#
-
-QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar
-
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_MEM=-Xmx1024m \
- CLASSPATH=$QPID_LIBS
diff --git a/qpid/java/broker/etc/qpid-server.conf.jpp b/qpid/java/broker/etc/qpid-server.conf.jpp
deleted file mode 100644
index 0378c82fd9..0000000000
--- a/qpid/java/broker/etc/qpid-server.conf.jpp
+++ /dev/null
@@ -1,48 +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.
-#
-
-QPID_LIBS=$(build-classpath commons-beanutils \
- commons-beanutils-core \
- commons-cli \
- commons-codec \
- commons-collections \
- commons-configuration \
- commons-digester \
- commons-lang \
- commons-logging \
- commons-logging-api \
- dom4j \
- geronimo-jms-1.1-api \
- isorelax \
- jaxen \
- log4j \
- mina/core \
- mina/filter-ssl \
- mina/java5 \
- msv-msv \
- qpid-broker \
- qpid-client \
- qpid-common \
- relaxngDatatype \
- slf4j)
-
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_MEM=-Xmx1024m \
- CLASSPATH=$QPID_LIBS
diff --git a/qpid/java/broker/etc/qpid.passwd b/qpid/java/broker/etc/qpid.passwd
deleted file mode 100644
index dbfb9d1923..0000000000
--- a/qpid/java/broker/etc/qpid.passwd
+++ /dev/null
@@ -1,23 +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.
-#
-guest:CE4DQ6BIb/BVMN9scFyLtA==
-admin:ISMvKXpXpadDiUoOSoAfww==
-user:CE4DQ6BIb/BVMN9scFyLtA==
-server:CE4DQ6BIb/BVMN9scFyLtA==
-client:CE4DQ6BIb/BVMN9scFyLtA==
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index d1ea5dba69..01a0d9900d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -20,8 +20,8 @@ package org.apache.qpid.server;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import java.util.Map;
import javax.management.JMException;
import javax.management.MBeanException;
@@ -30,6 +30,7 @@ import javax.management.ObjectName;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
@@ -60,6 +61,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
private final QueueRegistry _queueRegistry;
private final ExchangeRegistry _exchangeRegistry;
private final ExchangeFactory _exchangeFactory;
+ private final Exchange _defaultExchange;
private final DurableConfigurationStore _durableConfig;
private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean;
@@ -74,6 +76,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
_queueRegistry = virtualHost.getQueueRegistry();
_exchangeRegistry = virtualHost.getExchangeRegistry();
+ _defaultExchange = _exchangeRegistry.getDefaultExchange();
_durableConfig = virtualHost.getDurableConfigurationStore();
_exchangeFactory = virtualHost.getExchangeFactory();
}
@@ -241,7 +244,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
*/
public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException
{
- AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName));
+ createNewQueue(queueName, owner, durable, null);
+ }
+
+ public void createNewQueue(String queueName, String owner, boolean durable, Map<String,Object> arguments) throws JMException
+ {
+ final AMQShortString queueNameAsAMQShortString = new AMQShortString(queueName);
+ AMQQueue queue = _queueRegistry.getQueue(queueNameAsAMQShortString);
if (queue != null)
{
throw new JMException("The queue \"" + queueName + "\" already exists.");
@@ -256,13 +265,21 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
ownerShortString = new AMQShortString(owner);
}
- queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, getVirtualHost(), null);
+ FieldTable args = null;
+ if(arguments != null)
+ {
+ args = FieldTable.convertToFieldTable(arguments);
+ }
+ final VirtualHost virtualHost = getVirtualHost();
+
+ queue = AMQQueueFactory.createAMQQueueImpl(queueNameAsAMQShortString, durable, ownerShortString,
+ false, false, getVirtualHost(), args);
if (queue.isDurable() && !queue.isAutoDelete())
{
- _durableConfig.createQueue(queue);
+ _durableConfig.createQueue(queue, args);
}
- _queueRegistry.registerQueue(queue);
+ virtualHost.getBindingFactory().addBinding(queueName, queue, _defaultExchange, null);
}
catch (AMQException ex)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 2a96426f02..30d620401f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -22,7 +22,6 @@ package org.apache.qpid.server;
import org.apache.log4j.Logger;
-import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQMethodBody;
@@ -53,6 +52,7 @@ import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.logging.messages.ExchangeMessages;
import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.server.message.MessageReference;
import org.apache.qpid.server.message.ServerMessage;
@@ -63,6 +63,7 @@ import org.apache.qpid.server.protocol.AMQSessionModel;
import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.InboundMessageAdapter;
import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
@@ -693,6 +694,31 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
}
+ public boolean isMaxDeliveryCountEnabled(final long deliveryTag)
+ {
+ final QueueEntry queueEntry = _unacknowledgedMessageMap.get(deliveryTag);
+ if (queueEntry != null)
+ {
+ final int maximumDeliveryCount = queueEntry.getQueue().getMaximumDeliveryCount();
+ return maximumDeliveryCount > 0;
+ }
+
+ return false;
+ }
+
+ public boolean isDeliveredTooManyTimes(final long deliveryTag)
+ {
+ final QueueEntry queueEntry = _unacknowledgedMessageMap.get(deliveryTag);
+ if (queueEntry != null)
+ {
+ final int maximumDeliveryCount = queueEntry.getQueue().getMaximumDeliveryCount();
+ final int numDeliveries = queueEntry.getDeliveryCount();
+ return maximumDeliveryCount != 0 && numDeliveries >= maximumDeliveryCount;
+ }
+
+ return false;
+ }
+
/**
* Called to resend all outstanding unacknowledged messages to this same channel.
*
@@ -740,9 +766,9 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
QueueEntry message = entry.getValue();
long deliveryTag = entry.getKey();
+ //Amend the delivery counter as the client hasn't seen these messages yet.
+ message.decrementDeliveryCount();
-
- ServerMessage msg = message.getMessage();
AMQQueue queue = message.getQueue();
// Our Java Client will always suspend the channel when resending!
@@ -800,6 +826,10 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
QueueEntry message = entry.getValue();
long deliveryTag = entry.getKey();
+
+ //Amend the delivery counter as the client hasn't seen these messages yet.
+ message.decrementDeliveryCount();
+
_unacknowledgedMessageMap.remove(deliveryTag);
message.setRedelivered();
@@ -1060,6 +1090,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(),
deliveryTag,
((SubscriptionImpl)sub).getConsumerTag());
+ entry.incrementDeliveryCount();
}
};
@@ -1248,7 +1279,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
private final Collection<QueueEntry> _ackedMessages;
-
public MessageAcknowledgeAction(Collection<QueueEntry> ackedMessages)
{
_ackedMessages = ackedMessages;
@@ -1481,4 +1511,54 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
}
}
}
+
+ public void deadLetter(long deliveryTag) throws AMQException
+ {
+ final UnacknowledgedMessageMap unackedMap = getUnacknowledgedMessageMap();
+ final QueueEntry rejectedQueueEntry = unackedMap.get(deliveryTag);
+
+ if (rejectedQueueEntry == null)
+ {
+ _logger.warn("No message found, unable to DLQ delivery tag: " + deliveryTag);
+ return;
+ }
+ else
+ {
+ final ServerMessage msg = rejectedQueueEntry.getMessage();
+
+ final AMQQueue queue = rejectedQueueEntry.getQueue();
+
+ final Exchange altExchange = queue.getAlternateExchange();
+ unackedMap.remove(deliveryTag);
+
+ if (altExchange == null)
+ {
+ _logger.debug("No alternate exchange configured for queue, must discard the message as unable to DLQ: delivery tag: " + deliveryTag);
+ _actor.message(_logSubject, ChannelMessages.DISCARDMSG_NOALTEXCH(msg.getMessageNumber(), queue.getName(), msg.getRoutingKey()));
+ rejectedQueueEntry.discard();
+ return;
+ }
+
+ final InboundMessage m = new InboundMessageAdapter(rejectedQueueEntry);
+
+ final ArrayList<? extends BaseQueue> destinationQueues = altExchange.route(m);
+
+ if (destinationQueues == null || destinationQueues.isEmpty())
+ {
+ _logger.debug("Routing process provided no queues to enqueue the message on, must discard message as unable to DLQ: delivery tag: " + deliveryTag);
+ _actor.message(_logSubject, ChannelMessages.DISCARDMSG_NOROUTE(msg.getMessageNumber(), altExchange.getName()));
+ rejectedQueueEntry.discard();
+ return;
+ }
+
+ rejectedQueueEntry.routeToAlternate();
+
+ //output operational logging for each delivery post commit
+ for (final BaseQueue destinationQueue : destinationQueues)
+ {
+ _actor.message(_logSubject, ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(), destinationQueue.getNameShortString().asString()));
+ }
+
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
index 400ce50bc4..94ab43c851 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
@@ -170,11 +170,17 @@ public class BindingFactory
{
arguments = Collections.emptyMap();
}
-
- //Perform ACLs
- if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey)))
+
+ // The default exchange bindings must reflect the existence of queues, allow
+ // all operations on it to succeed. It is up to the broker to prevent illegal
+ // attempts at binding to this exchange, not the ACLs.
+ if(exchange != _defaultExchange)
{
- throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ //Perform ACLs
+ if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey)))
+ {
+ throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ }
}
BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments);
@@ -238,10 +244,16 @@ public class BindingFactory
arguments = Collections.emptyMap();
}
- // Check access
- if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue))
+ // The default exchange bindings must reflect the existence of queues, allow
+ // all operations on it to succeed. It is up to the broker to prevent illegal
+ // attempts at binding to this exchange, not the ACLs.
+ if(exchange != _defaultExchange)
{
- throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ // Check access
+ if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue))
+ {
+ throw new AMQSecurityException("Permission denied: unbinding " + bindingKey);
+ }
}
BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments));
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
index 3a28b65a08..759907d4bd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
@@ -62,7 +62,10 @@ public class QueueConfiguration extends ConfigurationPlugin
"capacity",
"flowResumeCapacity",
"lvq",
- "lvqKey"
+ "lvqKey",
+ "sortKey",
+ "maximumDeliveryCount",
+ "deadLetterQueues"
};
}
@@ -167,11 +170,30 @@ public class QueueConfiguration extends ConfigurationPlugin
return getStringValue("lvqKey", null);
}
+
public boolean isTopic()
{
return getBooleanValue("topic");
}
+ public String getQueueSortKey()
+ {
+ return getStringValue("sortKey", null);
+ }
+
+ public int getMaxDeliveryCount()
+ {
+ return getIntValue("maximumDeliveryCount", _vHostConfig.getMaxDeliveryCount());
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, deferring to the virtualhost configuration if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getBooleanValue("deadLetterQueues", _vHostConfig.isDeadLetterQueueEnabled());
+ }
+
public static class QueueConfig extends ConfigurationPlugin
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index 0d347873c2..4b42e39aa1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -40,6 +40,8 @@ import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.DefaultExchangeFactory;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.signal.SignalHandlerTask;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -805,4 +807,39 @@ public class ServerConfiguration extends ConfigurationPlugin
final List<String> disabledFeatures = getListValue("disabledFeatures", Collections.emptyList());
return disabledFeatures;
}
+
+ public boolean getManagementRightsInferAllAccess()
+ {
+ return getBooleanValue("management.managementRightsInferAllAccess", true);
+ }
+
+ public int getMaxDeliveryCount()
+ {
+ return getConfig().getInt("maximumDeliveryCount", 0);
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, defaults to disabled if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getConfig().getBoolean("deadLetterQueues", false);
+ }
+
+ /**
+ * String to affix to end of queue name when generating an alternate exchange for DLQ purposes.
+ */
+ public String getDeadLetterExchangeSuffix()
+ {
+ return getConfig().getString("deadLetterExchangeSuffix", DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ }
+
+ /**
+ * String to affix to end of queue name when generating a queue for DLQ purposes.
+ */
+ public String getDeadLetterQueueSuffix()
+ {
+ return getConfig().getString("deadLetterQueueSuffix", AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
index 6729a5ce0f..c4e4f701a8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
@@ -347,4 +347,18 @@ public class VirtualHostConfiguration extends ConfigurationPlugin
{
return getLongValue("transactionTimeout.idleClose", 0L);
}
+
+ public int getMaxDeliveryCount()
+ {
+ return getIntValue("queues.maximumDeliveryCount", ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount());
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, deferring to the broker configuration if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getBooleanValue("queues.deadLetterQueues", ApplicationRegistry.getInstance().getConfiguration().isDeadLetterQueueEnabled());
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
index 0638ea362f..6f8020fc54 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
@@ -87,6 +87,19 @@ public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin
@Override
public void validateConfiguration() throws ConfigurationException
{
+ PluginManager pluginManager;
+ try
+ {
+ pluginManager = ApplicationRegistry.getInstance().getPluginManager();
+ }
+ catch (IllegalStateException ise)
+ {
+ // We see this happen during shutdown due to asynchronous reconfig performed IO threads
+ // running at the same time as the shutdown handler.
+ _policyPlugin = null;
+ return;
+ }
+
if (!containsPositiveLong("messageAge") &&
!containsPositiveLong("depth") &&
!containsPositiveLong("messageCount"))
@@ -96,8 +109,6 @@ public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin
}
SlowConsumerDetectionPolicyConfiguration policyConfig = getConfiguration(SlowConsumerDetectionPolicyConfiguration.class.getName());
-
- PluginManager pluginManager = ApplicationRegistry.getInstance().getPluginManager();
Map<String, SlowConsumerPolicyPluginFactory> factories = pluginManager.getSlowConsumerPlugins();
if (policyConfig == null)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 7837a9bc38..090c0426cf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -40,6 +40,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
public class DefaultExchangeFactory implements ExchangeFactory
{
private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class);
+ public static final String DEFAULT_DLE_NAME_SUFFIX = "_DLE";
private Map<AMQShortString, ExchangeType<? extends Exchange>> _exchangeClassMap = new HashMap<AMQShortString, ExchangeType<? extends Exchange>>();
private final VirtualHost _host;
@@ -122,7 +123,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
if (exchangeType == null)
{
_logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\"");
- return;
+ continue;
}
Class<? extends ExchangeType> exchangeTypeClass = exchangeType.getClass();
ExchangeType<? extends ExchangeType> type = exchangeTypeClass.newInstance();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
index 0e7459498a..8d2dee5aaa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
@@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentMap;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -87,12 +89,22 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException
{
- // Check access
- if (!_host.getSecurityManager().authoriseDelete(_exchangeMap.get(name)))
+ final Exchange exchange = _exchangeMap.get(name);
+ if (exchange == null)
+ {
+ throw new AMQException(AMQConstant.NOT_FOUND, "Unknown exchange " + name, null);
+ }
+
+ if (ExchangeDefaults.DEFAULT_EXCHANGE_NAME.equals(name))
+ {
+ throw new AMQException(AMQConstant.NOT_ALLOWED, "Cannot unregister the default exchange", null);
+ }
+
+ if (!_host.getSecurityManager().authoriseDelete(exchange))
{
throw new AMQSecurityException();
}
-
+
// TODO: check inUse argument
Exchange e = _exchangeMap.remove(name);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
index bd75f7bc51..76f86ea1b4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
@@ -117,7 +117,7 @@ public class FanoutExchange extends AbstractExchange
public boolean isBound(AMQShortString routingKey, AMQQueue queue)
{
- return _queues.contains(queue);
+ return _queues.containsKey(queue);
}
public boolean isBound(AMQShortString routingKey)
@@ -129,7 +129,7 @@ public class FanoutExchange extends AbstractExchange
public boolean isBound(AMQQueue queue)
{
- return _queues.contains(queue);
+ return _queues.containsKey(queue);
}
public boolean hasBindings()
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
index 66c9b5b552..caed8f4b94 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
@@ -20,12 +20,21 @@
*/
package org.apache.qpid.server.exchange;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.server.binding.Binding;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+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.*;
+
+import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
@@ -94,5 +103,48 @@ final class HeadersExchangeMBean extends AbstractExchangeMBean<HeadersExchange>
return bindingList;
}
+ @Override
+ public void createNewBinding(String queueName, String binding) throws JMException
+ {
+ VirtualHost vhost = getExchange().getVirtualHost();
+ AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName));
+ if (queue == null)
+ {
+ throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost.");
+ }
+
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ final String[] bindings = binding.split(",");
+ for (int i = 0; i < bindings.length; i++)
+ {
+ final String[] keyAndValue = bindings[i].split("=");
+ if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2 || keyAndValue[0].length() == 0)
+ {
+ throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" ");
+ }
+
+ if(keyAndValue.length == 1)
+ {
+ //no value was given, only a key. Use an empty value to signal match on key presence alone
+ arguments.put(keyAndValue[0], "");
+ }
+ else
+ {
+ arguments.put(keyAndValue[0], keyAndValue[1]);
+ }
+ }
+ try
+ {
+ vhost.getBindingFactory().addBinding(binding,queue,getExchange(),arguments);
+ }
+ catch (AMQException ex)
+ {
+ JMException jme = new JMException(ex.toString());
+ throw new MBeanException(jme, "Error creating new binding " + binding);
+ }
+ CurrentActor.remove();
+ }
} // End of MBean class
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
index c5f2d1e808..5a5ef5e6c5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
@@ -59,9 +58,8 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager
return _bytesCredit.get() > 0L;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
- final long msgSize = msg.getSize();
if(hasCredit())
{
if(_bytesCredit.addAndGet(-msgSize) >= 0)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
index b47f986155..c6771177ac 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
public class CreditCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
{
@@ -118,7 +117,7 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
return (_bytesCredit != 0L && _messageCredit != 0L);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(long msgSize)
{
if(_messageCredit >= 0L)
{
@@ -130,10 +129,10 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
return true;
}
- else if(msg.getSize() <= _bytesCredit)
+ else if(msgSize <= _bytesCredit)
{
_messageCredit--;
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
@@ -151,9 +150,9 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
}
else if(_bytesCredit >= 0L)
{
- if(msg.getSize() <= _bytesCredit)
+ if(msgSize <= _bytesCredit)
{
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
index bec51d361d..8a80262983 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -41,6 +40,6 @@ public interface FlowCreditManager
public boolean hasCredit();
- public boolean useCreditForMessage(ServerMessage msg);
+ public boolean useCreditForMessage(long msgSize);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
index 901b71fd1f..6fcc687440 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -47,7 +46,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements
return true;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
index 19a9ac1d23..0e6ce70a60 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -62,7 +61,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
return (_messageCredit > 0L) && ( _bytesCredit > 0L );
}
- public synchronized boolean useCreditForMessage(ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCredit == 0L)
{
@@ -71,7 +70,6 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
}
else
{
- final long msgSize = msg.getSize();
if(msgSize > _bytesCredit)
{
setSuspended(true);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
index a386f66b11..9b7c40e923 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
@@ -61,7 +60,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen
return _messageCredit.get() > 0L;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
if(hasCredit())
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
index 026804439c..a193f8fae4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager
{
@@ -133,7 +132,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
&& (_messageCreditLimit == 0L || _messageCredit > 0);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCreditLimit != 0L)
{
@@ -147,10 +146,10 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
}
else
{
- if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ if((_bytesCredit >= msgSize) || (_bytesCredit == _bytesCreditLimit))
{
_messageCredit--;
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
@@ -176,9 +175,9 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
}
else
{
- if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ if((_bytesCredit >= msgSize) || (_bytesCredit == _bytesCreditLimit))
{
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
index 10f578551a..a0c2e9f977 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
@@ -20,10 +20,12 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
+import org.apache.log4j.Logger;
public class WindowCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
{
+ private static final Logger LOGGER = Logger.getLogger(WindowCreditManager.class);
+
private volatile long _bytesCreditLimit;
private volatile long _messageCreditLimit;
@@ -43,6 +45,15 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
+ public long getBytesCreditLimit()
+ {
+ return _bytesCreditLimit;
+ }
+
+ public long getMessageCreditLimit()
+ {
+ return _messageCreditLimit;
+ }
public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit)
{
@@ -70,31 +81,30 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
public synchronized void restoreCredit(final long messageCredit, final long bytesCredit)
{
+ _messageUsed -= messageCredit;
+ if(_messageUsed < 0L)
+ {
+ LOGGER.error("Message credit used value was negative: "+ _messageUsed);
+ _messageUsed = 0;
+ }
+
boolean notifyIncrease = true;
+
if(_messageCreditLimit > 0L)
{
notifyIncrease = (_messageUsed != _messageCreditLimit);
- _messageUsed -= messageCredit;
-
- //TODO log warning
- if(_messageUsed < 0L)
- {
- _messageUsed = 0;
- }
}
-
+ _bytesUsed -= bytesCredit;
+ if(_bytesUsed < 0L)
+ {
+ LOGGER.error("Bytes credit used value was negative: "+ _messageUsed);
+ _bytesUsed = 0;
+ }
if(_bytesCreditLimit > 0L)
{
notifyIncrease = notifyIncrease && bytesCredit>0;
- _bytesUsed -= bytesCredit;
-
- //TODO log warning
- if(_bytesUsed < 0L)
- {
- _bytesUsed = 0;
- }
if(notifyIncrease)
{
@@ -102,10 +112,7 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
}
-
-
setSuspended(!hasCredit());
-
}
@@ -116,7 +123,7 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
&& (_messageCreditLimit < 0L || _messageCreditLimit > _messageUsed);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCreditLimit >= 0L)
{
@@ -128,10 +135,10 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
return true;
}
- else if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ else if(_bytesUsed + msgSize <= _bytesCreditLimit)
{
_messageUsed++;
- _bytesUsed += msg.getSize();
+ _bytesUsed += msgSize;
return true;
}
@@ -149,9 +156,9 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
else if(_bytesCreditLimit >= 0L)
{
- if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ if(_bytesUsed + msgSize <= _bytesCreditLimit)
{
- _bytesUsed += msg.getSize();
+ _bytesUsed += msgSize;
return true;
}
@@ -169,18 +176,6 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
- public void stop()
- {
- if(_bytesCreditLimit > 0)
- {
- _bytesCreditLimit = 0;
- }
- if(_messageCreditLimit > 0)
- {
- _messageCreditLimit = 0;
- }
-
- }
public synchronized void addCredit(long count, long bytes)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
index 14ce85530e..bbb009003c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
@@ -127,16 +127,15 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
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());
+ singleMessageCredit.useCreditForMessage(entry.getMessage().getSize());
if(entry.getMessage() instanceof AMQMessage)
{
session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(),
deliveryTag, queue.getMessageCount());
+ entry.incrementDeliveryCount();
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
index 62dd76f832..0ea88e4ab6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
@@ -59,7 +59,6 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.debug("Rejecting:" + body.getDeliveryTag() +
": Requeue:" + body.getRequeue() +
- //": Resend:" + evt.getMethod().resend +
" on channel:" + channel.debugIdentity());
}
@@ -70,26 +69,23 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
if (message == null)
{
_logger.warn("Dropping reject request as message is null for tag:" + deliveryTag);
-// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known");
}
else
{
if (message.isQueueDeleted())
{
- _logger.warn("Message's Queue as already been purged, unable to Reject. " +
- "Dropping message should use Dead Letter Queue");
+ _logger.warn("Message's Queue has already been purged, dropping message");
message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
if(message != null)
{
message.discard();
}
- //sendtoDeadLetterQueue(msg)
return;
}
if (message.getMessage() == null)
{
- _logger.warn("Message as already been purged, unable to Reject.");
+ _logger.warn("Message has already been purged, unable to Reject.");
return;
}
@@ -98,27 +94,44 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() +
": Requeue:" + body.getRequeue() +
- //": Resend:" + evt.getMethod().resend +
" on channel:" + channel.debugIdentity());
}
- // If we haven't requested message to be resent to this consumer then reject it from ever getting it.
- //if (!evt.getMethod().resend)
- {
- message.reject();
- }
+ message.reject();
if (body.getRequeue())
{
channel.requeue(deliveryTag);
+
+ //this requeue represents a message rejected from the pre-dispatch queue
+ //therefore we need to amend the delivery counter.
+ message.decrementDeliveryCount();
}
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);
+ final boolean maxDeliveryCountEnabled = channel.isMaxDeliveryCountEnabled(deliveryTag);
+ _logger.debug("maxDeliveryCountEnabled: " + maxDeliveryCountEnabled + " deliveryTag " + deliveryTag);
+ if (maxDeliveryCountEnabled)
+ {
+ final boolean deliveredTooManyTimes = channel.isDeliveredTooManyTimes(deliveryTag);
+ _logger.debug("deliveredTooManyTimes: " + deliveredTooManyTimes + " deliveryTag " + deliveryTag);
+ if (deliveredTooManyTimes)
+ {
+ channel.deadLetter(body.getDeliveryTag());
+ }
+ else
+ {
+ //this requeue represents a message rejected because of a recover/rollback that we
+ //are not ready to DLQ. We rely on the reject command to resend from the unacked map
+ //and therefore need to increment the delivery counter so we cancel out the effect
+ //of the AMQChannel#resend() decrement.
+ message.incrementDeliveryCount();
+ }
+ }
+ else
+ {
+ channel.deadLetter(body.getDeliveryTag());
+ }
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index 8391a4b184..f2119f7faa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -25,8 +25,10 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.framing.QueueUnbindBody;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.exchange.Exchange;
@@ -62,7 +64,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
final AMQQueue queue;
- final AMQShortString routingKey;
+ final AMQShortString routingKey;
if (body.getQueue() == null)
{
@@ -114,10 +116,21 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
_log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey);
}
- MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createQueueUnbindOkBody();
+ final MethodRegistry registry = session.getMethodRegistry();
+ final AMQMethodBody responseBody;
+ if (registry instanceof MethodRegistry_0_9)
+ {
+ responseBody = ((MethodRegistry_0_9)registry).createQueueUnbindOkBody();
+ }
+ else if (registry instanceof MethodRegistry_0_91)
+ {
+ responseBody = ((MethodRegistry_0_91)registry).createQueueUnbindOkBody();
+ }
+ else
+ {
+ // 0-8 does not support QueueUnbind
+ throw new AMQException(AMQConstant.COMMAND_INVALID, "QueueUnbind not present in AMQP version: " + session.getProtocolVersion(), null);
+ }
session.writeFrame(responseBody.generateFrame(channelId));
-
-
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
index 4643dee0a3..20ba3af458 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
@@ -72,7 +72,12 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod
};
channel.rollback(task);
-
+
+ //Now resend all the unacknowledged messages back to the original subscribers.
+ //(Must be done after the TxnRollback-ok response).
+ // Why, are we not allowed to send messages back to client before the ok method?
+ channel.resend(false);
+
}
catch (AMQException e)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
index ed8c0d0ce9..b5df212904 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
@@ -32,3 +32,7 @@ FLOW_REMOVED = CHN-1006 : Flow Control Removed
# 0 - time in milliseconds
OPEN_TXN = CHN-1007 : Open Transaction : {0,number} ms
IDLE_TXN = CHN-1008 : Idle Transaction : {0,number} ms
+
+DISCARDMSG_NOALTEXCH = CHN-1009 : Discarded message : {0,number} as no alternate exchange configured for queue : {1} routing key : {2}
+DISCARDMSG_NOROUTE = CHN-1010 : Discarded message : {0,number} as no binding on alternate exchange : {1}
+DEADLETTERMSG = CHN-1011 : Message : {0,number} moved to dead letter queue : {1}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
index c4ffcd26bf..6c9d6e39de 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
@@ -52,8 +52,6 @@ public abstract class AMQManagedObject extends DefaultManagedObject
*/
protected long _notificationSequenceNumber = 0;
- protected MBeanInfo _mbeanInfo;
-
protected LogActor _logActor;
protected AMQManagedObject(Class<?> managementInterface, String typeName)
@@ -63,27 +61,8 @@ public abstract class AMQManagedObject extends DefaultManagedObject
// CurrentActor will be defined as these objects are created during
// broker startup.
_logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger());
- buildMBeanInfo();
- }
-
- @Override
- public MBeanInfo getMBeanInfo()
- {
- return _mbeanInfo;
- }
-
- private void buildMBeanInfo() throws NotCompliantMBeanException
- {
- _mbeanInfo = new MBeanInfo(this.getClass().getName(),
- MBeanIntrospector.getMBeanDescription(this.getClass()),
- MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()),
- MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()),
- MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()),
- this.getNotificationInfo());
}
-
-
// notification broadcaster implementation
public void addNotificationListener(NotificationListener listener,
@@ -99,8 +78,5 @@ public abstract class AMQManagedObject extends DefaultManagedObject
_broadcaster.removeNotificationListener(listener);
}
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- return null;
- }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java
new file mode 100644
index 0000000000..68350a1632
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java
@@ -0,0 +1,71 @@
+package org.apache.qpid.server.management;
+
+import javax.management.Notification;
+
+import javax.management.JMException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.monitor.MonitorNotification;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularType;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+public abstract class AbstractAMQManagedConnectionObject extends AMQManagedObject implements ManagedConnection
+{
+ protected final String _name;
+
+ protected static final OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN };
+ protected static final CompositeType _channelType;
+ protected static final TabularType _channelsType;
+
+ protected static final String BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR =
+ "Broker Management Console has closed the connection.";
+
+ static
+ {
+ try
+ {
+ _channelType = new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]),
+ COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes);
+ _channelsType = new TabularType("Channels", "Channels", _channelType, (String[]) TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()]));
+ }
+ catch (JMException ex)
+ {
+ // This is not expected to ever occur.
+ throw new RuntimeException("Got JMException in static initializer.", ex);
+ }
+ }
+
+ protected AbstractAMQManagedConnectionObject(final String remoteAddress) throws NotCompliantMBeanException
+ {
+ super(ManagedConnection.class, ManagedConnection.TYPE);
+ _name = "anonymous".equals(remoteAddress) ? (remoteAddress + hashCode()) : remoteAddress;
+ }
+
+ @Override
+ public String getObjectInstanceName()
+ {
+ return ObjectName.quote(_name);
+ }
+
+ public void notifyClients(String notificationMsg)
+ {
+ final Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber,
+ System.currentTimeMillis(), notificationMsg);
+ _broadcaster.sendNotification(n);
+ }
+
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
+ String name = MonitorNotification.class.getName();
+ String description = "Channel count has reached threshold value";
+ MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description);
+
+ return new MBeanNotificationInfo[] { info1 };
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
index e44b8c41cb..0c3a5fc571 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
@@ -21,6 +21,8 @@
package org.apache.qpid.server.management;
import javax.management.JMException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
@@ -28,7 +30,6 @@ import javax.management.StandardMBean;
import org.apache.log4j.Logger;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
/**
* Provides implementation of the boilerplate ManagedObject interface. Most managed objects should find it useful
@@ -37,11 +38,13 @@ import org.apache.qpid.server.registry.IApplicationRegistry;
*/
public abstract class DefaultManagedObject extends StandardMBean implements ManagedObject
{
- private static final Logger LOGGER = Logger.getLogger(ApplicationRegistry.class);
+ private static final Logger LOGGER = Logger.getLogger(DefaultManagedObject.class);
- private Class<?> _managementInterface;
+ private final Class<?> _managementInterface;
- private String _typeName;
+ private final String _typeName;
+
+ private final MBeanInfo _mbeanInfo;
private ManagedObjectRegistry _registry;
@@ -51,6 +54,13 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
super(managementInterface);
_managementInterface = managementInterface;
_typeName = typeName;
+ _mbeanInfo = buildMBeanInfo();
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo()
+ {
+ return _mbeanInfo;
}
public String getType()
@@ -98,7 +108,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return getObjectInstanceName() + "[" + getType() + "]";
}
-
/**
* Created the ObjectName as per the JMX Specs
* @return ObjectName
@@ -161,4 +170,18 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return "";
}
+ private MBeanInfo buildMBeanInfo() throws NotCompliantMBeanException
+ {
+ return new MBeanInfo(this.getClass().getName(),
+ MBeanIntrospector.getMBeanDescription(this.getClass()),
+ MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()),
+ MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()),
+ MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()),
+ this.getNotificationInfo());
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ return null;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
index b44964f176..8583e8d57b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
@@ -38,10 +38,13 @@ import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
+import javax.management.Notification;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
@@ -49,11 +52,13 @@ import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.MBeanServerForwarder;
+import javax.management.remote.rmi.RMIConnection;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.management.remote.rmi.RMIJRMPServerImpl;
import javax.management.remote.rmi.RMIServerImpl;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
+import javax.security.auth.Subject;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
@@ -63,6 +68,7 @@ import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
/**
* This class starts up an MBeanserver. If out of the box agent has been enabled then there are no
@@ -223,7 +229,40 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
* The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer
* on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's.
*/
- final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(_jmxPortConnectorServer, csf, ssf, env);
+ final Map<String, String> connectionIdUsernameMap = new ConcurrentHashMap<String, String>();
+ final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(_jmxPortConnectorServer, csf, ssf, env)
+ {
+
+ /**
+ * Override makeClient so we can cache the username of the client in a Map keyed by connectionId.
+ * ConnectionId is guaranteed to be unique per client connection, according to the JMS spec.
+ * An instance of NotificationListener (mapCleanupListener) will be responsible for removing these Map
+ * entries.
+ *
+ * @see javax.management.remote.rmi.RMIJRMPServerImpl#makeClient(java.lang.String, javax.security.auth.Subject)
+ */
+ @Override
+ protected RMIConnection makeClient(String connectionId, Subject subject) throws IOException
+ {
+ final RMIConnection makeClient = super.makeClient(connectionId, subject);
+ final UsernamePrincipal usernamePrincipalFromSubject = UsernamePrincipal.getUsernamePrincipalFromSubject(subject);
+ connectionIdUsernameMap.put(connectionId, usernamePrincipalFromSubject.getName());
+ return makeClient;
+ }
+ };
+
+ // Create a Listener responsible for removing the map entries add by the #makeClient entry above.
+ final NotificationListener mapCleanupListener = new NotificationListener()
+ {
+
+ @Override
+ public void handleNotification(Notification notification, Object handback)
+ {
+ final String connectionId = ((JMXConnectionNotification) notification).getConnectionId();
+ connectionIdUsernameMap.remove(connectionId);
+ }
+ };
+
String localHost;
try
{
@@ -295,13 +334,26 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance();
_cs.setMBeanServerForwarder(mbsf);
- NotificationFilterSupport filter = new NotificationFilterSupport();
- filter.enableType(JMXConnectionNotification.OPENED);
- filter.enableType(JMXConnectionNotification.CLOSED);
- filter.enableType(JMXConnectionNotification.FAILED);
+
// Get the handler that is used by the above MBInvocationHandler Proxy.
- // which is the MBeanInvocationHandlerImpl and so also a NotificationListener
- _cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null);
+ // which is the MBeanInvocationHandlerImpl and so also a NotificationListener.
+ final NotificationListener invocationHandler = (NotificationListener) Proxy.getInvocationHandler(mbsf);
+
+ // Install a notification listener on OPENED, CLOSED, and FAILED,
+ // passing the map of connection-ids to usernames as hand-back data.
+ final NotificationFilterSupport invocationHandlerFilter = new NotificationFilterSupport();
+ invocationHandlerFilter.enableType(JMXConnectionNotification.OPENED);
+ invocationHandlerFilter.enableType(JMXConnectionNotification.CLOSED);
+ invocationHandlerFilter.enableType(JMXConnectionNotification.FAILED);
+ _cs.addNotificationListener(invocationHandler, invocationHandlerFilter, connectionIdUsernameMap);
+
+ // Install a second notification listener on CLOSED AND FAILED only to remove the entry from the
+ // Map. Here we rely on the fact that JMX will call the listeners in the order in which they are
+ // installed.
+ final NotificationFilterSupport mapCleanupHandlerFilter = new NotificationFilterSupport();
+ mapCleanupHandlerFilter.enableType(JMXConnectionNotification.CLOSED);
+ mapCleanupHandlerFilter.enableType(JMXConnectionNotification.FAILED);
+ _cs.addNotificationListener(mapCleanupListener, mapCleanupHandlerFilter, null);
_cs.start();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
index 169195304c..40a221e0ba 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
@@ -26,6 +26,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessControlContext;
import java.security.AccessController;
+import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
@@ -45,6 +46,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.logging.actors.ManagementActor;
import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.access.Operation;
@@ -56,22 +58,54 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
{
private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class);
+ private final IApplicationRegistry _appRegistry = ApplicationRegistry.getInstance();
private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate";
private MBeanServer _mbs;
- private static ManagementActor _logActor;
-
+ private final ManagementActor _logActor = new ManagementActor(_appRegistry.getRootMessageLogger());
+ private final boolean _managementRightsInferAllAccess =
+ _appRegistry.getConfiguration().getManagementRightsInferAllAccess();
+
public static MBeanServerForwarder newProxyInstance()
{
final InvocationHandler handler = new MBeanInvocationHandlerImpl();
final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class };
-
- _logActor = new ManagementActor(ApplicationRegistry.getInstance().getRootMessageLogger());
-
Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler);
return MBeanServerForwarder.class.cast(proxy);
}
+ private boolean invokeDirectly(String methodName, Object[] args, Subject subject)
+ {
+ // Allow operations performed locally on behalf of the connector server itself
+ if (subject == null)
+ {
+ return true;
+ }
+
+ if (args == null || DELEGATE.equals(args[0]))
+ {
+ return true;
+ }
+
+ // Allow querying available object names
+ if (methodName.equals("queryNames"))
+ {
+ return true;
+ }
+
+ if (args[0] instanceof ObjectName)
+ {
+ ObjectName mbean = (ObjectName) args[0];
+
+ if(!DefaultManagedObject.DOMAIN.equalsIgnoreCase(mbean.getDomain()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
final String methodName = getMethodName(method, args);
@@ -95,36 +129,24 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
return null;
}
+ // Restrict access to "createMBean" and "unregisterMBean" to any user
+ if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
+ {
+ _logger.debug("User trying to create or unregister an MBean");
+ throw new SecurityException("Access denied: " + methodName);
+ }
+
// Retrieve Subject from current AccessControlContext
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
try
{
- // Allow operations performed locally on behalf of the connector server itself
- if (subject == null)
+ if(invokeDirectly(methodName, args, subject))
{
return method.invoke(_mbs, args);
}
-
- if (args == null || DELEGATE.equals(args[0]))
- {
- return method.invoke(_mbs, args);
- }
-
- // Restrict access to "createMBean" and "unregisterMBean" to any user
- if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
- {
- _logger.debug("User trying to create or unregister an MBean");
- throw new SecurityException("Access denied: " + methodName);
- }
-
- // Allow querying available object names
- if (methodName.equals("queryNames"))
- {
- return method.invoke(_mbs, args);
- }
-
+
// Retrieve JMXPrincipal from Subject
Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
if (principals == null || principals.isEmpty())
@@ -134,23 +156,23 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
// Save the subject
SecurityManager.setThreadSubject(subject);
-
+
// Get the component, type and impact, which may be null
String type = getType(method, args);
String vhost = getVirtualHost(method, args);
int impact = getImpact(method, args);
-
+
// Get the security manager for the virtual host (if set)
SecurityManager security;
if (vhost == null)
{
- security = ApplicationRegistry.getInstance().getSecurityManager();
+ security = _appRegistry.getSecurityManager();
}
else
{
- security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
+ security = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
}
-
+
if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO)
{
// Check for read-only method invocation permission
@@ -159,25 +181,33 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
throw new SecurityException("Permission denied: Access " + methodName);
}
}
- else if (isUpdateMethod(methodName))
- {
- // Check for setting properties permission
- if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
- {
- throw new SecurityException("Permission denied: Update " + methodName);
- }
- }
- else
- {
- // Check for invoking/executing method action/operation permission
- if (!security.authoriseMethod(Operation.EXECUTE, type, methodName))
- {
- throw new SecurityException("Permission denied: Execute " + methodName);
- }
- }
-
- // Actually invoke the method
- return method.invoke(_mbs, args);
+ else
+ {
+ // Check for setting properties permission
+ if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
+ {
+ throw new SecurityException("Permission denied: Update " + methodName);
+ }
+ }
+
+ boolean oldAccessChecksDisabled = false;
+ if(_managementRightsInferAllAccess)
+ {
+ oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true);
+ }
+
+ try
+ {
+ // Actually invoke the method
+ return method.invoke(_mbs, args);
+ }
+ finally
+ {
+ if(_managementRightsInferAllAccess)
+ {
+ SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled);
+ }
+ }
}
catch (InvocationTargetException e)
{
@@ -290,28 +320,44 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is"));
}
-
- private boolean isUpdateMethod(String methodName)
- {
- //handle standard set methods from MBeanServer
- return methodName.startsWith("set");
- }
-
- public void handleNotification(Notification notification, Object handback)
+ /**
+ * Receives notifications from the MBeanServer.
+ */
+ public void handleNotification(final Notification notification, final Object handback)
{
assert notification instanceof JMXConnectionNotification;
- // only RMI Connections are serviced here, Local API atta
- // rmi://169.24.29.116 guest 3
- String[] connectionData = ((JMXConnectionNotification) notification).getConnectionId().split(" ");
- String user = connectionData[1];
+ final String connectionId = ((JMXConnectionNotification) notification).getConnectionId();
+ final String type = notification.getType();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Notification connectionId : " + connectionId + " type : " + type
+ + " Notification handback : " + handback);
+ }
+
+ // Normally JMXManagedObjectRegistry provides a Map as handback data containing a map
+ // between connection id and username.
+ String user = null;
+ if (handback != null && handback instanceof Map)
+ {
+ final Map<String, String> connectionIdUsernameMap = (Map<String, String>) handback;
+ user = connectionIdUsernameMap.get(connectionId);
+ }
+
+ // If user is still null, fallback to an unordered list of Principals from the connection id.
+ if (user == null)
+ {
+ final String[] splitConnectionId = connectionId.split(" ");
+ user = splitConnectionId[1];
+ }
- if (notification.getType().equals(JMXConnectionNotification.OPENED))
+ if (JMXConnectionNotification.OPENED.equals(type))
{
_logActor.message(ManagementConsoleMessages.OPEN(user));
}
- else if (notification.getType().equals(JMXConnectionNotification.CLOSED) ||
- notification.getType().equals(JMXConnectionNotification.FAILED))
+ else if (JMXConnectionNotification.CLOSED.equals(type) ||
+ JMXConnectionNotification.FAILED.equals(type))
{
_logActor.message(ManagementConsoleMessages.CLOSE(user));
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
index 0e0b18aa2f..4fcbaa237e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.message;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.AMQChannel;
@@ -65,7 +66,6 @@ public class AMQMessage extends AbstractServerMessageImpl
WeakReference<AMQChannel> _channelRef;
-
public AMQMessage(StoredMessage<MessageMetaData> handle)
{
this(handle, null);
@@ -122,7 +122,15 @@ public class AMQMessage extends AbstractServerMessageImpl
public String getRoutingKey()
{
- // TODO
+ MessageMetaData messageMetaData = getMessageMetaData();
+ if (messageMetaData != null)
+ {
+ AMQShortString routingKey = messageMetaData.getMessagePublishInfo().getRoutingKey();
+ if (routingKey != null)
+ {
+ return routingKey.asString();
+ }
+ }
return null;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
index 186bb8601c..80c28332c0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.message;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
index 31cf223428..2f30f260c9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
@@ -79,7 +79,7 @@ class MessageTransferHeader implements AMQMessageHeader
public byte getPriority()
{
- MessageDeliveryPriority priority = _deliveryProps == null
+ MessageDeliveryPriority priority = _deliveryProps == null || !_deliveryProps.hasPriority()
? MessageDeliveryPriority.MEDIUM
: _deliveryProps.getPriority();
return (byte) priority.getValue();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
index aaab4f76cc..badeffca05 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
@@ -75,6 +75,7 @@ org.apache.qpid.server.exchange=0.0.0
org.apache.qpid.server.logging=0.0.0
org.apache.qpid.server.logging.actors=0.0.0
org.apache.qpid.server.logging.subjects=0.0.0
+org.apache.qpid.server.message=0.0.0
org.apache.qpid.server.management=0.0.0
org.apache.qpid.server.persistent=0.0.0
org.apache.qpid.server.plugins=0.0.0
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index b960ce8608..4e5088808a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.server.protocol;
+import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -36,36 +37,17 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
-
import javax.management.JMException;
import javax.security.auth.Subject;
import javax.security.sasl.SaslServer;
-
import org.apache.log4j.Logger;
import org.apache.qpid.AMQChannelException;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.codec.AMQDecoder;
import org.apache.qpid.common.ClientProperties;
-import org.apache.qpid.framing.AMQBody;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQFrame;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.framing.AMQProtocolHeaderException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ChannelCloseBody;
-import org.apache.qpid.framing.ChannelCloseOkBody;
-import org.apache.qpid.framing.ConnectionCloseBody;
-import org.apache.qpid.framing.ContentBody;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.HeartbeatBody;
-import org.apache.qpid.framing.MethodDispatcher;
-import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.framing.ProtocolInitiation;
-import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.*;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQMethodListener;
@@ -87,11 +69,15 @@ import org.apache.qpid.server.management.Managable;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.stats.StatisticsCounter;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
import org.apache.qpid.transport.Sender;
@@ -139,7 +125,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
/* AMQP Version for this session */
private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion();
-
+ private MethodRegistry _methodRegistry = MethodRegistry.getMethodRegistry(_protocolVersion);
private FieldTable _clientProperties;
private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
@@ -173,6 +159,9 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
private NetworkConnection _network;
private Sender<ByteBuffer> _sender;
+ private volatile boolean _deferFlush;
+ private long _lastReceivedTime;
+
public ManagedObject getManagedObject()
{
return _managedObject;
@@ -240,14 +229,29 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
return _closing.get();
}
+ public synchronized void flushBatched()
+ {
+ _sender.flush();
+ }
+
+
+ public ClientDeliveryMethod createDeliveryMethod(int channelId)
+ {
+ return new WriteDeliverMethod(channelId);
+ }
+
public void received(final ByteBuffer msg)
{
- _lastIoTime = System.currentTimeMillis();
+ final long arrivalTime = System.currentTimeMillis();
+ _lastReceivedTime = arrivalTime;
+ _lastIoTime = arrivalTime;
try
{
final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
- for (AMQDataBlock dataBlock : dataBlocks)
+ final int len = dataBlocks.size();
+ for (int i = 0; i < len; i++)
{
+ AMQDataBlock dataBlock = dataBlocks.get(i);
try
{
dataBlockReceived(dataBlock);
@@ -347,7 +351,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
}
}
- private void protocolInitiationReceived(ProtocolInitiation pi)
+ private synchronized void protocolInitiationReceived(ProtocolInitiation pi)
{
// this ensures the codec never checks for a PI message again
(_codecFactory.getDecoder()).setExpectProtocolInitiation(false);
@@ -524,12 +528,15 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
*/
public synchronized void writeFrame(AMQDataBlock frame)
{
- _lastSent = frame;
+
final ByteBuffer buf = asByteBuffer(frame);
- _lastIoTime = System.currentTimeMillis();
_writtenBytes += buf.remaining();
_sender.send(buf);
- _sender.flush();
+ _lastIoTime = System.currentTimeMillis();
+ if(!_deferFlush)
+ {
+ _sender.flush();
+ }
}
public AMQShortString getContextKey()
@@ -918,7 +925,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
private void setProtocolVersion(ProtocolVersion pv)
{
_protocolVersion = pv;
-
+ _methodRegistry = MethodRegistry.getMethodRegistry(_protocolVersion);
_protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this);
_dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion);
}
@@ -1023,7 +1030,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
public MethodRegistry getMethodRegistry()
{
- return MethodRegistry.getMethodRegistry(getProtocolVersion());
+ return _methodRegistry;
}
public MethodDispatcher getMethodDispatcher()
@@ -1052,7 +1059,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
// Nothing
}
- public void writerIdle()
+ public synchronized void writerIdle()
{
_sender.send(asByteBuffer(HeartbeatBody.FRAME));
}
@@ -1109,6 +1116,11 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
return _lastIoTime;
}
+ public long getLastReceivedTime()
+ {
+ return _lastReceivedTime;
+ }
+
public ProtocolSessionIdentifier getSessionIdentifier()
{
return _sessionIdentifier;
@@ -1395,16 +1407,220 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
_statisticsEnabled = enabled;
}
- @Override
public boolean isSessionNameUnique(byte[] name)
{
// 0-8/0-9/0-9-1 sessions don't have names
return true;
}
- @Override
+ public void setDeferFlush(boolean deferFlush)
+ {
+ _deferFlush = deferFlush;
+ }
+
+
+
public String getUserName()
{
return getAuthorizedPrincipal().getName();
}
+
+ private static class ByteBufferOutputStream extends OutputStream
+ {
+
+
+ private final ByteBuffer _buf;
+
+ public ByteBufferOutputStream(ByteBuffer buf)
+ {
+ _buf = buf;
+ }
+
+ @Override
+ public void write(int b) throws IOException
+ {
+ _buf.put((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ _buf.put(b, off, len);
+ }
+ }
+
+ public final class WriteDeliverMethod
+ implements ClientDeliveryMethod
+ {
+ private final int _channelId;
+
+ public WriteDeliverMethod(int channelId)
+ {
+ _channelId = channelId;
+ }
+
+ public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ throws AMQException
+ {
+ registerMessageDelivered(entry.getMessage().getSize());
+ _protocolOutputConverter.writeDeliver(entry, _channelId, deliveryTag, ((SubscriptionImpl)sub).getConsumerTag());
+ entry.incrementDeliveryCount();
+ }
+
+ }
+
+ private static class BytesDataOutput implements DataOutput
+ {
+ int _pos = 0;
+ byte[] _buf;
+
+ public BytesDataOutput(byte[] buf)
+ {
+ _buf = buf;
+ }
+
+ public void setBuffer(byte[] buf)
+ {
+ _buf = buf;
+ _pos = 0;
+ }
+
+ public void reset()
+ {
+ _pos = 0;
+ }
+
+ public int length()
+ {
+ return _pos;
+ }
+
+ public void write(int b)
+ {
+ _buf[_pos++] = (byte) b;
+ }
+
+ public void write(byte[] b)
+ {
+ System.arraycopy(b, 0, _buf, _pos, b.length);
+ _pos+=b.length;
+ }
+
+
+ public void write(byte[] b, int off, int len)
+ {
+ System.arraycopy(b, off, _buf, _pos, len);
+ _pos+=len;
+
+ }
+
+ public void writeBoolean(boolean v)
+ {
+ _buf[_pos++] = v ? (byte) 1 : (byte) 0;
+ }
+
+ public void writeByte(int v)
+ {
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeShort(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeChar(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeInt(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 24);
+ _buf[_pos++] = (byte) (v >>> 16);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeLong(long v)
+ {
+ _buf[_pos++] = (byte) (v >>> 56);
+ _buf[_pos++] = (byte) (v >>> 48);
+ _buf[_pos++] = (byte) (v >>> 40);
+ _buf[_pos++] = (byte) (v >>> 32);
+ _buf[_pos++] = (byte) (v >>> 24);
+ _buf[_pos++] = (byte) (v >>> 16);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte)v;
+ }
+
+ public void writeFloat(float v)
+ {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ public void writeDouble(double v)
+ {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeBytes(String s)
+ {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++)
+ {
+ _buf[_pos++] = ((byte)s.charAt(i));
+ }
+ }
+
+ public void writeChars(String s)
+ {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++)
+ {
+ int v = s.charAt(i);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+ }
+
+ public void writeUTF(String s)
+ {
+ int strlen = s.length();
+
+ int pos = _pos;
+ _pos+=2;
+
+
+ for (int i = 0; i < strlen; i++)
+ {
+ int c = s.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F))
+ {
+ c = s.charAt(i);
+ _buf[_pos++] = (byte) c;
+
+ }
+ else if (c > 0x07FF)
+ {
+ _buf[_pos++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ _buf[_pos++] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ _buf[_pos++] = (byte) (0x80 | (c & 0x3F));
+ }
+ else
+ {
+ _buf[_pos++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ _buf[_pos++] = (byte) (0x80 | (c & 0x3F));
+ }
+ }
+
+ int len = _pos - (pos + 2);
+
+ _buf[pos++] = (byte) (len >>> 8);
+ _buf[pos] = (byte) len;
+ }
+
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
index c1b5b02f8f..dfba10750c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
@@ -32,6 +32,7 @@ import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.security.AuthorizationHolder;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
import org.apache.qpid.server.virtualhost.VirtualHost;
import java.util.List;
@@ -49,6 +50,14 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
boolean isClosing();
+ void flushBatched();
+
+ void setDeferFlush(boolean defer);
+
+ ClientDeliveryMethod createDeliveryMethod(int channelId);
+
+ long getLastReceivedTime();
+
public static final class ProtocolSessionIdentifier
{
private final Object _sessionIdentifier;
@@ -77,15 +86,6 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
}
/**
- * Called when a protocol data block is received
- *
- * @param message the data block that has been received
- *
- * @throws Exception if processing the datablock fails
- */
- void dataBlockReceived(AMQDataBlock message) throws Exception;
-
- /**
* Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC
* 6).
*
@@ -234,4 +234,5 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
List<AMQChannel> getChannels();
void mgmtCloseChannel(int channelId);
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
index 16d99de492..8d39420631 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
@@ -39,89 +39,44 @@ package org.apache.qpid.server.protocol;
import java.util.Date;
import java.util.List;
-
import javax.management.JMException;
import javax.management.MBeanException;
-import javax.management.MBeanNotificationInfo;
import javax.management.NotCompliantMBeanException;
-import javax.management.Notification;
-import javax.management.ObjectName;
-import javax.management.monitor.MonitorNotification;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
-import javax.management.openmbean.TabularType;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ConnectionCloseBody;
import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.management.common.mbeans.ManagedConnection;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.ManagementActor;
-import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject;
import org.apache.qpid.server.management.ManagedObject;
/**
* This MBean class implements the management interface. In order to make more attributes, operations and notifications
* available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here.
*/
-@MBeanDescription("Management Bean for an AMQ Broker Connection")
-public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection
+@MBeanDescription("Management Bean for an AMQ Broker 0-9-1/0-9/0-8 Connections")
+public class AMQProtocolSessionMBean extends AbstractAMQManagedConnectionObject
{
private AMQProtocolSession _protocolSession = null;
- private String _name = null;
- // openmbean data types for representing the channel attributes
-
- private static final OpenType[] _channelAttributeTypes =
- { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN };
- private static CompositeType _channelType = null; // represents the data type for channel data
- private static TabularType _channelsType = null; // Data type for list of channels type
private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION =
- new AMQShortString("Broker Management Console has closed the connection.");
+ new AMQShortString(BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR);
- @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection")
+ @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-9-1/0-9/0-8 Connection")
public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException
{
- super(ManagedConnection.class, ManagedConnection.TYPE);
+ super(amqProtocolSession.getRemoteAddress().toString());
_protocolSession = amqProtocolSession;
- String remote = getRemoteAddress();
- _name = "anonymous".equals(remote) ? (remote + hashCode()) : remote;
- init();
- }
-
- static
- {
- try
- {
- init();
- }
- catch (JMException ex)
- {
- // This is not expected to ever occur.
- throw new RuntimeException("Got JMException in static initializer.", ex);
- }
- }
-
- /**
- * initialises the openmbean data types
- */
- private static void init() throws OpenDataException
- {
- _channelType =
- new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]),
- COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes);
- _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()]));
}
public String getClientId()
@@ -169,16 +124,6 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
return _protocolSession.getMaximumNumberOfChannels();
}
- public void setMaximumNumberOfChannels(Long value)
- {
- _protocolSession.setMaximumNumberOfChannels(value);
- }
-
- public String getObjectInstanceName()
- {
- return ObjectName.quote(_name);
- }
-
/**
* commits transactions for a transactional channel
*
@@ -321,25 +266,6 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
}
}
- @Override
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
- String name = MonitorNotification.class.getName();
- String description = "Channel count has reached threshold value";
- MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description);
-
- return new MBeanNotificationInfo[] { info1 };
- }
-
- public void notifyClients(String notificationMsg)
- {
- Notification n =
- new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber,
- System.currentTimeMillis(), notificationMsg);
- _broadcaster.sendNotification(n);
- }
-
public void resetStatistics() throws Exception
{
_protocolSession.resetStatistics();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
index 48a8a1bf42..5d4b8c603b 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
@@ -100,6 +100,12 @@ public class ProtocolEngine_0_10 extends InputHandler implements ServerProtocol
return _network.getLocalAddress();
}
+ public void received(final ByteBuffer buf)
+ {
+ super.received(buf);
+ _connection.receivedComplete();
+ }
+
public long getReadBytes()
{
return _readBytes;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
index a9ddf9bb0c..dd4bd2bb1c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
@@ -20,6 +20,14 @@
*/
package org.apache.qpid.server.protocol.v1_0;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInternalException;
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQSecurityException;
@@ -27,16 +35,28 @@ import org.apache.qpid.amqp_1_0.transport.DeliveryStateHandler;
import org.apache.qpid.amqp_1_0.transport.LinkEndpoint;
import org.apache.qpid.amqp_1_0.transport.SendingLinkEndpoint;
import org.apache.qpid.amqp_1_0.transport.SendingLinkListener;
-import org.apache.qpid.amqp_1_0.type.*;
-
-import org.apache.qpid.amqp_1_0.type.messaging.*;
+import org.apache.qpid.amqp_1_0.type.AmqpErrorException;
+import org.apache.qpid.amqp_1_0.type.Binary;
+import org.apache.qpid.amqp_1_0.type.DeliveryState;
+import org.apache.qpid.amqp_1_0.type.Outcome;
+import org.apache.qpid.amqp_1_0.type.Symbol;
+import org.apache.qpid.amqp_1_0.type.UnsignedInteger;
+import org.apache.qpid.amqp_1_0.type.messaging.Accepted;
+import org.apache.qpid.amqp_1_0.type.messaging.ExactSubjectFilter;
+import org.apache.qpid.amqp_1_0.type.messaging.Filter;
+import org.apache.qpid.amqp_1_0.type.messaging.JMSSelectorFilter;
+import org.apache.qpid.amqp_1_0.type.messaging.MatchingSubjectFilter;
+import org.apache.qpid.amqp_1_0.type.messaging.NoLocalFilter;
+import org.apache.qpid.amqp_1_0.type.messaging.Released;
import org.apache.qpid.amqp_1_0.type.messaging.Source;
-import org.apache.qpid.amqp_1_0.type.transport.*;
-import org.apache.qpid.AMQException;
+import org.apache.qpid.amqp_1_0.type.messaging.StdDistMode;
+import org.apache.qpid.amqp_1_0.type.messaging.TerminusDurability;
+import org.apache.qpid.amqp_1_0.type.transport.AmqpError;
+import org.apache.qpid.amqp_1_0.type.transport.Detach;
import org.apache.qpid.amqp_1_0.type.transport.Error;
+import org.apache.qpid.amqp_1_0.type.transport.Transfer;
import org.apache.qpid.server.exchange.DirectExchange;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.exchange.ExchangeType;
import org.apache.qpid.server.exchange.TopicExchange;
import org.apache.qpid.server.filter.JMSSelectorMessageFilter;
import org.apache.qpid.server.filter.SimpleFilterManager;
@@ -47,9 +67,6 @@ import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryStateHandler
{
private VirtualHost _vhost;
@@ -140,7 +157,7 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS
try
{
queue = AMQQueueFactory.createAMQQueueImpl(UUID.randomUUID().toString(), false, null, true,
- false, _vhost, Collections.EMPTY_MAP);
+ false, _vhost, Collections.EMPTY_MAP);
Exchange exchange = ((ExchangeDestination) destination).getExchange();
String binding = "";
@@ -183,6 +200,9 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS
catch (AMQInternalException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (AMQException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
index 4b189652d3..e08e7f3e39 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
@@ -365,6 +365,9 @@ public class Session_1_0 implements SessionEventListener
catch (AMQSecurityException e)
{
e.printStackTrace(); //TODO.
+ } catch (AMQException e)
+ {
+ e.printStackTrace(); //TODO
}
return queue;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
index fc64527f3b..5dea91b6d4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
@@ -20,6 +20,13 @@
*/
package org.apache.qpid.server.protocol.v1_0;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.qpid.AMQException;
import org.apache.qpid.amqp_1_0.transport.SendingLinkEndpoint;
import org.apache.qpid.amqp_1_0.type.Binary;
import org.apache.qpid.amqp_1_0.type.DeliveryState;
@@ -31,24 +38,14 @@ import org.apache.qpid.amqp_1_0.type.messaging.StdDistMode;
import org.apache.qpid.amqp_1_0.type.transaction.TransactionalState;
import org.apache.qpid.amqp_1_0.type.transport.SenderSettleMode;
import org.apache.qpid.amqp_1_0.type.transport.Transfer;
-
-import org.apache.qpid.AMQException;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.txn.ServerTransaction;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.ReentrantLock;
-
class Subscription_1_0 implements Subscription
{
private SendingLink_1_0 _link;
@@ -171,6 +168,17 @@ class Subscription_1_0 implements Subscription
getEndpoint().detach();
}
+ public void send(QueueEntry entry, boolean batch) throws AMQException
+ {
+ // TODO
+ send(entry);
+ }
+
+ public void flushBatched()
+ {
+ // TODO
+ }
+
public void send(final QueueEntry queueEntry) throws AMQException
{
//TODO
@@ -296,6 +304,11 @@ class Subscription_1_0 implements Subscription
return !hasCredit;
}
+ public boolean trySendLock()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void suspend()
{
if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
@@ -314,6 +327,11 @@ class Subscription_1_0 implements Subscription
_stateChangeLock.unlock();
}
+ public void releaseQueueEntry(QueueEntry queueEntryImpl)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void onDequeue(final QueueEntry queueEntry)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
index 371ae0de50..2c04a626ff 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
@@ -20,71 +20,25 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.subscription.SubscriptionList;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
import java.util.Map;
+import org.apache.qpid.server.virtualhost.VirtualHost;
-public class AMQPriorityQueue extends SimpleAMQQueue
+public class AMQPriorityQueue extends OutOfOrderQueue
{
- protected AMQPriorityQueue(final AMQShortString name,
- final boolean durable,
- final AMQShortString owner,
- final boolean autoDelete,
- boolean exclusive,
- final VirtualHost virtualHost,
- int priorities, Map<String, Object> arguments)
- {
- super(name, durable, owner, autoDelete, exclusive, virtualHost,new PriorityQueueList.Factory(priorities), arguments);
- }
-
- public AMQPriorityQueue(String queueName,
- boolean durable,
- String owner,
- boolean autoDelete,
- boolean exclusive, VirtualHost virtualHost, int priorities, Map<String,Object> arguments)
+ protected AMQPriorityQueue(final String name,
+ final boolean durable,
+ final String owner,
+ final boolean autoDelete,
+ boolean exclusive,
+ final VirtualHost virtualHost,
+ Map<String, Object> arguments,
+ int priorities)
{
- this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),
- autoDelete, exclusive,virtualHost, priorities, arguments);
+ super(name, durable, owner, autoDelete, exclusive, virtualHost, new PriorityQueueList.Factory(priorities), arguments);
}
public int getPriorities()
{
return ((PriorityQueueList) _entries).getPriorities();
}
-
- @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.isAvailable())
- {
- final Subscription subscription = subIter.getNode().getSubscription();
- if(!subscription.isClosed())
- {
- QueueContext context = (QueueContext) subscription.getQueueContext();
- if(context != null)
- {
- QueueEntry subnode = context._lastSeenEntry;
- QueueEntry released = context._releasedEntry;
- while(subnode != null && entry.compareTo(subnode) < 0 && entry.isAvailable() && (released == null || released.compareTo(entry) < 0))
- {
- if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
- {
- break;
- }
- else
- {
- subnode = context._lastSeenEntry;
- released = context._releasedEntry;
- }
- }
- }
- }
-
- }
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 9140a13625..6dfdc5e8b4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -213,6 +213,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
void setAlternateExchange(Exchange exchange);
+ void setAlternateExchange(String exchangeName);
+
Map<String, Object> getArguments();
void checkCapacity(AMQChannel channel);
@@ -272,4 +274,22 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
ManagedObject getManagedObject();
void setExclusive(boolean exclusive) throws AMQException;
+
+ /**
+ * Gets the maximum delivery count. If a message on this queue
+ * is delivered more than maximumDeliveryCount, the message will be
+ * routed to the {@link #getAlternateExchange()} (if set), or otherwise
+ * discarded. 0 indicates that maximum deliver count should not be enforced.
+ *
+ * @return maximum delivery count
+ */
+ int getMaximumDeliveryCount();
+
+ /**
+ * Sets the maximum delivery count.
+ *
+ * @param maximumDeliveryCount maximum delivery count
+ */
+ public void setMaximumDeliveryCount(final int maximumDeliveryCount);
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
index 5fbad74978..14ca147982 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -20,22 +20,33 @@
*/
package org.apache.qpid.server.queue;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.configuration.QueueConfiguration;
-
-import java.util.Map;
-import java.util.HashMap;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
public class AMQQueueFactory
{
- public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
+ public static final String X_QPID_PRIORITIES = "x-qpid-priorities";
public static final String QPID_LVQ_KEY = "qpid.LVQ_key";
public static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue";
public static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key";
+ public static final String QPID_QUEUE_SORT_KEY = "qpid.queue_sort_key";
+
+ public static final String DLQ_ROUTING_KEY = "dlq";
+ public static final String X_QPID_DLQ_ENABLED = "x-qpid-dlq-enabled";
+ public static final String X_QPID_MAXIMUM_DELIVERY_COUNT = "x-qpid-maximum-delivery-count";
+ public static final String DEFAULT_DLQ_NAME_SUFFIX = "_DLQ";
private abstract static class QueueProperty
{
@@ -80,6 +91,24 @@ public class AMQQueueFactory
}
+ private abstract static class QueueIntegerProperty extends QueueProperty
+ {
+ public QueueIntegerProperty(String argumentName)
+ {
+ super(argumentName);
+ }
+
+ public void setPropertyValue(AMQQueue queue, Object value)
+ {
+ if(value instanceof Number)
+ {
+ setPropertyValue(queue, ((Number)value).intValue());
+ }
+
+ }
+ abstract void setPropertyValue(AMQQueue queue, int value);
+ }
+
private static final QueueProperty[] DECLAREABLE_PROPERTIES = {
new QueueLongProperty("x-qpid-maximum-message-age")
{
@@ -122,8 +151,14 @@ public class AMQQueueFactory
{
queue.setFlowResumeCapacity(value);
}
+ },
+ new QueueIntegerProperty(X_QPID_MAXIMUM_DELIVERY_COUNT)
+ {
+ public void setPropertyValue(AMQQueue queue, int value)
+ {
+ queue.setMaximumDeliveryCount(value);
+ }
}
-
};
@@ -149,17 +184,31 @@ public class AMQQueueFactory
String owner,
boolean autoDelete,
boolean exclusive,
- VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException
+ VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException, AMQException
{
+ if (queueName == null)
+ {
+ throw new IllegalArgumentException("Queue name must not be null");
+ }
+
// Access check
if (!virtualHost.getSecurityManager().authoriseCreateQueue(autoDelete, durable, exclusive, null, null, new AMQShortString(queueName), owner))
{
String description = "Permission denied: queue-name '" + queueName + "'";
throw new AMQSecurityException(description);
}
-
+
+ QueueConfiguration queueConfiguration = virtualHost.getConfiguration().getQueueConfiguration(queueName);
+ boolean isDLQEnabled = isDLQEnabled(autoDelete, arguments, queueConfiguration);
+ if (isDLQEnabled)
+ {
+ validateDLNames(queueName);
+ }
+
int priorities = 1;
String conflationKey = null;
+ String sortingKey = null;
+
if(arguments != null)
{
if(arguments.containsKey(QPID_LAST_VALUE_QUEUE) || arguments.containsKey(QPID_LAST_VALUE_QUEUE_KEY))
@@ -170,24 +219,32 @@ public class AMQQueueFactory
conflationKey = QPID_LVQ_KEY;
}
}
- else if(arguments.containsKey(X_QPID_PRIORITIES.toString()))
+ else if(arguments.containsKey(X_QPID_PRIORITIES))
{
- Object prioritiesObj = arguments.get(X_QPID_PRIORITIES.toString());
+ Object prioritiesObj = arguments.get(X_QPID_PRIORITIES);
if(prioritiesObj instanceof Number)
{
priorities = ((Number)prioritiesObj).intValue();
}
}
+ else if(arguments.containsKey(QPID_QUEUE_SORT_KEY))
+ {
+ sortingKey = (String)arguments.get(QPID_QUEUE_SORT_KEY);
+ }
}
AMQQueue q;
- if(conflationKey != null)
+ if(sortingKey != null)
+ {
+ q = new SortedQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, sortingKey);
+ }
+ else if(conflationKey != null)
{
q = new ConflationQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, conflationKey);
}
else if(priorities > 1)
{
- q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, priorities, arguments);
+ q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, priorities);
}
else
{
@@ -209,10 +266,63 @@ public class AMQQueueFactory
}
}
- return q;
+ if(isDLQEnabled)
+ {
+ final String dlExchangeName = getDeadLetterExchangeName(queueName);
+ final String dlQueueName = getDeadLetterQueueName(queueName);
- }
+ final ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+ final ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
+ final QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
+
+ Exchange dlExchange = null;
+ synchronized(exchangeRegistry)
+ {
+ dlExchange = exchangeRegistry.getExchange(dlExchangeName);
+
+ if(dlExchange == null)
+ {
+ dlExchange = exchangeFactory.createExchange(new AMQShortString(dlExchangeName), ExchangeDefaults.FANOUT_EXCHANGE_CLASS, true, false, 0);
+
+ exchangeRegistry.registerExchange(dlExchange);
+
+ //enter the dle in the persistent store
+ virtualHost.getDurableConfigurationStore().createExchange(dlExchange);
+ }
+ }
+
+ AMQQueue dlQueue = null;
+
+ synchronized(queueRegistry)
+ {
+ dlQueue = queueRegistry.getQueue(dlQueueName);
+
+ if(dlQueue == null)
+ {
+ //set args to disable DLQ'ing/MDC from the DLQ itself, preventing loops etc
+ final Map<String, Object> args = new HashMap<String, Object>();
+ args.put(X_QPID_DLQ_ENABLED, false);
+ args.put(X_QPID_MAXIMUM_DELIVERY_COUNT, 0);
+
+ dlQueue = createAMQQueueImpl(dlQueueName, true, owner, false, exclusive, virtualHost, args);
+ //enter the dlq in the persistent store
+ virtualHost.getDurableConfigurationStore().createQueue(dlQueue, FieldTable.convertToFieldTable(args));
+ }
+ }
+
+ //ensure the queue is bound to the exchange
+ if(!dlExchange.isBound(DLQ_ROUTING_KEY, dlQueue))
+ {
+ //actual routing key used does not matter due to use of fanout exchange,
+ //but we will make the key 'dlq' as it can be logged at creation.
+ virtualHost.getBindingFactory().addBinding(DLQ_ROUTING_KEY, dlQueue, dlExchange, null);
+ }
+ q.setAlternateExchange(dlExchange);
+ }
+
+ return q;
+ }
public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException
{
@@ -223,26 +333,30 @@ public class AMQQueueFactory
boolean exclusive = config.getExclusive();
String owner = config.getOwner();
Map<String,Object> arguments = null;
+
if(config.isLVQ() || config.getLVQKey() != null)
{
-
arguments = new HashMap<String,Object>();
arguments.put(QPID_LAST_VALUE_QUEUE, 1);
arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey());
}
- else
+ else if (config.getPriority() || config.getPriorities() > 0)
+ {
+ arguments = new HashMap<String,Object>();
+ arguments.put(X_QPID_PRIORITIES, config.getPriorities() < 0 ? 10 : config.getPriorities());
+ }
+ else if (config.getQueueSortKey() != null && !"".equals(config.getQueueSortKey()))
+ {
+ arguments = new HashMap<String,Object>();
+ arguments.put(QPID_QUEUE_SORT_KEY, config.getQueueSortKey());
+ }
+ if (!config.getAutoDelete() && config.isDeadLetterQueueEnabled())
{
- boolean priority = config.getPriority();
- int priorities = config.getPriorities();
- if(priority || priorities > 0)
+ if (arguments == null)
{
arguments = new HashMap<String,Object>();
- if (priorities < 0)
- {
- priorities = 10;
- }
- arguments.put("x-qpid-priorities", priorities);
}
+ arguments.put(X_QPID_DLQ_ENABLED, true);
}
if(config.isTopic())
@@ -259,4 +373,94 @@ public class AMQQueueFactory
return q;
}
+
+ /**
+ * Validates DLQ and DLE names
+ * <p>
+ * DLQ name and DLQ exchange name need to be validated in order to keep
+ * integrity in cases when queue name passes validation check but DLQ name
+ * or DL exchange name fails to pass it. Otherwise, we might have situations
+ * when queue is created but DL exchange or/and DLQ creation fail.
+ * <p>
+ *
+ * @param name
+ * queue name
+ * @throws IllegalArgumentException
+ * thrown if length of queue name or exchange name exceed 255
+ */
+ protected static void validateDLNames(String name)
+ {
+ // check if DLQ name and DLQ exchange name do not exceed 255
+ String exchangeName = getDeadLetterExchangeName(name);
+ if (exchangeName.length() > AMQShortString.MAX_LENGTH)
+ {
+ throw new IllegalArgumentException("DL exchange name '" + exchangeName
+ + "' length exceeds limit of " + AMQShortString.MAX_LENGTH + " characters for queue " + name);
+ }
+ String queueName = getDeadLetterQueueName(name);
+ if (queueName.length() > AMQShortString.MAX_LENGTH)
+ {
+ throw new IllegalArgumentException("DLQ queue name '" + queueName + "' length exceeds limit of "
+ + AMQShortString.MAX_LENGTH + " characters for queue " + name);
+ }
+ }
+
+ /**
+ * Checks if DLQ is enabled for the queue.
+ *
+ * @param autoDelete
+ * queue auto-delete flag
+ * @param arguments
+ * queue arguments
+ * @param qConfig
+ * queue configuration
+ * @return true if DLQ enabled
+ */
+ protected static boolean isDLQEnabled(boolean autoDelete, Map<String, Object> arguments, QueueConfiguration qConfig)
+ {
+ //feature is not to be enabled for temporary queues or when explicitly disabled by argument
+ if (!autoDelete)
+ {
+ boolean dlqArgumentPresent = arguments != null && arguments.containsKey(X_QPID_DLQ_ENABLED);
+ if (dlqArgumentPresent || qConfig.isDeadLetterQueueEnabled())
+ {
+ boolean dlqEnabled = true;
+ if (dlqArgumentPresent)
+ {
+ Object argument = arguments.get(X_QPID_DLQ_ENABLED);
+ dlqEnabled = argument instanceof Boolean && ((Boolean)argument).booleanValue();
+ }
+ return dlqEnabled;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generates a dead letter queue name for a given queue name
+ *
+ * @param name
+ * queue name
+ * @return DLQ name
+ */
+ protected static String getDeadLetterQueueName(String name)
+ {
+ ServerConfiguration serverConfig = ApplicationRegistry.getInstance().getConfiguration();
+ String dlQueueName = name + serverConfig.getDeadLetterQueueSuffix();
+ return dlQueueName;
+ }
+
+ /**
+ * Generates a dead letter exchange name for a given queue name
+ *
+ * @param name
+ * queue name
+ * @return DL exchange name
+ */
+ protected static String getDeadLetterExchangeName(String name)
+ {
+ ServerConfiguration serverConfig = ApplicationRegistry.getInstance().getConfiguration();
+ String dlExchangeName = name + serverConfig.getDeadLetterExchangeSuffix();
+ return dlExchangeName;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index c8eb118b11..b4765d6227 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -28,7 +28,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
-import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.message.ServerMessage;
@@ -63,23 +63,25 @@ import java.util.*;
/**
* AMQQueueMBean is the management bean for an {@link AMQQueue}.
*
- * <p/><tablse id="crc"><caption>CRC Caption</caption>
+ * <p/><table id="crc"><caption>CRC Caption</caption>
* <tr><th> Responsibilities <th> Collaborations
* </table>
*/
@MBeanDescription("Management Interface for AMQQueue")
public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener
{
+
/** Used for debugging purposes. */
private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class);
- private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z");
+ /** Date/time format used for message expiration and message timestamp formatting */
+ public static final String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z";
- private AMQQueue _queue = null;
- private String _queueName = null;
+ private final AMQQueue _queue;
+ private final String _queueName;
// OpenMBean data types for viewMessages method
- private static OpenType[] _msgAttributeTypes = new OpenType[5]; // AMQ message attribute types.
+ private static OpenType[] _msgAttributeTypes = new OpenType[6]; // AMQ message attribute types.
private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data.
private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list.
@@ -138,6 +140,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
_msgAttributeTypes[2] = SimpleType.LONG; // For size
_msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered
_msgAttributeTypes[4] = SimpleType.LONG; // For queue position
+ _msgAttributeTypes[5] = SimpleType.INTEGER; // For delivery count
_messageDataType = new CompositeType("Message", "AMQ Message",
VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]),
@@ -176,6 +179,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
return _queue.getMessageCount();
}
+ public Integer getMaximumDeliveryCount()
+ {
+ return _queue.getMaximumDeliveryCount();
+ }
+
public Long getMaximumMessageSize()
{
return _queue.getMaximumMessageSize();
@@ -294,6 +302,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
}
}
+ public void setAlternateExchange(String exchangeName)
+ {
+ _queue.setAlternateExchange(exchangeName);
+ }
+
+ public String getAlternateExchange()
+ {
+ Exchange exchange = _queue.getAlternateExchange();
+ String name = exchange == null ? null : exchange.getName();
+ return name == null ? null : name;
+ }
+
/**
* Checks if there is any notification to be send to the listeners
*/
@@ -471,7 +491,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
ContentHeaderBody headerBody = msg.getContentHeaderBody();
// Create header attributes list
headerAttributes = getMessageHeaderProperties(headerBody);
- itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
else if(serverMsg instanceof MessageTransferMessage)
{
@@ -480,13 +500,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
// Create header attributes list
headerAttributes = getMessageTransferMessageHeaderProps(msg);
- itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
else
{
//unknown message
headerAttributes = new String[]{"N/A"};
- itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
CompositeData messageData = new CompositeDataSupport(_messageDataType,
@@ -523,13 +543,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
list.add("JMSPriority = " + headerProperties.getPriority());
list.add("JMSType = " + headerProperties.getType());
- long longDate = headerProperties.getExpiration();
- String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSExpiration = " + strDate);
+ final long expirationDate = headerProperties.getExpiration();
+ final long timestampDate = headerProperties.getTimestamp();
- longDate = headerProperties.getTimestamp();
- strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSTimestamp = " + strDate);
+ addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate,
+ timestampDate);
return list.toArray(new String[list.size()]);
}
@@ -561,17 +579,32 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
list.add("JMSPriority = " + header.getPriority());
list.add("JMSType = " + header.getType());
- long longDate = header.getExpiration();
- String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSExpiration = " + strDate);
-
- longDate = header.getTimestamp();
- strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSTimestamp = " + strDate);
+ final long expirationDate = header.getExpiration();
+ final long timestampDate = header.getTimestamp();
+ addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate, timestampDate);
return list.toArray(new String[list.size()]);
}
+ private void addStringifiedJMSTimestamoAndJMSExpiration(final List<String> list,
+ final long expirationDate, final long timestampDate)
+ {
+ final SimpleDateFormat dateFormat;
+ if (expirationDate != 0 || timestampDate != 0)
+ {
+ dateFormat = new SimpleDateFormat(JMSTIMESTAMP_DATETIME_FORMAT);
+ }
+ else
+ {
+ dateFormat = null;
+ }
+
+ final String formattedExpirationDate = (expirationDate != 0) ? dateFormat.format(new Date(expirationDate)) : null;
+ final String formattedTimestampDate = (timestampDate != 0) ? dateFormat.format(new Date(timestampDate)) : null;
+ list.add("JMSExpiration = " + formattedExpirationDate);
+ list.add("JMSTimestamp = " + formattedTimestampDate);
+ }
+
/**
* @see ManagedQueue#moveMessages
* @param fromMessageId
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
index 2c1883e763..c4762c98c9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
@@ -54,7 +54,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
@Override
- public QueueEntry add(final ServerMessage message)
+ public ConflationQueueEntry add(final ServerMessage message)
{
ConflationQueueEntry entry = (ConflationQueueEntry) (super.add(message));
AtomicReference<QueueEntry> latestValueReference = null;
@@ -117,7 +117,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
}
}
- private final class ConflationQueueEntry extends QueueEntryImpl
+ private final class ConflationQueueEntry extends SimpleQueueEntryImpl
{
@@ -158,7 +158,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
_conflationKey = conflationKey;
}
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public ConflationQueueList createQueueEntryList(AMQQueue queue)
{
return new ConflationQueueList(queue, _conflationKey);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
index 77da08d8c4..26112d9f53 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
@@ -24,7 +24,7 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.AMQMessageHeader;
-class InboundMessageAdapter implements InboundMessage
+public class InboundMessageAdapter implements InboundMessage
{
private QueueEntry _entry;
@@ -33,7 +33,7 @@ class InboundMessageAdapter implements InboundMessage
{
}
- InboundMessageAdapter(QueueEntry entry)
+ public InboundMessageAdapter(QueueEntry entry)
{
_entry = entry;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
new file mode 100644
index 0000000000..b16d1eb8e3
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
@@ -0,0 +1,53 @@
+package org.apache.qpid.server.queue;
+
+import java.util.Map;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionList;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public abstract class OutOfOrderQueue extends SimpleAMQQueue
+{
+ protected OutOfOrderQueue(String name, boolean durable, String owner,
+ boolean autoDelete, boolean exclusive, VirtualHost virtualHost,
+ QueueEntryListFactory entryListFactory, Map<String, Object> arguments)
+ {
+ super(name, durable, owner, autoDelete, exclusive, virtualHost, entryListFactory, arguments);
+ }
+
+ @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();
+ if(!subscription.isClosed())
+ {
+ QueueContext context = (QueueContext) subscription.getQueueContext();
+ if(context != null)
+ {
+ QueueEntry subnode = context._lastSeenEntry;
+ QueueEntry released = context._releasedEntry;
+
+ while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()
+ && (released == null || released.compareTo(entry) > 0))
+ {
+ if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
+ {
+ break;
+ }
+ else
+ {
+ subnode = context._lastSeenEntry;
+ released = context._releasedEntry;
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
index 0c6b84d2b6..79d3ab5bd0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
@@ -20,21 +20,19 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.framing.CommonContentHeaderProperties;
-import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.ServerMessage;
-public class PriorityQueueList implements QueueEntryList
+public class PriorityQueueList implements QueueEntryList<SimpleQueueEntryImpl>
{
private final AMQQueue _queue;
- private final QueueEntryList[] _priorityLists;
+ private final SimpleQueueEntryList[] _priorityLists;
private final int _priorities;
private final int _priorityOffset;
public PriorityQueueList(AMQQueue queue, int priorities)
{
_queue = queue;
- _priorityLists = new QueueEntryList[priorities];
+ _priorityLists = new SimpleQueueEntryList[priorities];
_priorities = priorities;
_priorityOffset = 5-((priorities + 1)/2);
for(int i = 0; i < priorities; i++)
@@ -53,7 +51,7 @@ public class PriorityQueueList implements QueueEntryList
return _queue;
}
- public QueueEntry add(ServerMessage message)
+ public SimpleQueueEntryImpl add(ServerMessage message)
{
int index = message.getMessageHeader().getPriority() - _priorityOffset;
if(index >= _priorities)
@@ -68,31 +66,30 @@ public class PriorityQueueList implements QueueEntryList
}
- public QueueEntry next(QueueEntry node)
+ public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node)
{
- QueueEntryImpl nodeImpl = (QueueEntryImpl)node;
- QueueEntry next = nodeImpl.getNext();
+ SimpleQueueEntryImpl next = node.getNextValidEntry();
if(next == null)
{
- QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList();
+ final QueueEntryList<?> nodeEntryList = node.getQueueEntryList();
int index;
for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--);
while(next == null && index != 0)
{
index--;
- next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext();
+ next = _priorityLists[index].getHead().getNextValidEntry();
}
}
return next;
}
- private final class PriorityQueueEntryListIterator implements QueueEntryIterator
+ private final class PriorityQueueEntryListIterator implements QueueEntryIterator<SimpleQueueEntryImpl>
{
- private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ];
- private QueueEntry _lastNode;
+ private final SimpleQueueEntryList.QueueEntryIteratorImpl[] _iterators = new SimpleQueueEntryList.QueueEntryIteratorImpl[ _priorityLists.length ];
+ private SimpleQueueEntryImpl _lastNode;
PriorityQueueEntryListIterator()
{
@@ -116,7 +113,7 @@ public class PriorityQueueList implements QueueEntryList
return true;
}
- public QueueEntry getNode()
+ public SimpleQueueEntryImpl getNode()
{
return _lastNode;
}
@@ -135,16 +132,21 @@ public class PriorityQueueList implements QueueEntryList
}
}
- public QueueEntryIterator iterator()
+ public PriorityQueueEntryListIterator iterator()
{
return new PriorityQueueEntryListIterator();
}
- public QueueEntry getHead()
+ public SimpleQueueEntryImpl getHead()
{
return _priorityLists[_priorities-1].getHead();
}
+ public void entryDeleted(final SimpleQueueEntryImpl queueEntry)
+ {
+
+ }
+
static class Factory implements QueueEntryListFactory
{
private final int _priorities;
@@ -154,7 +156,7 @@ public class PriorityQueueList implements QueueEntryList
_priorities = priorities;
}
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public PriorityQueueList createQueueEntryList(AMQQueue queue)
{
return new PriorityQueueList(queue, _priorities);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index be29245901..37fad54c07 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -1,5 +1,7 @@
package org.apache.qpid.server.queue;
+import java.util.Collection;
+
import org.apache.qpid.AMQException;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.message.ServerMessage;
@@ -214,6 +216,10 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable
boolean isQueueDeleted();
+ QueueEntry getNextNode();
+
+ QueueEntry getNextValidEntry();
+
void addStateChangeListener(StateChangeListener listener);
boolean removeStateChangeListener(StateChangeListener listener);
@@ -230,4 +236,16 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable
* @return true if entry is either DEQUED or DELETED state
*/
boolean isDispensed();
+
+ /**
+ * Number of times this queue entry has been delivered.
+ *
+ * @return delivery count
+ */
+ int getDeliveryCount();
+
+ void incrementDeliveryCount();
+
+ void decrementDeliveryCount();
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index 5b57e40a82..f1e50427b1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -20,8 +20,14 @@
*/
package org.apache.qpid.server.queue;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.apache.log4j.Logger;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.message.AMQMessageHeader;
@@ -31,23 +37,11 @@ import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.atomic.AtomicLongFieldUpdater;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-
-
-public class QueueEntryImpl implements QueueEntry
+public abstract class QueueEntryImpl implements QueueEntry
{
-
- /**
- * Used for debugging purposes.
- */
private static final Logger _log = Logger.getLogger(QueueEntryImpl.class);
- private final SimpleQueueEntryList _queueEntryList;
+ private final QueueEntryList _queueEntryList;
private MessageReference _message;
@@ -80,22 +74,26 @@ public class QueueEntryImpl implements QueueEntry
private volatile long _entryId;
- volatile QueueEntryImpl _next;
-
private static final int DELIVERED_TO_CONSUMER = 1;
private static final int REDELIVERED = 2;
private volatile int _deliveryState;
+ /** Number of times this message has been delivered */
+ private volatile int _deliveryCount = 0;
+ private static final AtomicIntegerFieldUpdater<QueueEntryImpl> _deliveryCountUpdater = AtomicIntegerFieldUpdater
+ .newUpdater(QueueEntryImpl.class, "_deliveryCount");
+
- QueueEntryImpl(SimpleQueueEntryList queueEntryList)
+
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList)
{
this(queueEntryList,null,Long.MIN_VALUE);
_state = DELETED_STATE;
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId)
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList, ServerMessage message, final long entryId)
{
_queueEntryList = queueEntryList;
@@ -104,7 +102,7 @@ public class QueueEntryImpl implements QueueEntry
_entryIdUpdater.set(this, entryId);
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message)
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList, ServerMessage message)
{
_queueEntryList = queueEntryList;
_message = message == null ? null : message.newReference();
@@ -233,8 +231,13 @@ public class QueueEntryImpl implements QueueEntry
if(state instanceof SubscriptionAcquiredState)
{
getQueue().decrementUnackedMsgCount();
+ Subscription subscription = ((SubscriptionAcquiredState)state).getSubscription();
+ if (subscription != null)
+ {
+ subscription.releaseQueueEntry(this);
+ }
}
-
+
if(!getQueue().isDeleted())
{
getQueue().requeue(this);
@@ -311,16 +314,15 @@ public class QueueEntryImpl implements QueueEntry
public Subscription getDeliveredSubscription()
{
- EntryState state = _state;
- if (state instanceof SubscriptionAcquiredState)
- {
- return ((SubscriptionAcquiredState) state).getSubscription();
- }
- else
- {
- return null;
- }
-
+ EntryState state = _state;
+ if (state instanceof SubscriptionAcquiredState)
+ {
+ return ((SubscriptionAcquiredState) state).getSubscription();
+ }
+ else
+ {
+ return null;
+ }
}
public void reject()
@@ -409,50 +411,51 @@ public class QueueEntryImpl implements QueueEntry
public void routeToAlternate()
{
final AMQQueue currentQueue = getQueue();
- Exchange alternateExchange = currentQueue.getAlternateExchange();
+ Exchange alternateExchange = currentQueue.getAlternateExchange();
- if(alternateExchange != null)
+ if (alternateExchange != null)
+ {
+ final List<? extends BaseQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this));
+ final ServerMessage message = getMessage();
+ if (rerouteQueues != null && rerouteQueues.size() != 0)
{
- final List<? extends BaseQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this));
- final ServerMessage message = getMessage();
- if(rerouteQueues != null && rerouteQueues.size() != 0)
- {
- ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
- txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() {
- public void postCommit()
+ ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
+
+ txn.enqueue(rerouteQueues, message, new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ try
{
- try
+ for (BaseQueue queue : rerouteQueues)
{
- for(BaseQueue queue : rerouteQueues)
- {
- queue.enqueue(message);
- }
- }
- catch (AMQException e)
- {
- throw new RuntimeException(e);
+ queue.enqueue(message);
}
}
-
- public void onRollback()
+ catch (AMQException e)
{
-
+ throw new RuntimeException(e);
}
- });
- txn.dequeue(currentQueue,message,
- new ServerTransaction.Action()
- {
- public void postCommit()
- {
- discard();
- }
-
- public void onRollback()
- {
-
- }
- });
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ txn.dequeue(currentQueue, message, new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ discard();
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
}
}
}
@@ -492,33 +495,6 @@ public class QueueEntryImpl implements QueueEntry
return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0;
}
- public QueueEntryImpl getNext()
- {
-
- QueueEntryImpl next = nextNode();
- while(next != null && next.isDispensed() )
- {
-
- 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;
@@ -530,7 +506,7 @@ public class QueueEntryImpl implements QueueEntry
if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE))
{
- _queueEntryList.advanceHead();
+ _queueEntryList.entryDeleted(this);
return true;
}
else
@@ -554,4 +530,19 @@ public class QueueEntryImpl implements QueueEntry
return _state.isDispensed();
}
+ public int getDeliveryCount()
+ {
+ return _deliveryCount;
+ }
+
+ public void incrementDeliveryCount()
+ {
+ _deliveryCountUpdater.incrementAndGet(this);
+ }
+
+ public void decrementDeliveryCount()
+ {
+ _deliveryCountUpdater.decrementAndGet(this);
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
index c5c115a2d1..73ebb0f300 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
@@ -20,11 +20,11 @@
*/
package org.apache.qpid.server.queue;
-public interface QueueEntryIterator
+public interface QueueEntryIterator<QE extends QueueEntry>
{
boolean atTail();
- QueueEntry getNode();
+ QE getNode();
boolean advance();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
index b4042ce02c..77c4b912e0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -22,15 +22,17 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.server.message.ServerMessage;
-public interface QueueEntryList
+public interface QueueEntryList<Q extends QueueEntry>
{
AMQQueue getQueue();
- QueueEntry add(ServerMessage message);
+ Q add(ServerMessage message);
- QueueEntry next(QueueEntry node);
+ Q next(Q node);
- QueueEntryIterator iterator();
+ QueueEntryIterator<Q> iterator();
- QueueEntry getHead();
+ Q getHead();
+
+ void entryDeleted(Q queueEntry);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
index 7e1d57e205..5270f9f740 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
@@ -27,6 +27,11 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.queue.QueueRunner;
import org.apache.qpid.server.queue.SimpleAMQQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
/**
* QueueRunners are Runnables used to process a queue when requiring
* asynchronous message delivery to subscriptions, which is necessary
@@ -37,33 +42,64 @@ public class QueueRunner implements ReadWriteRunnable
{
private static final Logger _logger = Logger.getLogger(QueueRunner.class);
- private final String _name;
private final SimpleAMQQueue _queue;
- public QueueRunner(SimpleAMQQueue queue, long count)
+ private static int IDLE = 0;
+ private static int SCHEDULED = 1;
+ private static int RUNNING = 2;
+
+
+ private final AtomicInteger _scheduled = new AtomicInteger(IDLE);
+
+ private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ private final AtomicBoolean _stateChange = new AtomicBoolean();
+
+ private final AtomicLong _lastRunAgain = new AtomicLong();
+ private final AtomicLong _lastRunTime = new AtomicLong();
+
+ private long _runs;
+ private long _continues;
+
+ public QueueRunner(SimpleAMQQueue queue)
{
_queue = queue;
- _name = "QueueRunner-" + count + "-" + queue.getLogActor();
}
+ private int trouble = 0;
+
public void run()
{
- String originalName = Thread.currentThread().getName();
- try
+ if(_scheduled.compareAndSet(SCHEDULED,RUNNING))
{
- Thread.currentThread().setName(_name);
- CurrentActor.set(_queue.getLogActor());
+ long runAgain = Long.MIN_VALUE;
+ _stateChange.set(false);
+ try
+ {
+ CurrentActor.set(_queue.getLogActor());
+
+ runAgain = _queue.processQueue(this);
+ }
+ catch (AMQException e)
+ {
+ _logger.error("Exception during asynchronous delivery by " + toString(), e);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ _scheduled.compareAndSet(RUNNING, IDLE);
+ long stateChangeCount = _queue.getStateChangeCount();
+ _lastRunAgain.set(runAgain);
+ _lastRunTime.set(System.nanoTime());
+ if(runAgain == 0L || runAgain != stateChangeCount || _stateChange.compareAndSet(true,false))
+ {
+ _continues++;
+ if(_scheduled.compareAndSet(IDLE, SCHEDULED))
+ {
+ _queue.execute(this);
+ }
+ }
- _queue.processQueue(this);
- }
- catch (AMQException e)
- {
- _logger.error("Exception during asynchronous delivery by " + _name, e);
- }
- finally
- {
- CurrentActor.remove();
- Thread.currentThread().setName(originalName);
}
}
@@ -79,6 +115,21 @@ public class QueueRunner implements ReadWriteRunnable
public String toString()
{
- return _name;
+ return "QueueRunner-" + _queue.getLogActor();
}
-} \ No newline at end of file
+
+ public void execute(Executor executor)
+ {
+ _stateChange.set(true);
+ if(_scheduled.compareAndSet(IDLE, SCHEDULED))
+ {
+ executor.execute(this);
+ }
+ }
+
+ public boolean isIdle()
+ {
+ return _scheduled.get() == IDLE;
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index 7effb1c0f8..08dab4e5fc 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -155,11 +155,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class);
- static final int MAX_ASYNC_DELIVERIES = 10;
+ static final int MAX_ASYNC_DELIVERIES = 80;
private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE);
- private AtomicReference<Runnable> _asynchronousRunner = new AtomicReference<Runnable>(null);
+
private final Executor _asyncDelivery;
private AtomicInteger _deliveredMessages = new AtomicInteger();
private AtomicBoolean _stopped = new AtomicBoolean(false);
@@ -188,6 +188,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private ConfigurationPlugin _queueConfiguration;
private final boolean _isTopic;
+ /** the maximum delivery count for each message on this queue or 0 if maximum delivery count is not to be enforced. */
+ private int _maximumDeliveryCount = ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount();
protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map<String,Object> arguments)
{
@@ -358,6 +360,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_alternateExchange = exchange;
}
+ public void setAlternateExchange(String exchangeName)
+ {
+ if(exchangeName == null || exchangeName.equals(""))
+ {
+ _alternateExchange = null;
+ return;
+ }
+
+ Exchange exchange = getVirtualHost().getExchangeRegistry().getExchange(new AMQShortString(exchangeName));
+ if (exchange == null)
+ {
+ throw new RuntimeException("Exchange '" + exchangeName + "' is not registered with the VirtualHost.");
+ }
+ setAlternateExchange(exchange);
+ }
+
public Map<String, Object> getArguments()
{
return _arguments;
@@ -528,13 +546,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//Reconfigure the queue for to reflect this new binding.
ConfigurationPlugin config = getVirtualHost().getConfiguration().getQueueConfiguration(this);
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Reconfiguring queue(" + this + ") with config:" + config + " was "+ _queueConfiguration);
- }
-
if (config != null)
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Reconfiguring queue(" + this + ") with config:" + config + " was "+ _queueConfiguration);
+ }
// Reconfigure with new config.
configure(config);
}
@@ -575,40 +592,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
{
+ incrementTxnEnqueueStats(message);
+ incrementQueueCount();
+ incrementQueueSize(message);
+
_totalMessagesReceived.incrementAndGet();
- Subscription exclusiveSub = _exclusiveSubscriber;
+ final Subscription exclusiveSub = _exclusiveSubscriber;
if(!_isTopic || _subscriptionList.size()!=0)
{
- incrementTxnEnqueueStats(message);
- incrementQueueCount();
- incrementQueueSize(message);
-
- QueueEntry entry;
+ QueueEntry entry = _entries.add(message);
- if (exclusiveSub != null)
+ if(action != null || (exclusiveSub == null && _queueRunner.isIdle()))
{
- exclusiveSub.getSendLock();
-
- try
- {
- entry = _entries.add(message);
-
- 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 = _subscriptionList.getMarkedNode();
SubscriptionList.SubscriptionNode nextNode = node.findNext();
@@ -654,12 +653,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+
if (entry.isAvailable())
{
checkSubscriptionsNotAheadOfDelivery(entry);
- deliverAsync();
+ if (exclusiveSub != null)
+ {
+ deliverAsync(exclusiveSub);
+ }
+ else
+ {
+ deliverAsync();
+ }
}
if(_managedObject != null)
@@ -678,30 +685,32 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throws AMQException
{
- sub.getSendLock();
- try
+ if(sub.trySendLock())
{
- if (subscriptionReadyAndHasInterest(sub, entry)
- && !sub.isSuspended())
+ try
{
- if (!sub.wouldSuspend(entry))
+ if (subscriptionReadyAndHasInterest(sub, entry)
+ && !sub.isSuspended())
{
- if (sub.acquires() && !entry.acquire(sub))
+ if (!sub.wouldSuspend(entry))
{
- // restore credit here that would have been taken away by wouldSuspend since we didn't manage
- // to acquire the entry for this subscription
- sub.onDequeue(entry);
- }
- else
- {
- deliverMessage(sub, entry);
+ if (sub.acquires() && !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, false);
+ }
}
}
}
- }
- finally
- {
- sub.releaseSendLock();
+ finally
+ {
+ sub.releaseSendLock();
+ }
}
}
@@ -745,7 +754,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_byteTxnDequeues.addAndGet(entry.getSize());
}
- private void deliverMessage(final Subscription sub, final QueueEntry entry)
+ private void deliverMessage(final Subscription sub, final QueueEntry entry, boolean batch)
throws AMQException
{
setLastSeenEntry(sub, entry);
@@ -753,7 +762,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_deliveredMessages.incrementAndGet();
incrementUnackedMsgCount();
- sub.send(entry);
+ sub.send(entry, batch);
if(_isTopic)
{
@@ -893,7 +902,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
if (!subscription.isClosed())
{
- deliverMessage(subscription, entry);
+ deliverMessage(subscription, entry, false);
return true;
}
else
@@ -1035,6 +1044,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_exclusiveSubscriber = exclusiveSubscriber;
}
+ long getStateChangeCount()
+ {
+ return _stateChangeCount.get();
+ }
+
+
public static interface QueueEntryFilter
{
public boolean accept(QueueEntry entry);
@@ -1335,7 +1350,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
QueueEntryIterator queueListIterator = _entries.iterator();
long count = 0;
- ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore());
while (queueListIterator.advance())
{
@@ -1358,7 +1373,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private void dequeueEntry(final QueueEntry node)
{
- ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getMessageStore());
dequeueEntry(node, txn);
}
@@ -1435,7 +1450,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
});
- ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore());
if(_alternateExchange != null)
{
@@ -1604,26 +1619,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+ private QueueRunner _queueRunner = new QueueRunner(this);
public void deliverAsync()
{
- QueueRunner runner = new QueueRunner(this, _stateChangeCount.incrementAndGet());
+ _stateChangeCount.incrementAndGet();
+
+ _queueRunner.execute(_asyncDelivery);
- if (_asynchronousRunner.compareAndSet(null, runner))
- {
- _asyncDelivery.execute(runner);
- }
}
public void deliverAsync(Subscription sub)
{
- SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER);
- if(flusher == null)
+ //_stateChangeCount.incrementAndGet();
+ if(_exclusiveSubscriber == null)
{
- flusher = new SubFlushRunner(sub);
- sub.set(SUB_FLUSH_RUNNER, flusher);
+ deliverAsync();
}
- _asyncDelivery.execute(flusher);
+ else
+ {
+ SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER);
+ if(flusher == null)
+ {
+ flusher = new SubFlushRunner(sub);
+ sub.set(SUB_FLUSH_RUNNER, flusher);
+ }
+ flusher.execute(_asyncDelivery);
+ }
+
}
public void flushSubscription(Subscription sub) throws AMQException
@@ -1639,25 +1662,49 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public boolean flushSubscription(Subscription sub, long iterations) throws AMQException
{
boolean atTail = false;
+ final boolean keepSendLockHeld = iterations <= SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ boolean queueEmpty = false;
- while (!sub.isSuspended() && !atTail && iterations != 0)
+ try
{
- boolean queueEmpty = false;
- try
+
+ if(keepSendLockHeld)
{
sub.getSendLock();
- atTail = attemptDelivery(sub);
- if (atTail && getNextAvailableEntry(sub) == null)
+ }
+
+ while (!sub.isSuspended() && !atTail && iterations != 0)
+ {
+ try
{
- queueEmpty = true;
+ if(!keepSendLockHeld)
+ {
+ sub.getSendLock();
+ }
+
+ atTail = attemptDelivery(sub, true);
+ if (atTail && getNextAvailableEntry(sub) == null)
+ {
+ queueEmpty = true;
+ }
+ else if (!atTail)
+ {
+ iterations--;
+ }
}
- else if (!atTail)
+ finally
{
- iterations--;
+ if(!keepSendLockHeld)
+ {
+ sub.releaseSendLock();
+ }
}
}
- finally
+ }
+ finally
+ {
+ if(keepSendLockHeld)
{
sub.releaseSendLock();
}
@@ -1665,8 +1712,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
sub.queueEmpty();
}
+ sub.flushBatched();
+
}
+
// 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".
@@ -1684,11 +1734,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
*
* Looks up the next node for the subscription and attempts to deliver it.
*
+ *
* @param sub
+ * @param batch
* @return true if we have completed all possible deliveries for this sub.
* @throws AMQException
*/
- private boolean attemptDelivery(Subscription sub) throws AMQException
+ private boolean attemptDelivery(Subscription sub, boolean batch) throws AMQException
{
boolean atTail = false;
@@ -1706,11 +1758,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
if (sub.acquires() && !node.acquire(sub))
{
- sub.onDequeue(node);
+ // 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(node);
}
else
{
- deliverMessage(sub, node);
+ deliverMessage(sub, node, batch);
}
}
@@ -1814,23 +1868,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
* @param runner the Runner to schedule
* @throws AMQException
*/
- public void processQueue(QueueRunner runner) throws AMQException
+ public long processQueue(QueueRunner runner) throws AMQException
{
- long stateChangeCount;
+ long stateChangeCount = Long.MIN_VALUE;
long previousStateChangeCount = Long.MIN_VALUE;
+ long rVal = Long.MIN_VALUE;
boolean deliveryIncomplete = true;
boolean lastLoop = false;
int iterations = MAX_ASYNC_DELIVERIES;
- _asynchronousRunner.compareAndSet(runner, null);
+ final int numSubs = _subscriptionList.size();
+
+ final int perSub = Math.max(iterations / Math.max(numSubs,1), 1);
// For every message enqueue/requeue the we fire deliveryAsync() which
// increases _stateChangeCount. If _sCC changes whilst we are in our loop
// (detected by setting previousStateChangeCount to stateChangeCount in the loop body)
// then we will continue to run for a maximum of iterations.
// So whilst delivery/rejection is going on a processQueue thread will be running
- while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner))
+ while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete))
{
// 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
@@ -1841,6 +1898,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//further asynchronous delivery is required since the
//previous loop. keep going if iteration slicing allows.
lastLoop = false;
+ rVal = stateChangeCount;
}
previousStateChangeCount = stateChangeCount;
@@ -1853,30 +1911,43 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
Subscription sub = subscriptionIter.getNode().getSubscription();
sub.getSendLock();
- try
- {
- //attempt delivery. returns true if no further delivery currently possible to this sub
- subscriptionDone = attemptDelivery(sub);
- if (subscriptionDone)
+
+ try
{
- if(lastLoop)
+ for(int i = 0 ; i < perSub; i++)
{
- sub.queueEmpty();
+ //attempt delivery. returns true if no further delivery currently possible to this sub
+ subscriptionDone = attemptDelivery(sub, true);
+ if (subscriptionDone)
+ {
+ sub.flushBatched();
+ //close autoClose subscriptions if we are not currently intent on continuing
+ if (lastLoop && !sub.isSuspended() )
+ {
+ sub.queueEmpty();
+ }
+ break;
+ }
+ else
+ {
+ //this subscription can accept additional deliveries, so we must
+ //keep going after this (if iteration slicing allows it)
+ allSubscriptionsDone = false;
+ lastLoop = false;
+ if(--iterations == 0)
+ {
+ sub.flushBatched();
+ break;
+ }
+ }
}
+
+ sub.flushBatched();
}
- else
+ finally
{
- //this subscription can accept additional deliveries, so we must
- //keep going after this (if iteration slicing allows it)
- allSubscriptionsDone = false;
- lastLoop = false;
- iterations--;
+ sub.releaseSendLock();
}
- }
- finally
- {
- sub.releaseSendLock();
- }
}
if(allSubscriptionsDone && lastLoop)
@@ -1902,24 +1973,24 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
deliveryIncomplete = true;
}
- _asynchronousRunner.set(null);
}
// If iterations == 0 then the limiting 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 (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner))
+ if (iterations == 0)
{
if (_logger.isDebugEnabled())
{
_logger.debug("Rescheduling runner:" + runner);
}
- _asyncDelivery.execute(runner);
+ return 0L;
}
+ return rVal;
+
}
public void checkMessageStatus() throws AMQException
{
-
QueueEntryIterator queueListIterator = _entries.iterator();
while (queueListIterator.advance())
@@ -2150,6 +2221,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
setMaximumMessageSize(((QueueConfiguration)config).getMaximumMessageSize());
setMaximumMessageCount(((QueueConfiguration)config).getMaximumMessageCount());
setMinimumAlertRepeatGap(((QueueConfiguration)config).getMinimumAlertRepeatGap());
+ setMaximumDeliveryCount(((QueueConfiguration)config).getMaxDeliveryCount());
_capacity = ((QueueConfiguration)config).getCapacity();
_flowResumeCapacity = ((QueueConfiguration)config).getFlowResumeCapacity();
}
@@ -2271,4 +2343,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
return _logActor;
}
+
+ public int getMaximumDeliveryCount()
+ {
+ return _maximumDeliveryCount;
+ }
+
+ public void setMaximumDeliveryCount(final int maximumDeliveryCount)
+ {
+ _maximumDeliveryCount = maximumDeliveryCount;
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java
new file mode 100644
index 0000000000..0707dc045c
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SimpleQueueEntryImpl extends QueueEntryImpl
+{
+ volatile SimpleQueueEntryImpl _next;
+
+ public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList)
+ {
+ super(queueEntryList);
+ }
+
+ public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId)
+ {
+ super(queueEntryList, message, entryId);
+ }
+
+ public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message)
+ {
+ super(queueEntryList, message);
+ }
+
+ public SimpleQueueEntryImpl getNextNode()
+ {
+ return _next;
+ }
+
+ public SimpleQueueEntryImpl getNextValidEntry()
+ {
+
+ SimpleQueueEntryImpl next = getNextNode();
+ while(next != null && next.isDispensed())
+ {
+
+ final SimpleQueueEntryImpl newNext = next.getNextNode();
+ if(newNext != null)
+ {
+ SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext);
+ next = getNextNode();
+ }
+ else
+ {
+ next = null;
+ }
+
+ }
+ return next;
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
index 46baab8c85..0bb5dcc219 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
@@ -1,10 +1,3 @@
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.server.message.ServerMessage;
-
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import java.util.concurrent.atomic.AtomicLong;
-
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -25,25 +18,31 @@ import java.util.concurrent.atomic.AtomicLong;
* under the License.
*
*/
-public class SimpleQueueEntryList implements QueueEntryList
+package org.apache.qpid.server.queue;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SimpleQueueEntryList implements QueueEntryList<SimpleQueueEntryImpl>
{
- private final QueueEntryImpl _head;
+ private final SimpleQueueEntryImpl _head;
- private volatile QueueEntryImpl _tail;
+ private volatile SimpleQueueEntryImpl _tail;
- static final AtomicReferenceFieldUpdater<SimpleQueueEntryList, QueueEntryImpl>
+ static final AtomicReferenceFieldUpdater<SimpleQueueEntryList, SimpleQueueEntryImpl>
_tailUpdater =
AtomicReferenceFieldUpdater.newUpdater
- (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail");
+ (SimpleQueueEntryList.class, SimpleQueueEntryImpl.class, "_tail");
private final AMQQueue _queue;
- static final AtomicReferenceFieldUpdater<QueueEntryImpl, QueueEntryImpl>
+ static final AtomicReferenceFieldUpdater<SimpleQueueEntryImpl, SimpleQueueEntryImpl>
_nextUpdater =
AtomicReferenceFieldUpdater.newUpdater
- (QueueEntryImpl.class, QueueEntryImpl.class, "_next");
+ (SimpleQueueEntryImpl.class, SimpleQueueEntryImpl.class, "_next");
private AtomicLong _scavenges = new AtomicLong(0L);
private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50);
@@ -52,14 +51,14 @@ public class SimpleQueueEntryList implements QueueEntryList
public SimpleQueueEntryList(AMQQueue queue)
{
_queue = queue;
- _head = new QueueEntryImpl(this);
+ _head = new SimpleQueueEntryImpl(this);
_tail = _head;
}
void advanceHead()
{
- QueueEntryImpl next = _head.nextNode();
- QueueEntryImpl newNext = _head.getNext();
+ SimpleQueueEntryImpl next = _head.getNextNode();
+ SimpleQueueEntryImpl newNext = _head.getNextValidEntry();
if (next == newNext)
{
@@ -73,11 +72,11 @@ public class SimpleQueueEntryList implements QueueEntryList
void scavenge()
{
- QueueEntryImpl next = _head.getNext();
+ SimpleQueueEntryImpl next = _head.getNextValidEntry();
while (next != null)
{
- next = next.getNext();
+ next = next.getNextValidEntry();
}
}
@@ -88,13 +87,13 @@ public class SimpleQueueEntryList implements QueueEntryList
}
- public QueueEntry add(ServerMessage message)
+ public SimpleQueueEntryImpl add(ServerMessage message)
{
- QueueEntryImpl node = createQueueEntry(message);
+ SimpleQueueEntryImpl node = createQueueEntry(message);
for (;;)
{
- QueueEntryImpl tail = _tail;
- QueueEntryImpl next = tail.nextNode();
+ SimpleQueueEntryImpl tail = _tail;
+ SimpleQueueEntryImpl next = tail.getNextNode();
if (tail == _tail)
{
if (next == null)
@@ -115,23 +114,22 @@ public class SimpleQueueEntryList implements QueueEntryList
}
}
- protected QueueEntryImpl createQueueEntry(ServerMessage message)
+ protected SimpleQueueEntryImpl createQueueEntry(ServerMessage message)
{
- return new QueueEntryImpl(this, message);
+ return new SimpleQueueEntryImpl(this, message);
}
- public QueueEntry next(QueueEntry node)
+ public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node)
{
- return ((QueueEntryImpl)node).getNext();
+ return node.getNextValidEntry();
}
-
- public static class QueueEntryIteratorImpl implements QueueEntryIterator
+ public static class QueueEntryIteratorImpl implements QueueEntryIterator<SimpleQueueEntryImpl>
{
- private QueueEntryImpl _lastNode;
+ private SimpleQueueEntryImpl _lastNode;
- QueueEntryIteratorImpl(QueueEntryImpl startNode)
+ QueueEntryIteratorImpl(SimpleQueueEntryImpl startNode)
{
_lastNode = startNode;
}
@@ -139,14 +137,12 @@ public class SimpleQueueEntryList implements QueueEntryList
public boolean atTail()
{
- return _lastNode.nextNode() == null;
+ return _lastNode.getNextNode() == null;
}
- public QueueEntry getNode()
+ public SimpleQueueEntryImpl getNode()
{
-
return _lastNode;
-
}
public boolean advance()
@@ -154,10 +150,10 @@ public class SimpleQueueEntryList implements QueueEntryList
if(!atTail())
{
- QueueEntryImpl nextNode = _lastNode.nextNode();
- while(nextNode.isDispensed() && nextNode.nextNode() != null)
+ SimpleQueueEntryImpl nextNode = _lastNode.getNextNode();
+ while(nextNode.isDispensed() && nextNode.getNextNode() != null)
{
- nextNode = nextNode.nextNode();
+ nextNode = nextNode.getNextNode();
}
_lastNode = nextNode;
return true;
@@ -173,21 +169,26 @@ public class SimpleQueueEntryList implements QueueEntryList
}
- public QueueEntryIterator iterator()
+ public QueueEntryIteratorImpl iterator()
{
return new QueueEntryIteratorImpl(_head);
}
- public QueueEntry getHead()
+ public SimpleQueueEntryImpl getHead()
{
return _head;
}
+ public void entryDeleted(SimpleQueueEntryImpl queueEntry)
+ {
+ advanceHead();
+ }
+
static class Factory implements QueueEntryListFactory
{
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public SimpleQueueEntryList createQueueEntryList(AMQQueue queue)
{
return new SimpleQueueEntryList(queue);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java
new file mode 100644
index 0000000000..3f02442704
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java
@@ -0,0 +1,30 @@
+package org.apache.qpid.server.queue;
+
+import java.util.Map;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class SortedQueue extends OutOfOrderQueue
+{
+ private String _sortedPropertyName;
+
+ protected SortedQueue(final String name, final boolean durable,
+ final String owner, final boolean autoDelete, final boolean exclusive,
+ final VirtualHost virtualHost, Map<String, Object> arguments, String sortedPropertyName)
+ {
+ super(name, durable, owner, autoDelete, exclusive, virtualHost,
+ new SortedQueueEntryListFactory(sortedPropertyName), arguments);
+ this._sortedPropertyName = sortedPropertyName;
+ }
+
+ public String getSortedPropertyName()
+ {
+ return _sortedPropertyName;
+ }
+
+ public synchronized void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
+ {
+ super.enqueue(message, action);
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java
new file mode 100644
index 0000000000..1052adbe67
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.message.ServerMessage;
+
+/**
+ * An implementation of QueueEntryImpl to be used in SortedQueueEntryList.
+ */
+public class SortedQueueEntryImpl extends QueueEntryImpl
+{
+ public static enum Colour
+ {
+ RED, BLACK
+ };
+
+ private volatile SortedQueueEntryImpl _next;
+ private SortedQueueEntryImpl _prev;
+ private String _key;
+
+ private Colour _colour = Colour.BLACK;
+ private SortedQueueEntryImpl _parent;
+ private SortedQueueEntryImpl _left;
+ private SortedQueueEntryImpl _right;
+
+ public SortedQueueEntryImpl(final SortedQueueEntryList queueEntryList)
+ {
+ super(queueEntryList);
+ }
+
+ public SortedQueueEntryImpl(final SortedQueueEntryList queueEntryList,
+ final ServerMessage message, final long entryId)
+ {
+ super(queueEntryList, message, entryId);
+ }
+
+ @Override
+ public int compareTo(final QueueEntry o)
+ {
+ final String otherKey = ((SortedQueueEntryImpl) o)._key;
+ final int compare = _key == null ? (otherKey == null ? 0 : -1) : otherKey == null ? 1 : _key.compareTo(otherKey);
+ return compare == 0 ? super.compareTo(o) : compare;
+ }
+
+ public Colour getColour()
+ {
+ return _colour;
+ }
+
+ public String getKey()
+ {
+ return _key;
+ }
+
+ public SortedQueueEntryImpl getLeft()
+ {
+ return _left;
+ }
+
+ public SortedQueueEntryImpl getNextNode()
+ {
+ return _next;
+ }
+
+ @Override
+ public SortedQueueEntryImpl getNextValidEntry()
+ {
+ return getNextNode();
+ }
+
+ public SortedQueueEntryImpl getParent()
+ {
+ return _parent;
+ }
+
+ public SortedQueueEntryImpl getPrev()
+ {
+ return _prev;
+ }
+
+ public SortedQueueEntryImpl getRight()
+ {
+ return _right;
+ }
+
+ public void setColour(final Colour colour)
+ {
+ _colour = colour;
+ }
+
+ public void setKey(final String key)
+ {
+ _key = key;
+ }
+
+ public void setLeft(final SortedQueueEntryImpl left)
+ {
+ _left = left;
+ }
+
+ public void setNext(final SortedQueueEntryImpl next)
+ {
+ _next = next;
+ }
+
+ public void setParent(final SortedQueueEntryImpl parent)
+ {
+ _parent = parent;
+ }
+
+ public void setPrev(final SortedQueueEntryImpl prev)
+ {
+ _prev = prev;
+ }
+
+ public void setRight(final SortedQueueEntryImpl right)
+ {
+ _right = right;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "(" + (_colour == Colour.RED ? "Red," : "Black,") + _key + ")";
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
new file mode 100644
index 0000000000..5f8ab16c06
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
@@ -0,0 +1,665 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.message.ServerMessage;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour;
+import org.apache.qpid.server.store.StoreContext;
+
+/**
+ * A sorted implementation of QueueEntryList.
+ * Uses the red/black tree algorithm specified in "Introduction to Algorithms".
+ * ISBN-10: 0262033844
+ * ISBN-13: 978-0262033848
+ * @see http://en.wikipedia.org/wiki/Red-black_tree
+ */
+public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl>
+{
+ private final SortedQueueEntryImpl _head;
+ private SortedQueueEntryImpl _root;
+ private long _entryId = Long.MIN_VALUE;
+ private final Object _lock = new Object();
+ private final AMQQueue _queue;
+ private final String _propertyName;
+
+ public SortedQueueEntryList(final AMQQueue queue, final String propertyName)
+ {
+ _queue = queue;
+ _head = new SortedQueueEntryImpl(this);
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ @Override
+ public SortedQueueEntryImpl add(final ServerMessage message)
+ {
+ synchronized(_lock)
+ {
+ String key = null;
+ final Object val = message.getMessageHeader().getHeader(_propertyName);
+ if(val != null)
+ {
+ key = val.toString();
+ }
+
+ final SortedQueueEntryImpl entry = new SortedQueueEntryImpl(this,message, ++_entryId);
+ entry.setKey(key);
+
+ insert(entry);
+
+ return entry;
+ }
+ }
+
+ /**
+ * Red Black Tree insert implementation.
+ * @param entry the entry to insert.
+ */
+ private void insert(final SortedQueueEntryImpl entry)
+ {
+ SortedQueueEntryImpl node = _root;
+ if((node = _root) == null)
+ {
+ _root = entry;
+ _head.setNext(entry);
+ entry.setPrev(_head);
+ return;
+ }
+ else
+ {
+ SortedQueueEntryImpl parent = null;
+ while(node != null)
+ {
+ parent = node;
+ if(entry.compareTo(node) < 0)
+ {
+ node = node.getLeft();
+ }
+ else
+ {
+ node = node.getRight();
+ }
+ }
+ entry.setParent(parent);
+
+ if(entry.compareTo(parent) < 0)
+ {
+ parent.setLeft(entry);
+ final SortedQueueEntryImpl prev = parent.getPrev();
+ entry.setNext(parent);
+ prev.setNext(entry);
+ entry.setPrev(prev);
+ parent.setPrev(entry);
+ }
+ else
+ {
+ parent.setRight(entry);
+
+ final SortedQueueEntryImpl next = parent.getNextValidEntry();
+ entry.setNext(next);
+ parent.setNext(entry);
+
+ if(next != null)
+ {
+ next.setPrev(entry);
+ }
+ entry.setPrev(parent);
+ }
+ }
+ entry.setColour(Colour.RED);
+ insertFixup(entry);
+ }
+
+ private void insertFixup(SortedQueueEntryImpl entry)
+ {
+ while(isParentColour(entry, Colour.RED))
+ {
+ final SortedQueueEntryImpl grandparent = nodeGrandparent(entry);
+
+ if(nodeParent(entry) == leftChild(grandparent))
+ {
+ final SortedQueueEntryImpl y = rightChild(grandparent);
+ if(isNodeColour(y, Colour.RED))
+ {
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(y, Colour.BLACK);
+ setColour(grandparent, Colour.RED);
+ entry = grandparent;
+ }
+ else
+ {
+ if(entry == rightChild(nodeParent(entry)))
+ {
+ entry = nodeParent(entry);
+ leftRotate(entry);
+ }
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(nodeGrandparent(entry), Colour.RED);
+ rightRotate(nodeGrandparent(entry));
+ }
+ }
+ else
+ {
+ final SortedQueueEntryImpl y = leftChild(grandparent);
+ if(isNodeColour(y, Colour.RED))
+ {
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(y, Colour.BLACK);
+ setColour(grandparent, Colour.RED);
+ entry = grandparent;
+ }
+ else
+ {
+ if(entry == leftChild(nodeParent(entry)))
+ {
+ entry = nodeParent(entry);
+ rightRotate(entry);
+ }
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(nodeGrandparent(entry), Colour.RED);
+ leftRotate(nodeGrandparent(entry));
+ }
+ }
+ }
+ _root.setColour(Colour.BLACK);
+ }
+
+ private void leftRotate(final SortedQueueEntryImpl entry)
+ {
+ if(entry != null)
+ {
+ final SortedQueueEntryImpl rightChild = rightChild(entry);
+ entry.setRight(rightChild.getLeft());
+ if(entry.getRight() != null)
+ {
+ entry.getRight().setParent(entry);
+ }
+ rightChild.setParent(entry.getParent());
+ if(entry.getParent() == null)
+ {
+ _root = rightChild;
+ }
+ else if(entry == entry.getParent().getLeft())
+ {
+ entry.getParent().setLeft(rightChild);
+ }
+ else
+ {
+ entry.getParent().setRight(rightChild);
+ }
+ rightChild.setLeft(entry);
+ entry.setParent(rightChild);
+ }
+ }
+
+ private void rightRotate(final SortedQueueEntryImpl entry)
+ {
+ if(entry != null)
+ {
+ final SortedQueueEntryImpl leftChild = leftChild(entry);
+ entry.setLeft(leftChild.getRight());
+ if(entry.getLeft() != null)
+ {
+ leftChild.getRight().setParent(entry);
+ }
+ leftChild.setParent(entry.getParent());
+ if(leftChild.getParent() == null)
+ {
+ _root = leftChild;
+ }
+ else if(entry == entry.getParent().getRight())
+ {
+ entry.getParent().setRight(leftChild);
+ }
+ else
+ {
+ entry.getParent().setLeft(leftChild);
+ }
+ leftChild.setRight(entry);
+ entry.setParent(leftChild);
+ }
+ }
+
+ private void setColour(final SortedQueueEntryImpl node, final Colour colour)
+ {
+ if(node != null)
+ {
+ node.setColour(colour);
+ }
+ }
+
+ private SortedQueueEntryImpl leftChild(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getLeft();
+ }
+
+ private SortedQueueEntryImpl rightChild(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getRight();
+ }
+
+ private SortedQueueEntryImpl nodeParent(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getParent();
+ }
+
+ private SortedQueueEntryImpl nodeGrandparent(final SortedQueueEntryImpl node)
+ {
+ return nodeParent(nodeParent(node));
+ }
+
+ private boolean isParentColour(final SortedQueueEntryImpl node, final SortedQueueEntryImpl.Colour colour)
+ {
+
+ return node != null && isNodeColour(node.getParent(), colour);
+ }
+
+ protected boolean isNodeColour(final SortedQueueEntryImpl node, final SortedQueueEntryImpl.Colour colour)
+ {
+ return (node == null ? Colour.BLACK : node.getColour()) == colour;
+ }
+
+ @Override
+ public SortedQueueEntryImpl next(final SortedQueueEntryImpl node)
+ {
+ synchronized(_lock)
+ {
+ if(node.isDispensed() && _head != node)
+ {
+ SortedQueueEntryImpl current = _head;
+ SortedQueueEntryImpl next;
+ while(current != null)
+ {
+ next = current.getNextValidEntry();
+ if(current.compareTo(node)>0 && !current.isDispensed())
+ {
+ break;
+ }
+ else
+ {
+ current = next;
+ }
+ }
+ return current;
+ }
+ else
+ {
+ return node.getNextValidEntry();
+ }
+ }
+ }
+
+ @Override
+ public QueueEntryIterator<SortedQueueEntryImpl> iterator()
+ {
+ return new QueueEntryIteratorImpl(_head);
+ }
+
+ @Override
+ public SortedQueueEntryImpl getHead()
+ {
+ return _head;
+ }
+
+ protected SortedQueueEntryImpl getRoot()
+ {
+ return _root;
+ }
+
+ @Override
+ public void entryDeleted(final SortedQueueEntryImpl entry)
+ {
+ synchronized(_lock)
+ {
+ // If the node to be removed has two children, we swap the position
+ // of the node and its successor in the tree
+ if(leftChild(entry) != null && rightChild(entry) != null)
+ {
+ swapWithSuccessor(entry);
+ }
+
+ // Then deal with the easy doubly linked list deletion (need to do
+ // this after the swap as the swap uses next
+ final SortedQueueEntryImpl prev = entry.getPrev();
+ if(prev != null)
+ {
+ prev.setNext(entry.getNextValidEntry());
+ }
+
+ final SortedQueueEntryImpl next = entry.getNextValidEntry();
+ if(next != null)
+ {
+ next.setPrev(prev);
+ }
+
+ // now deal with splicing
+ final SortedQueueEntryImpl chosenChild;
+
+ if(leftChild(entry) != null)
+ {
+ chosenChild = leftChild(entry);
+ }
+ else
+ {
+ chosenChild = rightChild(entry);
+ }
+
+ if(chosenChild != null)
+ {
+ // we have one child (x), we can move it up to replace x;
+ chosenChild.setParent(entry.getParent());
+ if(chosenChild.getParent() == null)
+ {
+ _root = chosenChild;
+ }
+ else if(entry == entry.getParent().getLeft())
+ {
+ entry.getParent().setLeft(chosenChild);
+ }
+ else
+ {
+ entry.getParent().setRight(chosenChild);
+ }
+
+ entry.setLeft(null);
+ entry.setRight(null);
+ entry.setParent(null);
+
+ if(entry.getColour() == Colour.BLACK)
+ {
+ deleteFixup(chosenChild);
+ }
+
+ }
+ else
+ {
+ // no children
+ if(entry.getParent() == null)
+ {
+ // no parent either - the tree is empty
+ _root = null;
+ }
+ else
+ {
+ if(entry.getColour() == Colour.BLACK)
+ {
+ deleteFixup(entry);
+ }
+
+ if(entry.getParent() != null)
+ {
+ if(entry.getParent().getLeft() == entry)
+ {
+ entry.getParent().setLeft(null);
+ }
+ else if(entry.getParent().getRight() == entry)
+ {
+ entry.getParent().setRight(null);
+ }
+ entry.setParent(null);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Swaps the position of the node in the tree with it's successor
+ * (that is the node with the next highest key)
+ * @param entry
+ */
+ private void swapWithSuccessor(final SortedQueueEntryImpl entry)
+ {
+ final SortedQueueEntryImpl next = entry.getNextValidEntry();
+ final SortedQueueEntryImpl nextParent = next.getParent();
+ final SortedQueueEntryImpl nextLeft = next.getLeft();
+ final SortedQueueEntryImpl nextRight = next.getRight();
+ final Colour nextColour = next.getColour();
+
+ // Special case - the successor is the right child of the node
+ if(next == entry.getRight())
+ {
+ next.setParent(entry.getParent());
+ if(next.getParent() == null)
+ {
+ _root = next;
+ }
+ else if(next.getParent().getLeft() == entry)
+ {
+ next.getParent().setLeft(next);
+ }
+ else
+ {
+ next.getParent().setRight(next);
+ }
+
+ next.setRight(entry);
+ entry.setParent(next);
+ next.setLeft(entry.getLeft());
+
+ if(next.getLeft() != null)
+ {
+ next.getLeft().setParent(next);
+ }
+
+ next.setColour(entry.getColour());
+ entry.setColour(nextColour);
+ entry.setLeft(nextLeft);
+
+ if(nextLeft != null)
+ {
+ nextLeft.setParent(entry);
+ }
+ entry.setRight(nextRight);
+ if(nextRight != null)
+ {
+ nextRight.setParent(entry);
+ }
+ }
+ else
+ {
+ next.setParent(entry.getParent());
+ if(next.getParent() == null)
+ {
+ _root = next;
+ }
+ else if(next.getParent().getLeft() == entry)
+ {
+ next.getParent().setLeft(next);
+ }
+ else
+ {
+ next.getParent().setRight(next);
+ }
+
+ next.setLeft(entry.getLeft());
+ if(next.getLeft() != null)
+ {
+ next.getLeft().setParent(next);
+ }
+ next.setRight(entry.getRight());
+ if(next.getRight() != null)
+ {
+ next.getRight().setParent(next);
+ }
+ next.setColour(entry.getColour());
+
+ entry.setParent(nextParent);
+ if(nextParent.getLeft() == next)
+ {
+ nextParent.setLeft(entry);
+ }
+ else
+ {
+ nextParent.setRight(entry);
+ }
+
+ entry.setLeft(nextLeft);
+ if(nextLeft != null)
+ {
+ nextLeft.setParent(entry);
+ }
+ entry.setRight(nextRight);
+ if(nextRight != null)
+ {
+ nextRight.setParent(entry);
+ }
+ entry.setColour(nextColour);
+ }
+ }
+
+ private void deleteFixup(SortedQueueEntryImpl entry)
+ {
+ int i = 0;
+ while(entry != null && entry != _root
+ && isNodeColour(entry, Colour.BLACK))
+ {
+ i++;
+
+ if(i > 1000)
+ {
+ return;
+ }
+
+ if(entry == leftChild(nodeParent(entry)))
+ {
+ SortedQueueEntryImpl rightSibling = rightChild(nodeParent(entry));
+ if(isNodeColour(rightSibling, Colour.RED))
+ {
+ setColour(rightSibling, Colour.BLACK);
+ nodeParent(entry).setColour(Colour.RED);
+ leftRotate(nodeParent(entry));
+ rightSibling = rightChild(nodeParent(entry));
+ }
+
+ if(isNodeColour(leftChild(rightSibling), Colour.BLACK)
+ && isNodeColour(rightChild(rightSibling), Colour.BLACK))
+ {
+ setColour(rightSibling, Colour.RED);
+ entry = nodeParent(entry);
+ }
+ else
+ {
+ if(isNodeColour(rightChild(rightSibling), Colour.BLACK))
+ {
+ setColour(leftChild(rightSibling), Colour.BLACK);
+ rightSibling.setColour(Colour.RED);
+ rightRotate(rightSibling);
+ rightSibling = rightChild(nodeParent(entry));
+ }
+ setColour(rightSibling, getColour(nodeParent(entry)));
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(rightChild(rightSibling), Colour.BLACK);
+ leftRotate(nodeParent(entry));
+ entry = _root;
+ }
+ }
+ else
+ {
+ SortedQueueEntryImpl leftSibling = leftChild(nodeParent(entry));
+ if(isNodeColour(leftSibling, Colour.RED))
+ {
+ setColour(leftSibling, Colour.BLACK);
+ nodeParent(entry).setColour(Colour.RED);
+ rightRotate(nodeParent(entry));
+ leftSibling = leftChild(nodeParent(entry));
+ }
+
+ if(isNodeColour(leftChild(leftSibling), Colour.BLACK)
+ && isNodeColour(rightChild(leftSibling), Colour.BLACK))
+ {
+ setColour(leftSibling, Colour.RED);
+ entry = nodeParent(entry);
+ }
+ else
+ {
+ if(isNodeColour(leftChild(leftSibling), Colour.BLACK))
+ {
+ setColour(rightChild(leftSibling), Colour.BLACK);
+ leftSibling.setColour(Colour.RED);
+ leftRotate(leftSibling);
+ leftSibling = leftChild(nodeParent(entry));
+ }
+ setColour(leftSibling, getColour(nodeParent(entry)));
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(leftChild(leftSibling), Colour.BLACK);
+ rightRotate(nodeParent(entry));
+ entry = _root;
+ }
+ }
+ }
+ setColour(entry, Colour.BLACK);
+ }
+
+ private Colour getColour(final SortedQueueEntryImpl x)
+ {
+ return x == null ? null : x.getColour();
+ }
+
+ public class QueueEntryIteratorImpl implements QueueEntryIterator<SortedQueueEntryImpl>
+ {
+ private SortedQueueEntryImpl _lastNode;
+
+ public QueueEntryIteratorImpl(final SortedQueueEntryImpl startNode)
+ {
+ _lastNode = startNode;
+ }
+
+ public boolean atTail()
+ {
+ return next(_lastNode) == null;
+ }
+
+ public SortedQueueEntryImpl getNode()
+ {
+ return _lastNode;
+ }
+
+ public boolean advance()
+ {
+ if(!atTail())
+ {
+ SortedQueueEntryImpl nextNode = next(_lastNode);
+ while(nextNode.isDispensed() && next(nextNode) != null)
+ {
+ nextNode = next(nextNode);
+ }
+ _lastNode = nextNode;
+ return true;
+
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java
new file mode 100644
index 0000000000..7a70795e77
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java
@@ -0,0 +1,19 @@
+package org.apache.qpid.server.queue;
+
+public class SortedQueueEntryListFactory implements QueueEntryListFactory
+{
+
+ private final String _propertyName;
+
+ public SortedQueueEntryListFactory(final String propertyName)
+ {
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public QueueEntryList<SortedQueueEntryImpl> createQueueEntryList(final AMQQueue queue)
+ {
+ return new SortedQueueEntryList(queue, _propertyName);
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
index 46c1a6af9a..fbef23dca1 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
@@ -27,6 +27,10 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.AMQException;
import org.apache.log4j.Logger;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
class SubFlushRunner implements ReadWriteRunnable
{
@@ -34,29 +38,33 @@ class SubFlushRunner implements ReadWriteRunnable
private final Subscription _sub;
- private final String _name;
+
+ private static int IDLE = 0;
+ private static int SCHEDULED = 1;
+ private static int RUNNING = 2;
+
+
+ private final AtomicInteger _scheduled = new AtomicInteger(IDLE);
+
+
private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ private final AtomicBoolean _stateChange = new AtomicBoolean();
public SubFlushRunner(Subscription sub)
{
_sub = sub;
- _name = "SubFlushRunner-"+_sub;
}
public void run()
{
-
- String originalName = Thread.currentThread().getName();
- try
+ if(_scheduled.compareAndSet(SCHEDULED, RUNNING))
{
- Thread.currentThread().setName(_name);
-
boolean complete = false;
+ _stateChange.set(false);
try
{
CurrentActor.set(_sub.getLogActor());
complete = getQueue().flushSubscription(_sub, ITERATIONS);
-
}
catch (AMQException e)
{
@@ -66,17 +74,15 @@ class SubFlushRunner implements ReadWriteRunnable
{
CurrentActor.remove();
}
- if (!complete && !_sub.isSuspended())
+ _scheduled.compareAndSet(RUNNING, IDLE);
+ if ((!complete || _stateChange.compareAndSet(true,false))&& !_sub.isSuspended())
{
- getQueue().execute(this);
+ if(_scheduled.compareAndSet(IDLE,SCHEDULED))
+ {
+ getQueue().execute(this);
+ }
}
-
}
- finally
- {
- Thread.currentThread().setName(originalName);
- }
-
}
private SimpleAMQQueue getQueue()
@@ -93,4 +99,18 @@ class SubFlushRunner implements ReadWriteRunnable
{
return true;
}
+
+ public String toString()
+ {
+ return "SubFlushRunner-" + _sub.getLogActor();
+ }
+
+ public void execute(Executor executor)
+ {
+ _stateChange.set(true);
+ if(_scheduled.compareAndSet(IDLE,SCHEDULED))
+ {
+ executor.execute(this);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index c07074f69c..7eb1b54693 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -250,14 +250,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
+ initialiseManagedObjectRegistry();
+
configure();
_qmfService = new QMFService(getConfigStore(), this);
CurrentActor.get().message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion()));
- initialiseManagedObjectRegistry();
-
_virtualHostRegistry = new VirtualHostRegistry(this);
_securityManager = new SecurityManager(_configuration, _pluginManager);
@@ -471,12 +471,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
close(_authenticationManager);
- close(_managedObjectRegistry);
-
close(_qmfService);
close(_pluginManager);
+ close(_managedObjectRegistry);
+
CurrentActor.get().message(BrokerMessages.STOPPED());
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
index 8b5ff6781d..ec11e2d39c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
@@ -73,11 +73,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin
return getDefault();
}
- public Result authoriseExecute(ObjectType object, ObjectProperties properties)
- {
- return getDefault();
- }
-
public Result authoriseUpdate(ObjectType object, ObjectProperties properties)
{
return getDefault();
@@ -121,8 +116,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin
return authoriseDelete(objectType, properties);
case PURGE:
return authorisePurge(objectType, properties);
- case EXECUTE:
- return authoriseExecute(objectType, properties);
case UPDATE:
return authoriseUpdate(objectType, properties);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index f582fed6a0..abf9e3379d 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -20,10 +20,8 @@ package org.apache.qpid.server.security;
import static org.apache.qpid.server.security.access.ObjectType.EXCHANGE;
import static org.apache.qpid.server.security.access.ObjectType.METHOD;
-import static org.apache.qpid.server.security.access.ObjectType.OBJECT;
import static org.apache.qpid.server.security.access.ObjectType.QUEUE;
import static org.apache.qpid.server.security.access.ObjectType.VIRTUALHOST;
-import static org.apache.qpid.server.security.access.Operation.ACCESS;
import static org.apache.qpid.server.security.access.Operation.BIND;
import static org.apache.qpid.server.security.access.Operation.CONSUME;
import static org.apache.qpid.server.security.access.Operation.CREATE;
@@ -67,7 +65,14 @@ public class SecurityManager
/** Container for the {@link Principal} that is using to this thread. */
private static final ThreadLocal<Subject> _subject = new ThreadLocal<Subject>();
-
+ private static final ThreadLocal<Boolean> _accessChecksDisabled = new ThreadLocal<Boolean>()
+ {
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
private PluginManager _pluginManager;
private Map<String, SecurityPluginFactory> _pluginFactories = new HashMap<String, SecurityPluginFactory>();
private Map<String, SecurityPlugin> _globalPlugins = new HashMap<String, SecurityPlugin>();
@@ -194,6 +199,11 @@ public class SecurityManager
private boolean checkAllPlugins(AccessCheck checker)
{
+ if(_accessChecksDisabled.get())
+ {
+ return true;
+ }
+
HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins);
for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet())
@@ -273,21 +283,6 @@ public class SecurityManager
}
});
}
-
- // TODO not implemented yet, awaiting consensus
- public boolean authoriseObject(final String packageName, final String className)
- {
- return checkAllPlugins(new AccessCheck()
- {
- Result allowed(SecurityPlugin plugin)
- {
- ObjectProperties properties = new ObjectProperties();
- properties.put(ObjectProperties.Property.PACKAGE, packageName);
- properties.put(ObjectProperties.Property.CLASS, className);
- return plugin.authorise(ACCESS, OBJECT, properties);
- }
- });
- }
public boolean authoriseMethod(final Operation operation, final String componentName, final String methodName)
{
@@ -329,17 +324,6 @@ public class SecurityManager
});
}
- public boolean authoriseConsume(final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
- Result allowed(SecurityPlugin plugin)
- {
- return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(exclusive, noAck, noLocal, nowait, queue));
- }
- });
- }
-
public boolean authoriseCreateExchange(final Boolean autoDelete, final Boolean durable, final AMQShortString exchangeName,
final Boolean internal, final Boolean nowait, final Boolean passive, final AMQShortString exchangeType)
{
@@ -419,4 +403,14 @@ public class SecurityManager
}
});
}
+
+ public static boolean setAccessChecksDisabled(final boolean status)
+ {
+ //remember current value
+ boolean current = _accessChecksDisabled.get();
+
+ _accessChecksDisabled.set(status);
+
+ return current;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
index 7103b30283..69c7ff185a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
@@ -32,14 +32,12 @@ import java.util.Set;
public enum ObjectType
{
ALL(Operation.ALL),
- VIRTUALHOST(ACCESS),
- QUEUE(CREATE, DELETE, PURGE, CONSUME),
- TOPIC(CREATE, DELETE, PURGE, CONSUME),
- EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
+ VIRTUALHOST(Operation.ALL, ACCESS),
+ QUEUE(Operation.ALL, CREATE, DELETE, PURGE, CONSUME),
+ EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
LINK, // Not allowed in the Java broker
ROUTE, // Not allowed in the Java broker
- METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE),
- OBJECT(ACCESS);
+ METHOD(Operation.ALL, ACCESS, UPDATE);
private EnumSet<Operation> _actions;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
index 06d7f8fd0c..21ea042eed 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
@@ -32,8 +32,7 @@ public enum Operation
UNBIND,
DELETE,
PURGE,
- UPDATE,
- EXECUTE;
+ UPDATE;
public static Operation parse(String text)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
index 1612d13b1b..7cb34da804 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
@@ -384,16 +384,8 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
BufferedReader reader = null;
PrintStream writer = null;
-
- Random r = new Random();
- File tmp;
- do
- {
- tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp");
- }
- while(tmp.exists());
-
- tmp.deleteOnExit();
+
+ final File tmp = createTempFileOnSameFilesystem(_passwordFile);
try
{
@@ -458,52 +450,72 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
}
finally
{
- if (reader != null)
- {
- reader.close();
- }
-
if (writer != null)
{
writer.close();
}
- }
-
- // Swap temp file to main password file.
- File old = new File(_passwordFile.getAbsoluteFile() + ".old");
- if (old.exists())
- {
- old.delete();
- }
-
- if(!_passwordFile.renameTo(old))
- {
- //unable to rename the existing file to the backup name
- _logger.error("Could not backup the existing password file");
- throw new IOException("Could not backup the existing password file");
- }
-
- if(!tmp.renameTo(_passwordFile))
- {
- //failed to rename the new file to the required filename
-
- if(!old.renameTo(_passwordFile))
+ if (reader != null)
{
- //unable to return the backup to required filename
- _logger.error("Could not rename the new password file into place, and unable to restore original file");
- throw new IOException("Could not rename the new password file into place, and unable to restore original file");
+ reader.close();
}
-
- _logger.error("Could not rename the new password file into place");
- throw new IOException("Could not rename the new password file into place");
}
-
+
+ swapTempFileToLive(_passwordFile, tmp);
+
}
finally
{
_userUpdate.unlock();
}
}
+
+ private void swapTempFileToLive(final File live, final File temp) throws IOException
+ {
+ // Remove any existing ".old" file
+ final File old = new File(live.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
+ }
+
+ // Create an new ".old" file
+ if(!live.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing password file");
+ throw new IOException("Could not backup the existing password file");
+ }
+
+ // Move temp file to be the new "live" file
+ if(!temp.renameTo(live))
+ {
+ //failed to rename the new file to the required filename
+ if(!old.renameTo(live))
+ {
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new password file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new password file into place, and unable to restore original file");
+ }
+
+ _logger.error("Could not rename the new password file into place");
+ throw new IOException("Could not rename the new password file into place");
+ }
+ }
+
+ private File createTempFileOnSameFilesystem(final File liveFile)
+ {
+ File tmp;
+ final Random r = new Random();
+
+ do
+ {
+ tmp = new File(liveFile.getPath() + r.nextInt() + ".tmp");
+ }
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
+ return tmp;
+ }
public void reload() throws IOException
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
index 8b099b62ce..d3f46d2e90 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
@@ -142,6 +142,19 @@ public class DerbyMessageStore implements MessageStore
private boolean _configured;
+ private static final class CommitStoreFuture implements StoreFuture
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public void waitForCompletion()
+ {
+
+ }
+ }
+
private enum State
{
INITIAL,
@@ -910,19 +923,19 @@ public class DerbyMessageStore implements MessageStore
throws AMQStoreException
{
Connection conn = null;
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
// 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);
+ stmt = conn.prepareStatement(DELETE_FROM_BINDINGS);
stmt.setString(1, exchange.getNameShortString().toString() );
stmt.setString(2, queue.getNameShortString().toString());
stmt.setString(3, routingKey == null ? null : routingKey.toString());
-
+
int result = stmt.executeUpdate();
- stmt.close();
-
+
if(result != 1)
{
throw new AMQStoreException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange "
@@ -936,21 +949,9 @@ public class DerbyMessageStore implements MessageStore
}
finally
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e)
- {
- _logger.error(e);
- }
- }
-
+ closePreparedStatement(stmt);
+ closeConnection(conn);
}
-
-
}
public void createQueue(AMQQueue queue) throws AMQStoreException
@@ -1153,15 +1154,14 @@ public class DerbyMessageStore implements MessageStore
AMQShortString name = queue.getNameShortString();
_logger.debug("public void removeQueue(AMQShortString name = " + name + "): called");
Connection conn = null;
-
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE);
+ stmt = conn.prepareStatement(DELETE_FROM_QUEUE);
stmt.setString(1, name.toString());
int results = stmt.executeUpdate();
- stmt.close();
-
+
if (results == 0)
{
throw new AMQStoreException("Queue " + name + " not found");
@@ -1173,18 +1173,8 @@ public class DerbyMessageStore implements MessageStore
}
finally
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e)
- {
- _logger.error(e);
- }
- }
-
+ closePreparedStatement(stmt);
+ closeConnection(conn);
}
@@ -1317,19 +1307,7 @@ public class DerbyMessageStore implements MessageStore
public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQStoreException
{
commitTran(connWrapper);
- return new StoreFuture()
- {
- public boolean isComplete()
- {
- return true;
- }
-
- public void waitForCompletion()
- {
-
- }
- };
-
+ return new CommitStoreFuture();
}
public void abortTran(ConnectionWrapper connWrapper) throws AMQStoreException
@@ -1572,6 +1550,7 @@ public class DerbyMessageStore implements MessageStore
{
_logger.debug("Adding content chunk offset " + offset + " for message " +messageId);
}
+ PreparedStatement stmt = null;
try
{
@@ -1580,7 +1559,7 @@ public class DerbyMessageStore implements MessageStore
byte[] chunkData = new byte[src.limit()];
src.duplicate().get(chunkData);
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
+ stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
stmt.setLong(1,messageId);
stmt.setInt(2, offset);
stmt.setInt(3, offset+chunkData.length);
@@ -1594,24 +1573,16 @@ public class DerbyMessageStore implements MessageStore
ByteArrayInputStream bis = new ByteArrayInputStream(chunkData);
stmt.setBinaryStream(4, bis, chunkData.length);
stmt.executeUpdate();
- stmt.close();
}
catch (SQLException e)
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e1)
- {
-
- }
- }
-
+ closeConnection(conn);
throw new RuntimeException("Error adding content chunk offset " + offset + " for message " + messageId + ": " + e.getMessage(), e);
}
+ finally
+ {
+ closePreparedStatement(stmt);
+ }
}
@@ -1619,13 +1590,13 @@ public class DerbyMessageStore implements MessageStore
public int getContent(long messageId, int offset, ByteBuffer dst)
{
Connection conn = null;
-
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
+ stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
stmt.setLong(1,messageId);
stmt.setInt(2, offset);
stmt.setInt(3, offset+dst.remaining());
@@ -1656,28 +1627,18 @@ public class DerbyMessageStore implements MessageStore
}
}
- stmt.close();
- conn.close();
return written;
}
catch (SQLException e)
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e1)
- {
-
- }
- }
-
throw new RuntimeException("Error retrieving content from offset " + offset + " for message " + messageId + ": " + e.getMessage(), e);
}
-
+ finally
+ {
+ closePreparedStatement(stmt);
+ closeConnection(conn);
+ }
}
@@ -1849,5 +1810,33 @@ public class DerbyMessageStore implements MessageStore
}
}
+ private void closeConnection(final Connection conn)
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e)
+ {
+ _logger.error("Problem closing connection", e);
+ }
+ }
+ }
+ private void closePreparedStatement(final PreparedStatement stmt)
+ {
+ if (stmt != null)
+ {
+ try
+ {
+ stmt.close();
+ }
+ catch(SQLException e)
+ {
+ _logger.error("Problem closing prepared statement", e);
+ }
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
index b49b12fb79..80c5e2866c 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
@@ -53,12 +53,12 @@ class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDi
}
- public void onRelease()
+ public void onRelease(boolean setRedelivered)
{
final Subscription_0_10 subscription = getSubscription();
if(subscription != null && _entry.isAcquiredBy(_sub))
{
- subscription.release(_entry);
+ subscription.release(_entry, setRedelivered);
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
index b5bb2014b5..a61b0b4e82 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
@@ -43,11 +43,11 @@ class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDi
_logger.warn("MessageAccept received for message which is using NONE as the accept mode (likely client error)");
}
- public void onRelease()
+ public void onRelease(boolean setRedelivered)
{
if(_entry.isAcquiredBy(_sub))
{
- getSubscription().release(_entry);
+ getSubscription().release(_entry, setRedelivered);
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
index 5c4e413989..bc1be90531 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
@@ -69,17 +69,24 @@ public interface Subscription
void close();
- void send(QueueEntry msg) throws AMQException;
+ void send(QueueEntry entry, boolean batch) throws AMQException;
+
+ void flushBatched();
void queueDeleted(AMQQueue queue);
boolean wouldSuspend(QueueEntry msg);
+ boolean trySendLock();
+
+
void getSendLock();
void releaseSendLock();
+ void releaseQueueEntry(final QueueEntry queueEntryImpl);
+
void onDequeue(final QueueEntry queueEntry);
void restoreCredit(final QueueEntry queueEntry);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
index adb0a84151..23ae14eef1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -119,11 +119,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* 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 entry
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry msg) throws AMQException
+ public void send(QueueEntry entry, boolean batch) 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.
@@ -131,7 +133,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
long deliveryTag = getChannel().getNextDeliveryTag();
- sendToClient(msg, deliveryTag);
+ sendToClient(entry, deliveryTag);
}
}
@@ -173,11 +175,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* 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
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry entry) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
// if we do not need to wait for client acknowledgements
// we can decrement the reference count immediately.
@@ -193,6 +197,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
+ getChannel().getProtocolSession().setDeferFlush(batch);
long deliveryTag = getChannel().getNextDeliveryTag();
sendToClient(entry, deliveryTag);
@@ -234,7 +239,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public boolean wouldSuspend(QueueEntry msg)
{
- return !getCreditManager().useCreditForMessage(msg.getMessage());
+ return !getCreditManager().useCreditForMessage(msg.getMessage().getSize());
}
}
@@ -263,11 +268,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* 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
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry entry) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
// if we do not need to wait for client acknowledgements
@@ -282,6 +289,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
+ getChannel().getProtocolSession().setDeferFlush(batch);
long deliveryTag = getChannel().getNextDeliveryTag();
@@ -441,10 +449,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* 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 entry
+ * @param batch
* @throws AMQException
*/
- abstract public void send(QueueEntry msg) throws AMQException;
+ abstract public void send(QueueEntry entry, boolean batch) throws AMQException;
public boolean isSuspended()
@@ -575,7 +585,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public boolean wouldSuspend(QueueEntry msg)
{
- return !_creditManager.useCreditForMessage(msg.getMessage());//_channel.wouldSuspend(msg.getMessage());
+ return !_creditManager.useCreditForMessage(msg.getMessage().getSize());//_channel.wouldSuspend(msg.getMessage());
+ }
+
+ public boolean trySendLock()
+ {
+ return _stateChangeLock.tryLock();
}
public void getSendLock()
@@ -623,13 +638,16 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
restoreCredit(queueEntry);
}
+ public void releaseQueueEntry(final QueueEntry queueEntry)
+ {
+ restoreCredit(queueEntry);
+ }
+
public void restoreCredit(final QueueEntry queueEntry)
{
_creditManager.restoreCredit(1, queueEntry.getSize());
}
-
-
public void creditStateChanged(boolean hasCredit)
{
@@ -821,4 +839,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
confirmAutoClose();
}
}
+
+ public void flushBatched()
+ {
+ _channel.getProtocolSession().setDeferFlush(false);
+
+ _channel.getProtocolSession().flushBatched();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
index d9845c5fa6..6db58ce9c1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -24,12 +24,15 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SUBSCRIPT
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.QUEUE_FORMAT;
import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.InboundMessageAdapter;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.configuration.ConfigStore;
import org.apache.qpid.server.configuration.ConfiguredObject;
import org.apache.qpid.server.configuration.SessionConfig;
import org.apache.qpid.server.configuration.SubscriptionConfig;
import org.apache.qpid.server.configuration.SubscriptionConfigType;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.CreditCreditManager;
import org.apache.qpid.server.flow.WindowCreditManager;
@@ -37,9 +40,11 @@ import org.apache.qpid.server.flow.FlowCreditManager_0_10;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
+import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.logging.messages.SubscriptionMessages;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.server.message.AMQMessage;
@@ -56,6 +61,8 @@ import org.apache.qpid.transport.MessageFlowMode;
import org.apache.qpid.transport.MessageProperties;
import org.apache.qpid.transport.MessageTransfer;
import org.apache.qpid.transport.Method;
+import org.apache.qpid.transport.Option;
+import org.apache.qpid.transport.Session;
import org.apache.qpid.transport.Struct;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -79,11 +86,14 @@ import java.nio.ByteBuffer;
public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig, LogSubject
{
+
private final long _subscriptionID;
private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this);
+ private static final Option[] BATCHED = new Option[] { Option.BATCH };
+
private final Lock _stateChangeLock = new ReentrantLock();
private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE);
@@ -120,6 +130,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
private final long _createTime = System.currentTimeMillis();
private final AtomicLong _deliveredCount = new AtomicLong(0);
private final Map<String, Object> _arguments;
+ private int _deferredMessageCredit;
+ private long _deferredSizeCredit;
public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode,
@@ -130,6 +142,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
{
_subscriptionID = subscriptionId;
_session = session;
+ _postIdSettingAction = new AddMessageDispositionListenerAction(session);
_destination = destination;
_acceptMode = acceptMode;
_acquireMode = acquireMode;
@@ -204,13 +217,13 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return false;
}
-
-
- if (_noLocal
- && (entry.getMessage() instanceof MessageTransferMessage)
- && ((MessageTransferMessage)entry.getMessage()).getSession() == _session)
+ if (_noLocal && entry.getMessage() instanceof MessageTransferMessage)
{
- return false;
+ Session messageSession= ((MessageTransferMessage)entry.getMessage()).getSession();
+ if (messageSession != null && messageSession.getConnection() == _session.getConnection())
+ {
+ return false;
+ }
}
@@ -307,10 +320,26 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
}
- private class AddMessageDispositionListnerAction implements Runnable
+ public static class AddMessageDispositionListenerAction implements Runnable
{
- public MessageTransfer _xfr;
- public ServerSession.MessageDispositionChangeListener _action;
+ private MessageTransfer _xfr;
+ private ServerSession.MessageDispositionChangeListener _action;
+ private ServerSession _session;
+
+ public AddMessageDispositionListenerAction(ServerSession session)
+ {
+ _session = session;
+ }
+
+ public void setXfr(MessageTransfer xfr)
+ {
+ _xfr = xfr;
+ }
+
+ public void setAction(ServerSession.MessageDispositionChangeListener action)
+ {
+ _action = action;
+ }
public void run()
{
@@ -321,9 +350,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
}
}
- private final AddMessageDispositionListnerAction _postIdSettingAction = new AddMessageDispositionListnerAction();
+ private final AddMessageDispositionListenerAction _postIdSettingAction;
- public void send(final QueueEntry entry) throws AMQException
+ public void send(final QueueEntry entry, boolean batch) throws AMQException
{
ServerMessage serverMsg = entry.getMessage();
@@ -568,27 +597,29 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
{
public void onComplete(Method method)
{
- restoreCredit(entry);
+ deferredAddCredit(1, entry.getSize());
}
});
}
- _postIdSettingAction._xfr = xfr;
+ _postIdSettingAction.setXfr(xfr);
if(_acceptMode == MessageAcceptMode.EXPLICIT)
{
- _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this);
+ _postIdSettingAction.setAction(new ExplicitAcceptDispositionChangeListener(entry, this));
}
else if(_acquireMode != MessageAcquireMode.PRE_ACQUIRED)
{
- _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this);
+ _postIdSettingAction.setAction(new ImplicitAcceptDispositionChangeListener(entry, this));
}
else
{
- _postIdSettingAction._action = null;
+ _postIdSettingAction.setAction(null);
}
+
_session.sendMessage(xfr, _postIdSettingAction);
+ entry.incrementDeliveryCount();
_deliveredCount.incrementAndGet();
if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED)
{
@@ -624,17 +655,74 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
});
}
- void reject(QueueEntry entry)
+ void reject(final QueueEntry entry)
{
entry.setRedelivered();
entry.routeToAlternate();
}
- void release(QueueEntry entry)
+ void release(final QueueEntry entry, final boolean setRedelivered)
{
- entry.setRedelivered();
- entry.release();
+ if (setRedelivered)
+ {
+ entry.setRedelivered();
+ }
+
+ if (getSession().isClosing() || !setRedelivered)
+ {
+ entry.decrementDeliveryCount();
+ }
+
+ if (isMaxDeliveryLimitReached(entry))
+ {
+ sendToDLQOrDiscard(entry);
+ }
+ else
+ {
+ entry.release();
+ }
+ }
+
+ protected void sendToDLQOrDiscard(QueueEntry entry)
+ {
+ final Exchange alternateExchange = entry.getQueue().getAlternateExchange();
+ final LogActor logActor = CurrentActor.get();
+ final ServerMessage msg = entry.getMessage();
+ if (alternateExchange != null)
+ {
+ final InboundMessage m = new InboundMessageAdapter(entry);
+
+ final ArrayList<? extends BaseQueue> destinationQueues = alternateExchange.route(m);
+
+ if (destinationQueues == null || destinationQueues.isEmpty())
+ {
+ entry.discard();
+
+ logActor.message( ChannelMessages.DISCARDMSG_NOROUTE(msg.getMessageNumber(), alternateExchange.getName()));
+ }
+ else
+ {
+ entry.routeToAlternate();
+
+ //output operational logging for each delivery post commit
+ for (final BaseQueue destinationQueue : destinationQueues)
+ {
+ logActor.message( ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(), destinationQueue.getNameShortString().asString()));
+ }
+ }
+ }
+ else
+ {
+ entry.discard();
+ logActor.message(ChannelMessages.DISCARDMSG_NOALTEXCH(msg.getMessageNumber(), entry.getQueue().getName(), msg.getRoutingKey()));
+ }
+ }
+
+ private boolean isMaxDeliveryLimitReached(QueueEntry entry)
+ {
+ final int maxDeliveryLimit = entry.getQueue().getMaximumDeliveryCount();
+ return (maxDeliveryLimit > 0 && entry.getDeliveryCount() >= maxDeliveryLimit);
}
public void queueDeleted(AMQQueue queue)
@@ -642,9 +730,14 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
_deleted.set(true);
}
- public boolean wouldSuspend(QueueEntry msg)
+ public boolean wouldSuspend(QueueEntry entry)
{
- return !_creditManager.useCreditForMessage(msg.getMessage());
+ return !_creditManager.useCreditForMessage(entry.getMessage().getSize());
+ }
+
+ public boolean trySendLock()
+ {
+ return _stateChangeLock.tryLock();
}
public void getSendLock()
@@ -664,7 +757,12 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
public void onDequeue(QueueEntry queueEntry)
{
+ // no-op for 0-10, credit restored by completing command.
+ }
+ public void releaseQueueEntry(QueueEntry queueEntry)
+ {
+ // no-op for 0-10, credit restored by completing command.
}
public void setStateListener(StateListener listener)
@@ -702,6 +800,28 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return _properties.get(key);
}
+ private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit)
+ {
+ _deferredMessageCredit += deferredMessageCredit;
+ _deferredSizeCredit += deferredSizeCredit;
+
+ }
+
+ public void flushCreditState()
+ {
+ flushCreditState(false);
+ }
+ public void flushCreditState(boolean strict)
+ {
+ if(strict || !isSuspended() || _deferredMessageCredit >= 200
+ || !(_creditManager instanceof WindowCreditManager)
+ || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 )
+ {
+ _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit);
+ _deferredMessageCredit = 0;
+ _deferredSizeCredit = 0l;
+ }
+ }
public FlowCreditManager_0_10 getCreditManager()
{
@@ -804,6 +924,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
public void flush() throws AMQException
{
+ flushCreditState(true);
_queue.flushSubscription(this);
stop();
}
@@ -947,4 +1068,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return (LogSubject) this;
}
+
+ public void flushBatched()
+ {
+ _session.getConnection().flush();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
index e18b453db3..00f0c9f0f1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -24,6 +24,14 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTIO
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT;
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.JMException;
+
+import org.apache.qpid.server.management.ManagedObject;
+
+import org.apache.qpid.server.management.Managable;
+
import java.security.Principal;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -55,7 +63,7 @@ import org.apache.qpid.transport.Method;
import org.apache.qpid.transport.ProtocolEvent;
import org.apache.qpid.transport.Session;
-public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject, AuthorizationHolder
+public class ServerConnection extends Connection implements Managable, AMQConnectionModel, LogSubject, AuthorizationHolder
{
private ConnectionConfig _config;
private Runnable _onOpenTask;
@@ -67,6 +75,10 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
private boolean _statisticsEnabled = false;
private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
private final long _connectionId;
+
+ private ServerConnectionMBean _mBean;
+ private VirtualHost _virtualHost;
+ private AtomicLong _lastIoTime = new AtomicLong();
public ServerConnection(final long connectionId)
{
@@ -133,9 +145,6 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
super.setConnectionDelegate(delegate);
}
- private VirtualHost _virtualHost;
-
-
public VirtualHost getVirtualHost()
{
return _virtualHost;
@@ -144,8 +153,18 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void setVirtualHost(VirtualHost virtualHost)
{
_virtualHost = virtualHost;
-
+
initialiseStatistics();
+
+ try
+ {
+ _mBean = new ServerConnectionMBean(this);
+ _mBean.register();
+ }
+ catch (JMException jme)
+ {
+ log.error("Unable to create mBean for ServerConnection",jme);
+ }
}
public void setConnectionConfig(final ConnectionConfig config)
@@ -190,6 +209,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
@Override
public void received(ProtocolEvent event)
{
+ _lastIoTime.set(System.currentTimeMillis());
if (event.isConnectionControl())
{
CurrentActor.set(_actor);
@@ -260,6 +280,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void close(AMQConstant cause, String message) throws AMQException
{
closeSubscriptions();
+ if (_mBean != null)
+ {
+ _mBean.unregister();
+ _mBean = null;
+ }
ConnectionCloseCode replyCode = ConnectionCloseCode.NORMAL;
try
{
@@ -405,6 +430,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void closed()
{
closeSubscriptions();
+ if (_mBean != null)
+ {
+ _mBean.unregister();
+ _mBean = null;
+ }
super.closed();
}
@@ -416,4 +446,38 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
}
}
+ public void receivedComplete()
+ {
+ for (Session ssn : getChannels())
+ {
+ ((ServerSession)ssn).flushCreditState();
+ }
+ }
+
+ @Override
+ public ManagedObject getManagedObject()
+ {
+ return _mBean;
+ }
+
+ @Override
+ public void send(ProtocolEvent event)
+ {
+ _lastIoTime.set(System.currentTimeMillis());
+ super.send(event);
+ }
+
+ public AtomicLong getLastIoTime()
+ {
+ return _lastIoTime;
+ }
+
+ void checkForNotification()
+ {
+ int channelsCount = getSessionModels().size();
+ if (_mBean != null && channelsCount >= getConnectionDelegate().getChannelMax())
+ {
+ _mBean.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value");
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index 8d6e0e0d80..66ed6f1e62 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -28,10 +28,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
-
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
-
import org.apache.qpid.common.ServerPropertyNames;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.server.configuration.BrokerConfig;
@@ -49,6 +47,7 @@ import org.apache.qpid.transport.ConnectionClose;
import org.apache.qpid.transport.ConnectionCloseCode;
import org.apache.qpid.transport.ConnectionOpen;
import org.apache.qpid.transport.ConnectionOpenOk;
+import org.apache.qpid.transport.ConnectionStartOk;
import org.apache.qpid.transport.ConnectionTuneOk;
import org.apache.qpid.transport.ServerDelegate;
import org.apache.qpid.transport.Session;
@@ -62,6 +61,8 @@ public class ServerConnectionDelegate extends ServerDelegate
{
private final String _localFQDN;
private final IApplicationRegistry _appRegistry;
+ private int _maxNoOfChannels;
+ private Map<String,Object> _clientProperties;
public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN)
{
@@ -77,6 +78,7 @@ public class ServerConnectionDelegate extends ServerDelegate
_appRegistry = appRegistry;
_localFQDN = localFQDN;
+ _maxNoOfChannels = ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
}
private static Map<String, Object> createConnectionProperties(final BrokerConfig brokerConfig)
@@ -154,7 +156,7 @@ public class ServerConnectionDelegate extends ServerDelegate
public void connectionOpen(Connection conn, ConnectionOpen open)
{
final ServerConnection sconn = (ServerConnection) conn;
-
+
VirtualHost vhost;
String vhostName;
if(open.hasVirtualHost())
@@ -222,7 +224,12 @@ public class ServerConnectionDelegate extends ServerDelegate
@Override
protected int getChannelMax()
{
- return ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
+ return _maxNoOfChannels;
+ }
+
+ protected void setChannelMax(int channelMax)
+ {
+ _maxNoOfChannels = channelMax;
}
@Override public void sessionDetach(Connection conn, SessionDetach dtc)
@@ -253,6 +260,7 @@ public class ServerConnectionDelegate extends ServerDelegate
{
ssn = sessionAttachImpl(conn, atc);
conn.registerSession(ssn);
+ ((ServerConnection)conn).checkForNotification();
}
else
{
@@ -279,4 +287,16 @@ public class ServerConnectionDelegate extends ServerDelegate
}
return true;
}
+
+ @Override
+ public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ {
+ _clientProperties = ok.getClientProperties();
+ super.connectionStartOk(conn, ok);
+ }
+
+ public Map<String,Object> getClientProperties()
+ {
+ return _clientProperties;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java
new file mode 100644
index 0000000000..17c7bed601
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java
@@ -0,0 +1,264 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transport;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import javax.management.JMException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.common.ClientProperties;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.protocol.AMQSessionModel;
+
+/**
+ * This MBean class implements the management interface. In order to make more attributes, operations and notifications
+ * available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here.
+ */
+@MBeanDescription("Management Bean for an AMQ Broker 0-10 Connection")
+public class ServerConnectionMBean extends AbstractAMQManagedConnectionObject
+{
+ private final ServerConnection _serverConnection;
+
+ @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-10 Connection")
+ protected ServerConnectionMBean(final ServerConnection serverConnection) throws NotCompliantMBeanException
+ {
+ super(serverConnection.getConfig().getAddress());
+ _serverConnection = serverConnection;
+ }
+
+ @Override
+ public ManagedObject getParentObject()
+ {
+ return _serverConnection.getVirtualHost().getManagedObject();
+ }
+
+ @Override
+ public String getClientId()
+ {
+ return _serverConnection.getClientId();
+ }
+
+ @Override
+ public String getAuthorizedId()
+ {
+ return _serverConnection.getAuthorizedPrincipal().getName();
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return String.valueOf(_serverConnection.getConnectionDelegate().getClientProperties().get(ClientProperties.version.toString()));
+ }
+
+ @Override
+ public String getRemoteAddress()
+ {
+ return _serverConnection.getConfig().getAddress();
+ }
+
+ @Override
+ public Date getLastIoTime()
+ {
+ return new Date(_serverConnection.getLastIoTime().longValue());
+ }
+
+ @Override
+ public Long getMaximumNumberOfChannels()
+ {
+ return (long) _serverConnection.getConnectionDelegate().getChannelMax();
+ }
+
+ @Override
+ public TabularData channels() throws IOException, JMException
+ {
+ final TabularDataSupport channelsList = new TabularDataSupport(_channelsType);
+ final List<AMQSessionModel> list = _serverConnection.getSessionModels();
+
+ for (final AMQSessionModel channel : list)
+ {
+ final ServerSession session = (ServerSession)channel;
+ Object[] itemValues =
+ {
+ session.getChannel(),
+ session.isTransactional(),
+ null,
+ session.getUnacknowledgedMessageCount(),
+ session.getBlocking()
+ };
+
+ final CompositeData channelData = new CompositeDataSupport(_channelType,
+ COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues);
+ channelsList.put(channelData);
+ }
+ return channelsList;
+ }
+
+ @Override
+ public void commitTransactions(int channelId) throws JMException
+ {
+ final ServerSession session = (ServerSession)_serverConnection.getSession(channelId);
+ if (session == null)
+ {
+ throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
+ }
+ else if (session.isTransactional())
+ {
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+ try
+ {
+ session.commit();
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+ }
+
+ @Override
+ public void rollbackTransactions(int channelId) throws JMException
+ {
+ final ServerSession session = (ServerSession)_serverConnection.getSession(channelId);
+ if (session == null)
+ {
+ throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
+ }
+ else if (session.isTransactional())
+ {
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+ try
+ {
+ session.rollback();
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+ }
+
+ @Override
+ public void closeConnection() throws Exception
+ {
+ _serverConnection.mgmtClose();
+ }
+
+ @Override
+ public void resetStatistics() throws Exception
+ {
+ _serverConnection.resetStatistics();
+ }
+
+ @Override
+ public double getPeakMessageDeliveryRate()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getPeak();
+ }
+
+ @Override
+ public double getPeakDataDeliveryRate()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getPeak();
+ }
+
+ @Override
+ public double getMessageDeliveryRate()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getRate();
+ }
+
+ @Override
+ public double getDataDeliveryRate()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getRate();
+ }
+
+ @Override
+ public long getTotalMessagesDelivered()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getTotal();
+ }
+
+ @Override
+ public long getTotalDataDelivered()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getTotal();
+ }
+
+ @Override
+ public double getPeakMessageReceiptRate()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getPeak();
+ }
+
+ @Override
+ public double getPeakDataReceiptRate()
+ {
+ return _serverConnection.getDataReceiptStatistics().getPeak();
+ }
+
+ @Override
+ public double getMessageReceiptRate()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getRate();
+ }
+
+ @Override
+ public double getDataReceiptRate()
+ {
+ return _serverConnection.getDataReceiptStatistics().getRate();
+ }
+
+ @Override
+ public long getTotalMessagesReceived()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getTotal();
+ }
+
+ @Override
+ public long getTotalDataReceived()
+ {
+ return _serverConnection.getDataReceiptStatistics().getTotal();
+ }
+
+ @Override
+ public boolean isStatisticsEnabled()
+ {
+ return _serverConnection.isStatisticsEnabled();
+ }
+
+ @Override
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _serverConnection.setStatisticsEnabled(enabled);
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index 429cc4cf66..23b77b1fd9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -37,9 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
-
import javax.security.auth.Subject;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.ProtocolEngine;
@@ -93,7 +91,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
{
public void onAccept();
- public void onRelease();
+ public void onRelease(boolean setRedelivered);
public void onReject();
@@ -230,13 +228,13 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
}
- public void release(RangeSet ranges)
+ public void release(RangeSet ranges, final boolean setRedelivered)
{
dispositionChange(ranges, new MessageDispositionAction()
{
public void performAction(MessageDispositionChangeListener listener)
{
- listener.onRelease();
+ listener.onRelease(setRedelivered);
}
});
}
@@ -350,7 +348,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
_transaction.rollback();
for(MessageDispositionChangeListener listener : _messageDispositionListenerMap.values())
{
- listener.onRelease();
+ listener.onRelease(true);
}
_messageDispositionListenerMap.clear();
@@ -698,4 +696,23 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
unregister(subscription_0_10);
}
}
+
+ public void flushCreditState()
+ {
+ final Collection<Subscription_0_10> subscriptions = getSubscriptions();
+ for (Subscription_0_10 subscription_0_10 : subscriptions)
+ {
+ subscription_0_10.flushCreditState(false);
+ }
+ }
+
+ public int getUnacknowledgedMessageCount()
+ {
+ return _messageDispositionListenerMap.size();
+ }
+
+ public boolean getBlocking()
+ {
+ return false; //TODO: Blocking not implemented on 0-10 yet.
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index c87919b478..a0dca53ed0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -100,6 +100,11 @@ public class ServerSessionDelegate extends SessionDelegate
{
private static final Logger LOGGER = Logger.getLogger(ServerSessionDelegate.class);
+ /**
+ * No-local queue argument is used to support the no-local feature of Durable Subscribers.
+ */
+ private static final String QUEUE_ARGUMENT_NO_LOCAL = "no-local";
+
public ServerSessionDelegate()
{
@@ -143,7 +148,7 @@ public class ServerSessionDelegate extends SessionDelegate
@Override
public void messageRelease(Session session, MessageRelease method)
{
- ((ServerSession)session).release(method.getTransfers());
+ ((ServerSession)session).release(method.getTransfers(), method.getSetRedelivered());
}
@Override
@@ -963,13 +968,10 @@ public class ServerSessionDelegate extends SessionDelegate
if(method.hasArguments() && method.getArguments() != null)
{
- if(method.getArguments().containsKey("no-local"))
+ if(method.getArguments().containsKey(QUEUE_ARGUMENT_NO_LOCAL))
{
- Object no_local = method.getArguments().get("no-local");
- if(no_local instanceof Boolean && ((Boolean)no_local))
- {
- queue.setNoLocal(true);
- }
+ Object noLocal = method.getArguments().get(QUEUE_ARGUMENT_NO_LOCAL);
+ queue.setNoLocal(convertBooleanValue(noLocal));
}
}
@@ -1079,6 +1081,30 @@ public class ServerSessionDelegate extends SessionDelegate
}
}
+ /**
+ * Converts a queue argument into a boolean value. For compatibility with the C++
+ * and the clients, accepts with Boolean, String, or Number types.
+ * @param argValue argument value.
+ *
+ * @return true if set
+ */
+ private boolean convertBooleanValue(Object argValue)
+ {
+ if(argValue instanceof Boolean && ((Boolean)argValue))
+ {
+ return true;
+ }
+ else if (argValue instanceof String && Boolean.parseBoolean((String)argValue))
+ {
+ return true;
+ }
+ else if (argValue instanceof Number && ((Number)argValue).intValue() != 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
protected AMQQueue createQueue(final String queueName,
final QueueDeclare body,
VirtualHost virtualHost,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
index 5c4fe0aab8..248b3b2143 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
@@ -26,11 +26,13 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionConfiguration;
import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionQueueConfiguration;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.plugins.logging.SlowConsumerDetectionMessages;
+import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin;
public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
@@ -56,7 +58,7 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
/**
* Configures the slow consumer disconnect plugin by adding a listener to each exchange on this
- * cirtual host to record all the configured queues in a cache for processing by the housekeeping
+ * virtual host to record all the configured queues in a cache for processing by the housekeeping
* thread.
*
* @see Plugin#configure(ConfigurationPlugin)
@@ -65,9 +67,10 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
_config = (SlowConsumerDetectionConfiguration) config;
_listener = new ConfiguredQueueBindingListener(getVirtualHost().getName());
- for (AMQShortString exchangeName : getVirtualHost().getExchangeRegistry().getExchangeNames())
+ final ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry();
+ for (AMQShortString exchangeName : exchangeRegistry.getExchangeNames())
{
- getVirtualHost().getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener);
+ exchangeRegistry.getExchange(exchangeName).addBindingListener(_listener);
}
}
@@ -87,11 +90,21 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
try
{
- SlowConsumerDetectionQueueConfiguration config =
+ final SlowConsumerDetectionQueueConfiguration config =
q.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName());
if (checkQueueStatus(q, config))
{
- config.getPolicy().performPolicy(q);
+ final SlowConsumerPolicyPlugin policy = config.getPolicy();
+ if (policy == null)
+ {
+ // We would only expect to see this during shutdown
+ _logger.warn("No slow consumer policy for queue " + q.getName());
+ }
+ else
+ {
+ policy.performPolicy(q);
+ }
+
}
}
catch (Exception e)
@@ -126,7 +139,10 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
if (config != null)
{
- _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config);
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config);
+ }
int count = q.getMessageCount();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
deleted file mode 100644
index 2c0ceed80b..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
+++ /dev/null
@@ -1,652 +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.tools.messagestore;
-
-import org.apache.commons.cli.Option;
-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.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;
-import org.apache.qpid.tools.messagestore.commands.Dump;
-import org.apache.qpid.tools.messagestore.commands.Help;
-import org.apache.qpid.tools.messagestore.commands.List;
-import org.apache.qpid.tools.messagestore.commands.Load;
-import org.apache.qpid.tools.messagestore.commands.Quit;
-import org.apache.qpid.tools.messagestore.commands.Select;
-import org.apache.qpid.tools.messagestore.commands.Show;
-import org.apache.qpid.tools.messagestore.commands.Move;
-import org.apache.qpid.tools.messagestore.commands.Purge;
-import org.apache.qpid.tools.utils.CommandParser;
-import org.apache.qpid.tools.utils.Console;
-import org.apache.qpid.tools.utils.SimpleCommandParser;
-import org.apache.qpid.tools.utils.SimpleConsole;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-/**
- * MessageStoreTool.
- */
-public class MessageStoreTool
-{
- /** Text outputted at the start of each console.*/
- private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances";
-
- /** I/O Wrapper. */
- protected Console _console;
-
- /** Batch mode flag. */
- protected boolean _batchMode;
-
- /** Internal State object. */
- private State _state = new State();
-
- private HashMap<String, Command> _commands = new HashMap<String, Command>();
-
- /** SLF4J Logger. */
- private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class);
-
- /** Loaded configuration file. */
- private Configuration _config;
-
- /** Control used for main run loop. */
- private boolean _running = true;
- private boolean _initialised = false;
-
- //---------------------------------------------------------------------------------------------------/
-
- public static void main(String[] args) throws Configuration.InitException
- {
-
- MessageStoreTool tool = new MessageStoreTool(args);
-
- tool.start();
- }
-
-
- public MessageStoreTool(String[] args) throws Configuration.InitException
- {
- this(args, System.in, System.out);
- }
-
- public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException
- {
- BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in));
- BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out));
-
- Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this)));
- _batchMode = false;
-
- _console = new SimpleConsole(consoleWriter, consoleReader);
-
- _config = new Configuration();
-
- setOptions();
- _config.processCommandline(args);
- }
-
-
- private void setOptions()
- {
- Option help = new Option("h", "help", false, "print this message");
- Option version = new Option("v", "version", false, "print the version information and exit");
- Option configFile =
- OptionBuilder.withArgName("file").hasArg()
- .withDescription("use given configuration file By "
- + "default looks for a file named "
- + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME)
- .withLongOpt("config")
- .create("c");
-
- _config.setOption(help);
- _config.setOption(version);
- _config.setOption(configFile);
- }
-
- public State getState()
- {
- return _state;
- }
-
- public Map<String, Command> getCommands()
- {
- return _commands;
- }
-
- public void setConfigurationFile(String configfile) throws Configuration.InitException
- {
- _config.loadConfig(new File(configfile));
- setup();
- }
-
- public Console getConsole()
- {
- return _console;
- }
-
- public void setConsole(Console console)
- {
- _console = console;
- }
-
- /**
- * Simple ShutdownHook to cleanly shutdown the databases
- */
- static class ShutdownHook implements Runnable
- {
- MessageStoreTool _tool;
-
- ShutdownHook(MessageStoreTool messageStoreTool)
- {
- _tool = messageStoreTool;
- }
-
- public void run()
- {
- _tool.quit();
- }
- }
-
- public void quit()
- {
- _running = false;
-
- if (_initialised)
- {
- ApplicationRegistry.remove();
- }
-
- _console.println("...exiting");
-
- _console.close();
- }
-
- public void setBatchMode(boolean batchmode)
- {
- _batchMode = batchmode;
- }
-
- /**
- * Main loop
- */
- protected void start()
- {
- setup();
-
- if (!_initialised)
- {
- System.exit(1);
- }
-
- _console.println("");
-
- _console.println(BOILER_PLATE);
-
- runCLI();
- }
-
- private void setup()
- {
- loadDefaultVirtualHosts();
-
- loadCommands();
-
- _state.clearAll();
- }
-
- private void loadCommands()
- {
- _commands.clear();
- //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands
- _commands.put("close", new Clear(this));
- _commands.put("copy", new Copy(this));
- _commands.put("dump", new Dump(this));
- _commands.put("help", new Help(this));
- _commands.put("list", new List(this));
- _commands.put("load", new Load(this));
- _commands.put("move", new Move(this));
- _commands.put("purge", new Purge(this));
- _commands.put("quit", new Quit(this));
- _commands.put("select", new Select(this));
- _commands.put("show", new Show(this));
- }
-
- private void loadDefaultVirtualHosts()
- {
- final File configFile = _config.getConfigFile();
-
- loadVirtualHosts(configFile);
- }
-
- private void loadVirtualHosts(File configFile)
- {
-
- if (!configFile.exists())
- {
- _devlog.error("Config file not found:" + configFile.getAbsolutePath());
- return;
- }
- else
- {
- _devlog.debug("using config file :" + configFile.getAbsolutePath());
- }
-
- try
- {
- ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile);
-
- ApplicationRegistry.remove();
-
- ApplicationRegistry.initialise(registry);
-
- checkMessageStores();
- _initialised = true;
- }
- catch (ConfigurationException e)
- {
- _console.println("Unable to load configuration due to configuration error: " + e.getMessage());
- e.printStackTrace();
- }
- catch (Exception e)
- {
- _console.println("Unable to load configuration due to: " + e.getMessage());
- e.printStackTrace();
- }
-
-
- }
-
- private void checkMessageStores()
- {
- Collection<VirtualHost> vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts();
-
- boolean warning = false;
- for (VirtualHost vhost : vhosts)
- {
- if (vhost.getMessageStore() instanceof MemoryMessageStore)
- {
- _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. "
- + "Changes will not persist.");
- warning = true;
- }
- }
-
- if (warning)
- {
- _console.println("");
- _console.println("Please ensure you are using the correct config file currently using '"
- + _config.getConfigFile().getAbsolutePath() + "'");
- _console.println("New config file can be specifed by 'load <config file>' or -c on the commandline.");
- _console.println("");
- }
- }
-
- private void runCLI()
- {
- while (_running)
- {
- if (!_batchMode)
- {
- printPrompt();
- }
-
- String[] args = _console.readCommand();
-
- while (args != null)
- {
- exec(args);
-
- if (_running)
- {
- if (!_batchMode)
- {
- printPrompt();
- }
-
- args = _console.readCommand();
- }
- }
- }
- }
-
- private void printPrompt()
- {
- _console.print(prompt());
- }
-
-
- /**
- * Execute a script (batch mode).
- *
- * @param script The file script
- */
- protected void runScripts(String script)
- {
- //Store Current State
- boolean oldBatch = _batchMode;
- CommandParser oldParser = _console.getCommandParser();
- setBatchMode(true);
-
- try
- {
- _devlog.debug("Running script '" + script + "'");
-
- _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script))));
-
- start();
- }
- catch (java.io.FileNotFoundException e)
- {
- _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage());
- }
-
- //Restore previous state
- _console.setCommandParser(oldParser);
- setBatchMode(oldBatch);
- }
-
- public String prompt()
- {
- String state = _state.toString();
- if (state != null && state.length() != 0)
- {
- return state + ":bdb$ ";
- }
- else
- {
- return "bdb$ ";
- }
- }
-
- /**
- * Execute the command.
- *
- * @param args [command, arg0, arg1...].
- */
- protected void exec(String[] args)
- {
- // Comment lines start with a #
- if (args.length == 0 || args[0].startsWith("#"))
- {
- return;
- }
-
- final String command = args[0];
-
- Command cmd = _commands.get(command);
-
- if (cmd == null)
- {
- _console.println("Command not understood: " + command);
- }
- else
- {
- cmd.execute(args);
- }
- }
-
-
- /**
- * Displays usage info.
- */
- protected static void help()
- {
- System.out.println(BOILER_PLATE);
- System.out.println("Usage: java " + MessageStoreTool.class + " [Options]");
- System.out.println(" [-c <broker config file>] : Defaults to \"$QPID_HOME/etc/config.xml\"");
- }
-
-
- /**
- * This class is used to store the current state of the tool.
- *
- * This is then interrogated by the various commands to augment their behaviour.
- *
- *
- */
- public static class State
- {
- private VirtualHost _vhost = null;
- private AMQQueue _queue = null;
- private Exchange _exchange = null;
- private java.util.List<Long> _msgids = null;
-
- public State()
- {
- }
-
- public void setQueue(AMQQueue queue)
- {
- _queue = queue;
- }
-
- public AMQQueue getQueue()
- {
- return _queue;
- }
-
- public void setVhost(VirtualHost vhost)
- {
- _vhost = vhost;
- }
-
- public VirtualHost getVhost()
- {
- return _vhost;
- }
-
- public Exchange getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(Exchange exchange)
- {
- _exchange = exchange;
- }
-
- public String toString()
- {
- StringBuilder status = new StringBuilder();
-
- if (_vhost != null)
- {
- status.append(_vhost.getName());
-
- if (_exchange != null)
- {
- status.append("[");
- status.append(_exchange.getNameShortString());
- status.append("]");
-
- if (_queue != null)
- {
- status.append("->'");
- status.append(_queue.getNameShortString());
- status.append("'");
-
- if (_msgids != null)
- {
- status.append(printMessages());
- }
- }
- }
- }
-
- return status.toString();
- }
-
-
- public String printMessages()
- {
- StringBuilder sb = new StringBuilder();
-
- Long previous = null;
-
- Long start = null;
- for (Long id : _msgids)
- {
- if (previous != null)
- {
- if (id == previous + 1)
- {
- if (start == null)
- {
- start = previous;
- }
- }
- else
- {
- if (start != null)
- {
- sb.append(",");
- sb.append(start);
- sb.append("-");
- sb.append(id);
- start = null;
- }
- else
- {
- sb.append(",");
- sb.append(previous);
- }
- }
- }
-
- previous = id;
- }
-
- if (start != null)
- {
- sb.append(",");
- sb.append(start);
- sb.append("-");
- sb.append(_msgids.get(_msgids.size() - 1));
- }
- else
- {
- sb.append(",");
- sb.append(previous);
- }
-
- // surround list in ()
- sb.replace(0, 1, "(");
- sb.append(")");
- return sb.toString();
- }
-
- public void clearAll()
- {
- _vhost = null;
- clearExchange();
- }
-
- public void clearExchange()
- {
- _exchange = null;
- clearQueue();
- }
-
- public void clearQueue()
- {
- _queue = null;
- clearMessages();
- }
-
- public void clearMessages()
- {
- _msgids = null;
- }
-
- /**
- * A common location to provide parsing of the message id string
- * utilised by a number of the commands.
- * The String is comma separated list of ids that can be individual ids
- * or a range (4-10)
- *
- * @param msgString string of msg ids to parse 1,2,4-10
- */
- public void setMessages(String msgString)
- {
- StringTokenizer tok = new StringTokenizer(msgString, ",");
-
- if (tok.hasMoreTokens())
- {
- _msgids = new LinkedList<Long>();
- }
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
- if (next.contains("-"))
- {
- Long start = Long.parseLong(next.substring(0, next.indexOf("-")));
- Long end = Long.parseLong(next.substring(next.indexOf("-") + 1));
-
- if (end >= start)
- {
- for (long l = start; l <= end; l++)
- {
- _msgids.add(l);
- }
- }
- }
- else
- {
- _msgids.add(Long.parseLong(next));
- }
- }
-
- }
-
- public void setMessages(java.util.List<Long> msgids)
- {
- _msgids = msgids;
- }
-
- public java.util.List<Long> getMessages()
- {
- return _msgids;
- }
- }//Class State
-
-}//Class MessageStoreTool
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java
deleted file mode 100644
index 5444197cb4..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java
+++ /dev/null
@@ -1,66 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-public abstract class AbstractCommand implements Command
-{
- protected Console _console;
- protected MessageStoreTool _tool;
-
- public AbstractCommand(MessageStoreTool tool)
- {
- _console = tool.getConsole();
- _tool = tool;
- }
-
- public void setOutput(Console out)
- {
- _console = out;
- }
-
- protected void commandError(String message, String[] args)
- {
- _console.print(getCommand() + " : " + message);
-
- if (args != null)
- {
- for (int i = 1; i < args.length; i++)
- {
- _console.print(args[i]);
- }
- }
- _console.println("");
- _console.println(help());
- }
-
-
- public abstract String help();
-
- public abstract String usage();
-
- public abstract String getCommand();
-
-
- public abstract void execute(String... args);
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java
deleted file mode 100644
index b0006b3fe6..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java
+++ /dev/null
@@ -1,85 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Clear extends AbstractCommand
-{
- public Clear(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Clears any selection.";
- }
-
- public String usage()
- {
- return "clear [ all | virtualhost | exchange | queue | msgs ]";
- }
-
- public String getCommand()
- {
- return "clear";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length < 1)
- {
- doClose("all");
- }
- else
- {
- doClose(args[1]);
- }
- }
-
- private void doClose(String type)
- {
- if (type.equals("virtualhost")
- || type.equals("all"))
- {
- _tool.getState().clearAll();
- }
-
- if (type.equals("exchange"))
- {
- _tool.getState().clearExchange();
- }
-
- if (type.equals("queue"))
- {
- _tool.getState().clearQueue();
- }
-
- if (type.equals("msgs"))
- {
- _tool.getState().clearMessages();
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java
deleted file mode 100644
index bfa775a34a..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java
+++ /dev/null
@@ -1,36 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.utils.Console;
-
-public interface Command
-{
- public void setOutput(Console out);
-
- public String help();
-
- public abstract String usage();
-
- String getCommand();
-
- public void execute(String... args);
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
deleted file mode 100644
index 348c95572d..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
+++ /dev/null
@@ -1,59 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.txn.ServerTransaction;
-import org.apache.qpid.server.txn.LocalTransaction;
-
-public class Copy extends Move
-{
- public Copy(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Copy messages between queues.";/*\n" +
- "The currently selected message set will be copied to the specifed queue.\n" +
- "Alternatively the values can be provided on the command line."; */
- }
-
- public String usage()
- {
- return "copy to=<queue> [from=<queue>] [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "copy";
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
- {
- ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
- fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getNameShortString().toString(), txn);
- txn.commit();
- }
-
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
deleted file mode 100644
index 8bb5d02b01..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
+++ /dev/null
@@ -1,305 +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.tools.messagestore.commands;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.qpid.server.queue.QueueEntryImpl;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.io.UnsupportedEncodingException;
-import java.util.LinkedList;
-import java.util.List;
-
-public class Dump extends Show
-{
- private static final int LINE_SIZE = 8;
- private static final String DEFAULT_ENCODING = "utf-8";
- private static final boolean SPACE_BYTES = true;
- private static final String BYTE_SPACER = " ";
- private static final String NON_PRINTING_ASCII_CHAR = "?";
-
- protected boolean _content = true;
-
- public Dump(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Dump selected message content. Default: show=content";
- }
-
- public String usage()
- {
- return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=<msgid e.g. 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "dump";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("show="))
- {
- _content = arg.contains("content") || arg.contains("all");
- }
- }
-
- parseArgs(args);
- }
-
- performShow();
- }
-
-
- protected List<List> createMessageData(java.util.List<Long> msgids, List<QueueEntry> messages, boolean showHeaders, boolean showRouting,
- boolean showMessageHeaders)
- {
-
- List<List> display = new LinkedList<List>();
-
- List<String> hex = new LinkedList<String>();
- List<String> ascii = new LinkedList<String>();
- display.add(hex);
- display.add(ascii);
-
- for (QueueEntry entry : messages)
- {
- ServerMessage msg = entry.getMessage();
- if (!includeMsg(msg, msgids))
- {
- continue;
- }
-
- //Add divider between messages
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
- // Show general message information
- hex.add(Show.Columns.ID.name());
- ascii.add(msg.getMessageNumber().toString());
-
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
- if (showRouting)
- {
- addShowInformation(hex, ascii, msg, "Routing Details", true, false, false);
- }
- if (showHeaders)
- {
- addShowInformation(hex, ascii, msg, "Headers", false, true, false);
- }
- if (showMessageHeaders)
- {
- addShowInformation(hex, ascii, msg, null, false, false, true);
- }
-
- // Add Content Body section
- hex.add("Content Body");
- ascii.add("");
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
-
- final int messageSize = (int) msg.getSize();
- if (messageSize != 0)
- {
- hex.add("Hex");
- hex.add(Console.ROW_DIVIDER);
-
-
- ascii.add("ASCII");
- ascii.add(Console.ROW_DIVIDER);
-
- java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024);
-
- int position = 0;
-
- while(position < messageSize)
- {
-
- position += msg.getContent(buf, position);
- buf.flip();
- //Duplicate so we don't destroy original data :)
- java.nio.ByteBuffer hexBuffer = buf;
-
- java.nio.ByteBuffer charBuffer = hexBuffer.duplicate();
-
- Hex hexencoder = new Hex();
-
- while (hexBuffer.hasRemaining())
- {
- byte[] line = new byte[LINE_SIZE];
-
- int bufsize = hexBuffer.remaining();
- if (bufsize < LINE_SIZE)
- {
- hexBuffer.get(line, 0, bufsize);
- }
- else
- {
- bufsize = line.length;
- hexBuffer.get(line);
- }
-
- byte[] encoded = hexencoder.encode(line);
-
- try
- {
- String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING);
- String hexLine = "";
-
- int strLength = encStr.length();
- for (int c = 0; c < strLength; c++)
- {
- hexLine += encStr.charAt(c);
-
- if ((c & 1) == 1 && SPACE_BYTES)
- {
- hexLine += BYTE_SPACER;
- }
- }
-
- hex.add(hexLine);
- }
- catch (UnsupportedEncodingException e)
- {
- _console.println(e.getMessage());
- return null;
- }
- }
-
- while (charBuffer.hasRemaining())
- {
- String asciiLine = "";
-
- for (int pos = 0; pos < LINE_SIZE; pos++)
- {
- if (charBuffer.hasRemaining())
- {
- byte ch = charBuffer.get();
-
- if (isPrintable(ch))
- {
- asciiLine += (char) ch;
- }
- else
- {
- asciiLine += NON_PRINTING_ASCII_CHAR;
- }
-
- if (SPACE_BYTES)
- {
- asciiLine += BYTE_SPACER;
- }
- }
- else
- {
- break;
- }
- }
-
- ascii.add(asciiLine);
- }
- buf.clear();
- }
- }
- else
- {
- List<String> result = new LinkedList<String>();
-
- display.add(result);
- result.add("No ContentBodies");
- }
- }
-
- // if hex is empty then we have no data to display
- if (hex.size() == 0)
- {
- return null;
- }
-
- return display;
- }
-
- private void addShowInformation(List<String> column1, List<String> column2, ServerMessage msg,
- String title, boolean routing, boolean headers, boolean messageHeaders)
- {
- List<QueueEntry> single = new LinkedList<QueueEntry>();
- single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE));
-
- List<List> routingData = super.createMessageData(null, single, headers, routing, messageHeaders);
-
- //Reformat data
- if (title != null)
- {
- column1.add(title);
- column2.add("");
- column1.add(Console.ROW_DIVIDER);
- column2.add(Console.ROW_DIVIDER);
- }
-
- // look at all columns in the routing Data
- for (List item : routingData)
- {
- // the item should be:
- // Title
- // *divider
- // value
- // otherwise we can't reason about the correct value
- if (item.size() == 3)
- {
- //Filter out the columns we are not interested in.
-
- String columnName = item.get(0).toString();
-
- if (!(columnName.equals(Show.Columns.ID.name())
- || columnName.equals(Show.Columns.Size.name())))
- {
- column1.add(columnName);
- column2.add(item.get(2).toString());
- }
- }
- }
- column1.add(Console.ROW_DIVIDER);
- column2.add(Console.ROW_DIVIDER);
- }
-
- private boolean isPrintable(byte c)
- {
- return c > 31 && c < 127;
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java
deleted file mode 100644
index 0f9546541b..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java
+++ /dev/null
@@ -1,98 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.LinkedList;
-import java.util.Map;
-
-public class Help extends AbstractCommand
-{
- public Help(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Provides detailed help on commands.";
- }
-
- public String getCommand()
- {
- return "help";
- }
-
- public String usage()
- {
- return "help [<command>]";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 1)
- {
- Command command = _tool.getCommands().get(args[1]);
- if (command != null)
- {
- _console.println(command.help());
- _console.println("Usage:" + command.usage());
- }
- else
- {
- commandError("Command not found: ", args);
- }
- }
- else
- {
- java.util.List<java.util.List> data = new LinkedList<java.util.List>();
-
- java.util.List<String> commandName = new LinkedList<String>();
- java.util.List<String> commandDescription = new LinkedList<String>();
-
- data.add(commandName);
- data.add(commandDescription);
-
- //Set up Headers
- commandName.add("Command");
- commandDescription.add("Description");
-
- commandName.add(Console.ROW_DIVIDER);
- commandDescription.add(Console.ROW_DIVIDER);
-
- //Add current Commands with descriptions
- Map<String, Command> commands = _tool.getCommands();
-
- for (Command command : commands.values())
- {
- commandName.add(command.getCommand());
- commandDescription.add(command.help());
- }
-
- _console.printMap("Available Commands", data);
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
deleted file mode 100644
index 3c4a0c8fac..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
+++ /dev/null
@@ -1,314 +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.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.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.Collection;
-import java.util.LinkedList;
-
-public class List extends AbstractCommand
-{
-
- public List(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public void setOutput(Console out)
- {
- _console = out;
- }
-
- public String help()
- {
- return "list available items.";
- }
-
- public String usage()
- {
- return "list queues [<exchange>] | exchanges | bindings [<exchange>] | all";
- }
-
- public String getCommand()
- {
- return "list";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 1)
- {
- if ((args[1].equals("exchanges"))
- || (args[1].equals("queues"))
- || (args[1].equals("bindings"))
- || (args[1].equals("all")))
- {
- if (args.length == 2)
- {
- doList(args[1]);
- }
- else if (args.length == 3)
- {
- doList(args[1], args[2]);
- }
- }
- else
- {
- commandError("Unknown options. ", args);
- }
- }
- else if (args.length < 2)
- {
- doList("all");
- }
- else
- {
- doList(args[1]);
- }
- }
-
- private void doList(String... listItem)
- {
- if (_tool.getState().getVhost() == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- listVirtualHosts();
- return;
- }
-
- VirtualHost vhost = _tool.getState().getVhost();
-
- java.util.List<String> data = null;
-
- if (listItem[0].equals("queues"))
- {
- if (listItem.length > 1)
- {
- data = listQueues(vhost, new AMQShortString(listItem[1]));
- }
- else
- {
- Exchange exchange = _tool.getState().getExchange();
- data = listQueues(vhost, exchange);
- }
- }
-
- if (listItem[0].equals("exchanges"))
- {
- data = listExchanges(vhost);
- }
-
- if (listItem[0].equals("bindings"))
- {
-
- if (listItem.length > 1)
- {
- data = listBindings(vhost, new AMQShortString(listItem[1]));
- }
- else
- {
- Exchange exchange = _tool.getState().getExchange();
-
- data = listBindings(vhost, exchange);
- }
- }
-
- if (data != null)
- {
- if (data.size() == 1)
- {
- _console.println("No '" + listItem[0] + "' to display,");
- }
- else
- {
- _console.displayList(true, data.toArray(new String[0]));
- }
- }
-
-
- if (listItem[0].equals("all"))
- {
-
- boolean displayed = false;
- Exchange exchange = _tool.getState().getExchange();
-
- //Do the display here for each one so that they are pretty printed
- data = listQueues(vhost, exchange);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
-
- if (exchange == null)
- {
- data = listExchanges(vhost);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
- }
-
- data = listBindings(vhost, exchange);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
-
- if (!displayed)
- {
- _console.println("Nothing to list");
- }
- }
- }
-
- private void listVirtualHosts()
- {
- Collection<VirtualHost> vhosts = ApplicationRegistry.getInstance()
- .getVirtualHostRegistry().getVirtualHosts();
-
- String[] data = new String[vhosts.size() + 1];
-
- data[0] = "Available VirtualHosts";
-
- int index = 1;
- for (VirtualHost vhost : vhosts)
- {
- data[index] = vhost.getName();
- index++;
- }
-
- _console.displayList(true, data);
- }
-
- private java.util.List<String> listBindings(VirtualHost vhost, AMQShortString exchangeName)
- {
- return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName));
- }
-
- private java.util.List<String> listBindings(VirtualHost vhost, Exchange exchange)
- {
- Collection<AMQShortString> queues = vhost.getQueueRegistry().getQueueNames();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Current Bindings");
-
- for (AMQShortString queue : queues)
- {
- if (exchange != null)
- {
- if (exchange.isBound(queue))
- {
- data.add(queue.toString());
- }
- }
- else
- {
- data.add(queue.toString());
- }
- }
-
- return data;
- }
-
- private java.util.List<String> listExchanges(VirtualHost vhost)
- {
- Collection<AMQShortString> queues = vhost.getExchangeRegistry().getExchangeNames();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Available Exchanges");
-
- for (AMQShortString queue : queues)
- {
- data.add(queue.toString());
- }
-
- return data;
- }
-
- private java.util.List<String> listQueues(VirtualHost vhost, AMQShortString exchangeName)
- {
- return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName));
- }
-
- private java.util.List<String> listQueues(VirtualHost vhost, Exchange exchange)
- {
- Collection<AMQQueue> queues = vhost.getQueueRegistry().getQueues();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Available Queues");
-
- for (AMQQueue queue : queues)
- {
- if (exchange != null)
- {
- if (exchange.isBound(queue))
- {
- data.add(queue.getNameShortString().toString());
- }
- }
- else
- {
- data.add(queue.getNameShortString().toString());
- }
- }
-
- if (exchange != null)
- {
- if (queues.size() == 1)
- {
- return null;
- }
- }
-
- return data;
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java
deleted file mode 100644
index 244a311c30..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java
+++ /dev/null
@@ -1,94 +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.tools.messagestore.commands;
-
-import org.apache.qpid.configuration.Configuration;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Load extends AbstractCommand
-{
- public Load(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Loads specified broker configuration file.";
- }
-
- public String usage()
- {
- return "load <configuration file>";
- }
-
- public String getCommand()
- {
- return "load";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 2)
- {
- _console.print("load " + args[1] + ": additional options not understood:");
- for (int i = 2; i < args.length; i++)
- {
- _console.print(args[i] + " ");
- }
- _console.println("");
- }
- else if (args.length < 2)
- {
- _console.println("Enter Configuration file.");
- String input = _console.readln();
- if (input != null)
- {
- doLoad(input);
- }
- else
- {
- _console.println("Did not recognise config file.");
- }
- }
- else
- {
- doLoad(args[1]);
- }
- }
-
- private void doLoad(String configfile)
- {
- _console.println("Loading Configuration:" + configfile);
-
- try
- {
- _tool.setConfigurationFile(configfile);
- }
- catch (Configuration.InitException e)
- {
- _console.println("Unable to open config file due to: '" + e.getMessage() + "'");
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
deleted file mode 100644
index 615f6ec1c2..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
+++ /dev/null
@@ -1,202 +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.tools.messagestore.commands;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.txn.ServerTransaction;
-import org.apache.qpid.server.txn.LocalTransaction;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class Move extends AbstractCommand
-{
-
- public Move(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Move messages between queues.";/*\n" +
- "The currently selected message set will be moved to the specifed queue.\n" +
- "Alternatively the values can be provided on the command line.";*/
- }
-
- public String usage()
- {
- return "move to=<queue> [from=<queue>] [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "move";
- }
-
- public void execute(String... args)
- {
- AMQQueue toQueue = null;
- AMQQueue fromQueue = _tool.getState().getQueue();
- java.util.List<Long> msgids = _tool.getState().getMessages();
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("to="))
- {
- String queueName = arg.substring(arg.indexOf("=") + 1);
- toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- }
-
- if (arg.startsWith("from="))
- {
- String queueName = arg.substring(arg.indexOf("=") + 1);
- fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- }
-
- if (arg.startsWith("msgids="))
- {
- String msgidStr = arg.substring(arg.indexOf("=") + 1);
-
- // Record the current message selection
- java.util.List<Long> currentIDs = _tool.getState().getMessages();
-
- // Use the ToolState class to perform the messasge parsing
- _tool.getState().setMessages(msgidStr);
- msgids = _tool.getState().getMessages();
-
- // Reset the original selection of messages
- _tool.getState().setMessages(currentIDs);
- }
- }
- }
-
- if (!checkRequirements(fromQueue, toQueue, msgids))
- {
- return;
- }
-
- processIDs(fromQueue, toQueue, msgids);
- }
-
- private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List<Long> msgids)
- {
- Long previous = null;
- Long start = null;
-
- if (msgids == null)
- {
- msgids = allMessageIDs(fromQueue);
- }
-
- if (msgids == null || msgids.size() == 0)
- {
- _console.println("No Messages to move.");
- return;
- }
-
- for (long id : msgids)
- {
- if (previous != null)
- {
- if (id == previous + 1)
- {
- if (start == null)
- {
- start = previous;
- }
- }
- else
- {
- if (start != null)
- {
- //move a range of ids
- doCommand(fromQueue, start, id, toQueue);
- start = null;
- }
- else
- {
- //move a single id
- doCommand(fromQueue, id, id, toQueue);
- }
- }
- }
-
- previous = id;
- }
-
- if (start != null)
- {
- //move a range of ids
- doCommand(fromQueue, start, previous, toQueue);
- }
- }
-
- private List<Long> allMessageIDs(AMQQueue fromQueue)
- {
- List<Long> ids = new LinkedList<Long>();
-
- if (fromQueue != null)
- {
- List<QueueEntry> messages = fromQueue.getMessagesOnTheQueue();
- if (messages != null)
- {
- for (QueueEntry msg : messages)
- {
- ids.add(msg.getMessage().getMessageNumber());
- }
- }
- }
-
- return ids;
- }
-
- protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List<Long> msgids)
- {
- if (toQueue == null)
- {
- _console.println("Destination queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- if (fromQueue == null)
- {
- _console.println("Source queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- return true;
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue)
- {
- ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
- fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getNameShortString().toString(), txn);
- txn.commit();
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
deleted file mode 100644
index 8df4afa2db..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
+++ /dev/null
@@ -1,67 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.server.queue.AMQQueue;
-
-public class Purge extends Move
-{
- public Purge(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Purge messages from a queue.\n" +
- "The currently selected message set will be purged from the specifed queue.\n" +
- "Alternatively the values can be provided on the command line.";
- }
-
- public String usage()
- {
- return "purge from=<queue> [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "purge";
- }
-
-
- protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List<Long> msgids)
- {
- if (fromQueue == null)
- {
- _console.println("Source queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- return true;
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
- {
- fromQueue.removeMessagesFromQueue(start, end);
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java
deleted file mode 100644
index a81bc07c38..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java
+++ /dev/null
@@ -1,54 +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.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Quit extends AbstractCommand
-{
- public Quit(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Quit the tool.";
- }
-
- public String usage()
- {
- return "quit";
- }
-
- public String getCommand()
- {
- return "quit";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals("quit");
-
- _tool.quit();
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
deleted file mode 100644
index ff59568374..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
+++ /dev/null
@@ -1,233 +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.tools.messagestore.commands;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-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;
-import java.util.StringTokenizer;
-
-public class Select extends AbstractCommand
-{
-
- public Select(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Perform a selection.";
- }
-
- public String usage()
- {
- return "select virtualhost <name> |exchange <name> |queue <name> | msg id=<msgids eg. 1,2,4-10>";
- }
-
- public String getCommand()
- {
- return "select";
- }
-
- public void execute(String... args)
- {
- assert args.length > 2;
- assert args[0].equals("select");
-
- if (args.length < 3)
- {
- if (args[1].equals("show"))
- {
- doSelect(args[1], null);
- }
- else
- {
- _console.print("select : unknown command:");
- _console.println(help());
- }
- }
- else
- {
- if (args[1].equals("virtualhost")
- || args[1].equals("vhost")
- || args[1].equals("exchange")
- || args[1].equals("queue")
- || args[1].equals("msg")
- )
- {
- doSelect(args[1], args[2]);
- }
- else
- {
- _console.println(help());
- }
- }
- }
-
- private void doSelect(String type, String item)
- {
- if (type.equals("virtualhost"))
- {
-
- VirtualHost vhost = ApplicationRegistry.getInstance()
- .getVirtualHostRegistry().getVirtualHost(item);
-
- if (vhost == null)
- {
- _console.println("Virtualhost '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setVhost(vhost);
- }
- }
-
- if (type.equals("exchange"))
- {
-
- VirtualHost vhost = _tool.getState().getVhost();
-
- if (vhost == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- return;
- }
-
-
- Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item));
-
- if (exchange == null)
- {
- _console.println("Exchange '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setExchange(exchange);
- }
-
- if (_tool.getState().getQueue() != null)
- {
- if (!exchange.isBound(_tool.getState().getQueue()))
- {
- _tool.getState().setQueue(null);
- }
- }
- }
-
- if (type.equals("queue"))
- {
- VirtualHost vhost = _tool.getState().getVhost();
-
- if (vhost == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- return;
- }
-
- AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item));
-
- if (queue == null)
- {
- _console.println("Queue '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setQueue(queue);
-
- if (_tool.getState().getExchange() == null)
- {
- for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames())
- {
- Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName);
- if (exchange.isBound(queue))
- {
- _tool.getState().setExchange(exchange);
- break;
- }
- }
- }
-
- //remove the message selection
- _tool.getState().setMessages((java.util.List<Long>) null);
- }
- }
-
- if (type.equals("msg"))
- {
- if (item.startsWith("id="))
- {
- StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ",");
-
- java.util.List<Long> msgids = null;
-
- if (tok.hasMoreTokens())
- {
- msgids = new LinkedList<Long>();
- }
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
- if (next.contains("-"))
- {
- Long start = Long.parseLong(next.substring(0, next.indexOf("-")));
- Long end = Long.parseLong(next.substring(next.indexOf("-") + 1));
-
- if (end >= start)
- {
- for (long l = start; l <= end; l++)
- {
- msgids.add(l);
- }
- }
- }
- else
- {
- msgids.add(Long.parseLong(next));
- }
- }
-
- _tool.getState().setMessages(msgids);
- }
-
- }
-
- if (type.equals("show"))
- {
- _console.println(_tool.getState().toString());
- if (_tool.getState().getMessages() != null)
- {
- _console.print("Msgs:");
- for (Long l : _tool.getState().getMessages())
- {
- _console.print(" " + l);
- }
- _console.println("");
- }
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
deleted file mode 100644
index 806e161bbc..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
+++ /dev/null
@@ -1,516 +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.tools.messagestore.commands;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.message.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class Show extends AbstractCommand
-{
- protected boolean _amqHeaders = false;
- protected boolean _routing = false;
- protected boolean _msgHeaders = false;
-
- public Show(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Shows the messages headers.";
- }
-
- public String usage()
- {
- return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=<msgid e.g. 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "show";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length < 2)
- {
- parseArgs("all");
- }
- else
- {
- parseArgs(args);
- }
-
- performShow();
- }
-
- protected void parseArgs(String... args)
- {
- List<Long> msgids = null;
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("show="))
- {
- _msgHeaders = arg.contains("msgheaders") || arg.contains("all");
- _amqHeaders = arg.contains("amqheaders") || arg.contains("all");
- _routing = arg.contains("routing") || arg.contains("all");
- }
-
- if (arg.startsWith("id="))
- {
- _tool.getState().setMessages(msgids);
- }
- }//for args
- }// if args > 2
- }
-
- protected void performShow()
- {
- if (_tool.getState().getVhost() == null)
- {
- _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first.");
- return;
- }
-
- AMQQueue _queue = _tool.getState().getQueue();
-
- List<Long> msgids = _tool.getState().getMessages();
-
- if (_queue != null)
- {
- List<QueueEntry> messages = _queue.getMessagesOnTheQueue();
- if (messages == null || messages.size() == 0)
- {
- _console.println("No messages on queue");
- return;
- }
-
- List<List> data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders);
- if (data != null)
- {
- _console.printMap(null, data);
- }
- else
- {
- String message = "No data to display.";
- if (msgids != null)
- {
- message += " Is message selection correct? " + _tool.getState().printMessages();
- }
- _console.println(message);
- }
-
- }
- else
- {
- _console.println("No Queue specified to show.");
- }
- }
-
- /**
- * Create the list data for display from the messages.
- *
- * @param msgids The list of message ids to display
- * @param messages A list of messages to format and display.
- * @param showHeaders should the header info be shown
- * @param showRouting show the routing info be shown
- * @param showMessageHeaders show the msg headers be shown
- * @return the formated data lists for printing
- */
- protected List<List> createMessageData(List<Long> msgids, List<QueueEntry> messages, boolean showHeaders, boolean showRouting,
- boolean showMessageHeaders)
- {
-
- // Currenly exposed message properties
-// //Printing the content Body
-// msg.getContentBodyIterator();
-// //Print the Headers
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageNumber();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId();
-//
-// //Print out all the property names
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames();
-//
-// msg.getMessageNumber();
-// msg.getSize();
-// msg.getArrivalTime();
-
-// msg.getDeliveredSubscription();
-// msg.getDeliveredToConsumer();
-// msg.getMessageHandle();
-// msg.getMessageNumber();
-// msg.getMessagePublishInfo();
-// msg.getPublisher();
-
-// msg.getStoreContext();
-// msg.isAllContentReceived();
-// msg.isPersistent();
-// msg.isRedelivered();
-// msg.isRejectedBy();
-// msg.isTaken();
-
- //Header setup
-
- List<List> data = new LinkedList<List>();
-
- List<String> id = new LinkedList<String>();
- data.add(id);
- id.add(Columns.ID.name());
- id.add(Console.ROW_DIVIDER);
-
- List<String> exchange = new LinkedList<String>();
- List<String> routingkey = new LinkedList<String>();
- List<String> immediate = new LinkedList<String>();
- List<String> mandatory = new LinkedList<String>();
- if (showRouting)
- {
- data.add(exchange);
- exchange.add(Columns.Exchange.name());
- exchange.add(Console.ROW_DIVIDER);
-
- data.add(routingkey);
- routingkey.add(Columns.RoutingKey.name());
- routingkey.add(Console.ROW_DIVIDER);
-
- data.add(immediate);
- immediate.add(Columns.isImmediate.name());
- immediate.add(Console.ROW_DIVIDER);
-
- data.add(mandatory);
- mandatory.add(Columns.isMandatory.name());
- mandatory.add(Console.ROW_DIVIDER);
- }
-
- List<String> size = new LinkedList<String>();
- List<String> appid = new LinkedList<String>();
- List<String> clusterid = new LinkedList<String>();
- List<String> contenttype = new LinkedList<String>();
- List<String> correlationid = new LinkedList<String>();
- List<String> deliverymode = new LinkedList<String>();
- List<String> encoding = new LinkedList<String>();
- List<String> arrival = new LinkedList<String>();
- List<String> expiration = new LinkedList<String>();
- List<String> priority = new LinkedList<String>();
- List<String> propertyflag = new LinkedList<String>();
- List<String> replyto = new LinkedList<String>();
- List<String> timestamp = new LinkedList<String>();
- List<String> type = new LinkedList<String>();
- List<String> userid = new LinkedList<String>();
- List<String> ispersitent = new LinkedList<String>();
- List<String> isredelivered = new LinkedList<String>();
- List<String> isdelivered = new LinkedList<String>();
-
- data.add(size);
- size.add(Columns.Size.name());
- size.add(Console.ROW_DIVIDER);
-
- if (showHeaders)
- {
- data.add(ispersitent);
- ispersitent.add(Columns.isPersistent.name());
- ispersitent.add(Console.ROW_DIVIDER);
-
- data.add(isredelivered);
- isredelivered.add(Columns.isRedelivered.name());
- isredelivered.add(Console.ROW_DIVIDER);
-
- data.add(isdelivered);
- isdelivered.add(Columns.isDelivered.name());
- isdelivered.add(Console.ROW_DIVIDER);
-
- data.add(appid);
- appid.add(Columns.App_ID.name());
- appid.add(Console.ROW_DIVIDER);
-
- data.add(clusterid);
- clusterid.add(Columns.Cluster_ID.name());
- clusterid.add(Console.ROW_DIVIDER);
-
- data.add(contenttype);
- contenttype.add(Columns.Content_Type.name());
- contenttype.add(Console.ROW_DIVIDER);
-
- data.add(correlationid);
- correlationid.add(Columns.Correlation_ID.name());
- correlationid.add(Console.ROW_DIVIDER);
-
- data.add(deliverymode);
- deliverymode.add(Columns.Delivery_Mode.name());
- deliverymode.add(Console.ROW_DIVIDER);
-
- data.add(encoding);
- encoding.add(Columns.Encoding.name());
- encoding.add(Console.ROW_DIVIDER);
-
- data.add(arrival);
- expiration.add(Columns.Arrival.name());
- expiration.add(Console.ROW_DIVIDER);
-
- data.add(expiration);
- expiration.add(Columns.Expiration.name());
- expiration.add(Console.ROW_DIVIDER);
-
- data.add(priority);
- priority.add(Columns.Priority.name());
- priority.add(Console.ROW_DIVIDER);
-
- data.add(propertyflag);
- propertyflag.add(Columns.Property_Flag.name());
- propertyflag.add(Console.ROW_DIVIDER);
-
- data.add(replyto);
- replyto.add(Columns.ReplyTo.name());
- replyto.add(Console.ROW_DIVIDER);
-
- data.add(timestamp);
- timestamp.add(Columns.Timestamp.name());
- timestamp.add(Console.ROW_DIVIDER);
-
- data.add(type);
- type.add(Columns.Type.name());
- type.add(Console.ROW_DIVIDER);
-
- data.add(userid);
- userid.add(Columns.UserID.name());
- userid.add(Console.ROW_DIVIDER);
- }
-
- List<String> msgHeaders = new LinkedList<String>();
- if (showMessageHeaders)
- {
- data.add(msgHeaders);
- msgHeaders.add(Columns.MsgHeaders.name());
- msgHeaders.add(Console.ROW_DIVIDER);
- }
-
- //Add create the table of data
- for (QueueEntry entry : messages)
- {
- ServerMessage msg = entry.getMessage();
- if (!includeMsg(msg, msgids))
- {
- continue;
- }
-
- id.add(msg.getMessageNumber().toString());
-
- size.add("" + msg.getSize());
-
- arrival.add("" + msg.getArrivalTime());
-
- ispersitent.add(msg.isPersistent() ? "true" : "false");
-
-
- isredelivered.add(entry.isRedelivered() ? "true" : "false");
-
- isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false");
-
-// msg.getMessageHandle();
-
- BasicContentHeaderProperties headers = null;
-
- try
- {
- if(msg instanceof AMQMessage)
- {
- headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().getProperties());
- }
- }
- catch (AMQException e)
- {
- //ignore
-// commandError("Unable to read properties for message: " + e.getMessage(), null);
- }
-
- if (headers != null)
- {
- String appidS = headers.getAppIdAsString();
- appid.add(appidS == null ? "null" : appidS);
-
- String clusterS = headers.getClusterIdAsString();
- clusterid.add(clusterS == null ? "null" : clusterS);
-
- String contentS = headers.getContentTypeAsString();
- contenttype.add(contentS == null ? "null" : contentS);
-
- String correlationS = headers.getCorrelationIdAsString();
- correlationid.add(correlationS == null ? "null" : correlationS);
-
- deliverymode.add("" + headers.getDeliveryMode());
-
- AMQShortString encodeSS = headers.getEncoding();
- encoding.add(encodeSS == null ? "null" : encodeSS.toString());
-
- expiration.add("" + headers.getExpiration());
-
- FieldTable headerFT = headers.getHeaders();
- msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString());
-
- priority.add("" + headers.getPriority());
- propertyflag.add("" + headers.getPropertyFlags());
-
- AMQShortString replytoSS = headers.getReplyTo();
- replyto.add(replytoSS == null ? "null" : replytoSS.toString());
-
- timestamp.add("" + headers.getTimestamp());
-
- AMQShortString typeSS = headers.getType();
- type.add(typeSS == null ? "null" : typeSS.toString());
-
- AMQShortString useridSS = headers.getUserId();
- userid.add(useridSS == null ? "null" : useridSS.toString());
-
- MessagePublishInfo info = null;
- try
- {
- if(msg instanceof AMQMessage)
- {
- info = ((AMQMessage)msg).getMessagePublishInfo();
- }
-
- }
- catch (AMQException e)
- {
- //ignore
- }
-
- if (info != null)
- {
- AMQShortString exchangeSS = info.getExchange();
- exchange.add(exchangeSS == null ? "null" : exchangeSS.toString());
-
- AMQShortString routingkeySS = info.getRoutingKey();
- routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString());
-
- immediate.add(info.isImmediate() ? "true" : "false");
- mandatory.add(info.isMandatory() ? "true" : "false");
- }
-
-// msg.getPublisher(); -- only used in clustering
-// msg.getStoreContext();
-// msg.isAllContentReceived();
-
- }// if headers!=null
-
-// need to access internal map and do lookups.
-// msg.isTaken();
-// msg.getDeliveredSubscription();
-// msg.isRejectedBy();
-
- }
-
- // if id only had the header and the divider in it then we have no data to display
- if (id.size() == 2)
- {
- return null;
- }
- return data;
- }
-
- protected boolean includeMsg(ServerMessage msg, List<Long> msgids)
- {
- if (msgids == null)
- {
- return true;
- }
-
- Long msgid = msg.getMessageNumber();
-
- boolean found = false;
-
- if (msgids != null)
- {
- //check msgid is in msgids
- for (Long l : msgids)
- {
- if (l.equals(msgid))
- {
- found = true;
- break;
- }
- }
- }
- return found;
- }
-
- public enum Columns
- {
- ID,
- Size,
- Exchange,
- RoutingKey,
- isImmediate,
- isMandatory,
- isPersistent,
- isRedelivered,
- isDelivered,
- App_ID,
- Cluster_ID,
- Content_Type,
- Correlation_ID,
- Delivery_Mode,
- Encoding,
- Arrival,
- Expiration,
- Priority,
- Property_Flag,
- ReplyTo,
- Timestamp,
- Type,
- UserID,
- MsgHeaders
- }
-}
-
-
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
index c27c52eb8e..bfcdbe7460 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
@@ -60,9 +60,6 @@ public class Passwd
private static void output(String user, byte[] encoded) throws IOException
{
-
-// File passwdFile = new File("qpid.passwd");
-
PrintStream ps = new PrintStream(System.out);
user += ":";
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java
deleted file mode 100644
index 986fea32cc..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java
+++ /dev/null
@@ -1,51 +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.tools.utils;
-
-public interface CommandParser
-{
- /**
- * If there is more than one command received on the last parse request.
- *
- * Subsequent calls to parse will utilise this input rather than reading new data from the input source
- * @return boolean
- */
- boolean more();
-
- /**
- * True if the currently parsed command has been requested as a background operation
- *
- * @return boolean
- */
- boolean isBackground();
-
- /**
- * Parses user commands, and groups tokens in the
- * String[] format that all Java main's love.
- *
- * If more than one command is provided in one input line then the more() method will return true.
- * A subsequent call to parse() will continue to parse that input line before reading new input.
- *
- * @return <code>input</code> split in args[] format; null if eof.
- * @throws java.io.IOException if there is a problem reading from the input stream
- */
- String[] parse() throws java.io.IOException;
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java
deleted file mode 100644
index cf457d1ea5..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java
+++ /dev/null
@@ -1,90 +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.tools.utils;
-
-import java.util.List;
-
-public interface Console
-{
- public enum CellFormat
- {
- CENTRED, LEFT, RIGHT
- }
-
- public static String ROW_DIVIDER = "*divider";
-
- public void print(String... message);
-
- public void println(String... message);
-
- public String readln();
-
- /**
- * Reads and parses the command line.
- *
- *
- * @return The next command or null
- */
- public String[] readCommand();
-
- public CommandParser getCommandParser();
-
- public void setCommandParser(CommandParser parser);
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +-------------+
- * | Heading |
- * +-------------+
- * | Item 1 |
- * | Item 2 |
- * | Item 3 |
- * +-------------+
- *
- * @param hasTitle should list[0] be used as a heading
- * @param list The list of Strings to display
- */
- public void displayList(boolean hasTitle, String... list);
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +----------------------------+
- * | Heading |
- * +----------------------------+
- * | title | title | ..
- * +----------------------------+
- * | Item 2 | value 2 | ..
- * +----------------------------+ (*divider)
- * | Item 3 | value 2 | ..
- * +----------------------------+
- *
- * @param title The title to display if any
- * @param entries the entries to display in a map.
- */
- void printMap(String title, List<List> entries);
-
-
- public void close();
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java
deleted file mode 100644
index 09444ccdd7..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java
+++ /dev/null
@@ -1,121 +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.tools.utils;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.util.StringTokenizer;
-
-public class SimpleCommandParser implements CommandParser
-{
- private static final String COMMAND_SEPERATOR = ";";
-
- /** Input source of commands */
- protected BufferedReader _reader;
-
- /** The next list of commands from the command line */
- private StringBuilder _nextCommand = null;
-
- public SimpleCommandParser(BufferedReader reader)
- {
- _reader = reader;
- }
-
- public boolean more()
- {
- return _nextCommand != null;
- }
-
- public boolean isBackground()
- {
- return false;
- }
-
- public String[] parse() throws IOException
- {
- String[] commands = null;
-
- String input = null;
-
- if (_nextCommand == null)
- {
- input = _reader.readLine();
- }
- else
- {
- input = _nextCommand.toString();
- _nextCommand = null;
- }
-
- if (input == null)
- {
- return null;
- }
-
- StringTokenizer tok = new StringTokenizer(input, " ");
-
- int tokenCount = tok.countTokens();
- int index = 0;
-
- if (tokenCount > 0)
- {
- commands = new String[tokenCount];
- boolean commandComplete = false;
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
-
- if (next.equals(COMMAND_SEPERATOR))
- {
- commandComplete = true;
- _nextCommand = new StringBuilder();
- continue;
- }
-
- if (commandComplete)
- {
- _nextCommand.append(next);
- _nextCommand.append(" ");
- }
- else
- {
- commands[index] = next;
- index++;
- }
- }
-
- }
-
- //Reduce the String[] if not all the tokens were used in this command.
- // i.e. there is more than one command on the line.
- if (index != tokenCount)
- {
- String[] shortCommands = new String[index];
- System.arraycopy(commands, 0, shortCommands, 0, index);
- return shortCommands;
- }
- else
- {
- return commands;
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java
deleted file mode 100644
index 2791a39f92..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java
+++ /dev/null
@@ -1,364 +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.tools.utils;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-public class SimpleConsole implements Console
-{
- /** SLF4J Logger. */
- private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class);
-
- /** Console Writer. */
- protected BufferedWriter _consoleWriter;
-
- /** Console Reader. */
- protected BufferedReader _consoleReader;
-
- /** Parser for command-line input. */
- protected CommandParser _parser;
-
- public SimpleConsole(BufferedWriter writer, BufferedReader reader)
- {
- _consoleWriter = writer;
- _consoleReader = reader;
- _parser = new SimpleCommandParser(_consoleReader);
- }
-
- public void print(String... message)
- {
- try
- {
- for (String s : message)
- {
- _consoleWriter.write(s);
- }
- _consoleWriter.flush();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occurred whilst trying to write:" + Arrays.asList(message));
- }
-
- }
-
- public void println(String... message)
- {
- print(message);
- print(System.getProperty("line.separator"));
- }
-
-
- public String readln()
- {
- try
- {
- return _consoleReader.readLine();
- }
- catch (IOException e)
- {
- _devlog.debug("Unable to read input due to:" + e.getMessage());
- return null;
- }
- }
-
- public String[] readCommand()
- {
- try
- {
- return _parser.parse();
- }
- catch (IOException e)
- {
- _devlog.error("Error reading command:" + e.getMessage());
- return new String[0];
- }
- }
-
- public CommandParser getCommandParser()
- {
- return _parser;
- }
-
- public void setCommandParser(CommandParser parser)
- {
- _parser = parser;
- }
-
- public void displayList(boolean hasTitle, String... list)
- {
- java.util.List<java.util.List> data = new LinkedList<List>();
-
- java.util.List<String> values = new LinkedList<String>();
-
- data.add(values);
-
- for (String value : list)
- {
- values.add(value);
- }
-
- if (hasTitle)
- {
- values.add(1, "*divider");
- }
-
- printMap(null, data);
- }
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +----------------------------+
- * | Heading |
- * +----------------------------+
- * | title | title | ..
- * +----------------------------+
- * | Item 2 | value 2 | ..
- * | Item 3 | value 2 | ..
- * +----------------------------+
- *
- * @param title The title to display if any
- * @param entries the entries to display in a map.
- */
- public void printMap(String title, java.util.List<java.util.List> entries)
- {
- try
- {
- int columns = entries.size();
-
- int[] columnWidth = new int[columns];
-
- // calculate row count
- int rowMax = 0;
-
- //the longest item
- int itemMax = 0;
-
- for (int i = 0; i < columns; i++)
- {
- int columnIRowMax = entries.get(i).size();
-
- if (columnIRowMax > rowMax)
- {
- rowMax = columnIRowMax;
- }
- for (Object values : entries.get(i))
- {
- if (values.toString().equals(Console.ROW_DIVIDER))
- {
- continue;
- }
-
- int itemLength = values.toString().length();
-
- //note for single width
- if (itemLength > itemMax)
- {
- itemMax = itemLength;
- }
-
- //note for mulit width
- if (itemLength > columnWidth[i])
- {
- columnWidth[i] = itemLength;
- }
-
- }
- }
-
- int tableWidth = 0;
-
-
- for (int i = 0; i < columns; i++)
- {
- // plus 2 for the space padding
- columnWidth[i] += 2;
- }
- for (int size : columnWidth)
- {
- tableWidth += size;
- }
- tableWidth += (columns - 1);
-
- if (title != null)
- {
- if (title.length() > tableWidth)
- {
- tableWidth = title.length();
- }
-
- printCellRow("+", "-", tableWidth);
-
- printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0);
- _consoleWriter.newLine();
-
- }
-
- //put top line | or bottom of title
- printCellRow("+", "-", tableWidth);
-
- //print the table data
- int row = 0;
-
- for (; row < rowMax; row++)
- {
- for (int i = 0; i < columns; i++)
- {
- java.util.List columnData = entries.get(i);
-
- String value;
- // does this column have a value for this row
- if (columnData.size() > row)
- {
- value = " " + columnData.get(row).toString() + " ";
- }
- else
- {
- value = " ";
- }
-
- if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " "))
- {
- printCellRow("+", "-", tableWidth);
- //move on to the next row
- break;
- }
- else
- {
- printCell(CellFormat.LEFT, "|", columnWidth[i], value, i);
- }
-
- // if it is the last row then do a new line.
- if (i == columns - 1)
- {
- _consoleWriter.newLine();
- }
- }
- }
-
- printCellRow("+", "-", tableWidth);
-
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to write.");
- }
- }
-
- public void close()
- {
-
- try
- {
- _consoleReader.close();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to close reader.");
- }
-
- try
- {
-
- _consoleWriter.close();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to close writer.");
- }
-
- }
-
- private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException
- {
- int pad = cellWidth - cell.length();
-
- if (column == 0)
- {
- _consoleWriter.write(edge);
- }
-
- switch (format)
- {
- case CENTRED:
- printPad(" ", pad / 2);
- break;
- case RIGHT:
- printPad(" ", pad);
- break;
- }
-
- _consoleWriter.write(cell);
-
-
- switch (format)
- {
- case CENTRED:
- // if pad isn't even put the extra one on the right
- if (pad % 2 == 0)
- {
- printPad(" ", pad / 2);
- }
- else
- {
- printPad(" ", (pad / 2) + 1);
- }
- break;
- case LEFT:
- printPad(" ", pad);
- break;
- }
-
-
- _consoleWriter.write(edge);
-
- }
-
- private void printCellRow(String edge, String mid, int cellWidth) throws IOException
- {
- _consoleWriter.write(edge);
-
- printPad(mid, cellWidth);
-
- _consoleWriter.write(edge);
- _consoleWriter.newLine();
- }
-
- private void printPad(String padChar, int count) throws IOException
- {
- for (int i = 0; i < count; i++)
- {
- _consoleWriter.write(padChar);
- }
- }
-
-
-}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
index 6c135e8ba7..7d128f2bc5 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
@@ -20,18 +20,31 @@
*/
package org.apache.qpid.server;
-import junit.framework.TestCase;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.configuration.XMLConfiguration;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.logging.SystemOutMessageLogger;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.queue.AMQPriorityQueue;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.util.TestApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHostImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.test.utils.QpidTestCase;
-public class AMQBrokerManagerMBeanTest extends InternalBrokerBaseCase
+public class AMQBrokerManagerMBeanTest extends QpidTestCase
{
private QueueRegistry _queueRegistry;
private ExchangeRegistry _exchangeRegistry;
@@ -81,14 +94,100 @@ public class AMQBrokerManagerMBeanTest extends InternalBrokerBaseCase
assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
}
+ public void testCreateNewQueueBindsToDefaultExchange() throws Exception
+ {
+ String queueName = "testQueue_" + System.currentTimeMillis();
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject());
+ ExchangeRegistry exReg = _vHost.getExchangeRegistry();
+ Exchange defaultExchange = exReg.getDefaultExchange();
+
+ mbean.createNewQueue(queueName, "test", false);
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null);
+
+ assertTrue("New queue should be bound to default exchange", defaultExchange.isBound(new AMQShortString(queueName)));
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument does cause the
+ * maximum delivery count to be set on the Queue.
+ */
+ public void testCreateNewQueueWithMaximumDeliveryCount() throws Exception
+ {
+ final Map<String,Object> args = new HashMap<String, Object>();
+ args.put(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, 5);
+
+ final AMQShortString queueName = new AMQShortString("testCreateNewQueueWithMaximumDeliveryCount");
+
+ final QueueRegistry qReg = _vHost.getQueueRegistry();
+
+ assertNull("The queue should not yet exist", qReg.getQueue(queueName));
+
+ final ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject());
+ mbean.createNewQueue(queueName.asString(), "test", false, args);
+
+ final AMQQueue createdQueue = qReg.getQueue(queueName);
+ assertNotNull("The queue was not registered as expected", createdQueue);
+ assertEquals("Unexpected maximum delivery count", 5, createdQueue.getMaximumDeliveryCount());
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_PRIORITIES} argument prompts creation of
+ * a Priority Queue.
+ */
+ public void testCreatePriorityQueue() throws Exception
+ {
+ int numPriorities = 7;
+ Map<String,Object> args = new HashMap<String, Object>();
+ args.put(AMQQueueFactory.X_QPID_PRIORITIES, numPriorities);
+
+ AMQShortString queueName = new AMQShortString("testCreatePriorityQueue");
+
+ QueueRegistry qReg = _vHost.getQueueRegistry();
+
+ assertNull("The queue should not yet exist", qReg.getQueue(queueName));
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject());
+ mbean.createNewQueue(queueName.asString(), "test", false, args);
+
+ AMQQueue queue = qReg.getQueue(queueName);
+ assertEquals("Queue is not a priorty queue", AMQPriorityQueue.class, queue.getClass());
+ assertEquals("Number of priorities supported was not as expected", numPriorities, ((AMQPriorityQueue)queue).getPriorities());
+ }
+
@Override
public void setUp() throws Exception
{
super.setUp();
+
+ CurrentActor.set(new TestLogActor(new SystemOutMessageLogger()));
+
+ XMLConfiguration configXml = new XMLConfiguration();
+ configXml.addProperty("virtualhosts.virtualhost(-1).name", "test");
+ configXml.addProperty("virtualhosts.virtualhost(-1).test.store.class", TestableMemoryMessageStore.class.getName());
+
+ ServerConfiguration configuration = new ServerConfiguration(configXml);
+
+ ApplicationRegistry registry = new TestApplicationRegistry(configuration);
+ ApplicationRegistry.initialise(registry);
+ registry.getVirtualHostRegistry().setDefaultVirtualHostName("test");
+
IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
_vHost = appRegistry.getVirtualHostRegistry().getVirtualHost("test");
_queueRegistry = _vHost.getQueueRegistry();
_exchangeRegistry = _vHost.getExchangeRegistry();
}
+ @Override
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ ApplicationRegistry.remove();
+ }
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
index 9b0ae82b84..eea8e173f4 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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;
import java.util.EnumSet;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/MockConnectionConfig.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/MockConnectionConfig.java
new file mode 100644
index 0000000000..73e0bc5d27
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/MockConnectionConfig.java
@@ -0,0 +1,151 @@
+package org.apache.qpid.server.configuration;
+
+import java.util.UUID;
+
+public class MockConnectionConfig implements ConnectionConfig
+{
+
+ public MockConnectionConfig(UUID _id, ConnectionConfigType _configType,
+ ConfiguredObject<ConnectionConfigType, ConnectionConfig> _parent, boolean _durable,
+ long _createTime, VirtualHostConfig _virtualHost, String _address, Boolean _incoming,
+ Boolean _systemConnection, Boolean _federationLink, String _authId, String _remoteProcessName,
+ Integer _remotePID, Integer _remoteParentPID, ConfigStore _configStore, Boolean _shadow)
+ {
+ super();
+ this._id = _id;
+ this._configType = _configType;
+ this._parent = _parent;
+ this._durable = _durable;
+ this._createTime = _createTime;
+ this._virtualHost = _virtualHost;
+ this._address = _address;
+ this._incoming = _incoming;
+ this._systemConnection = _systemConnection;
+ this._federationLink = _federationLink;
+ this._authId = _authId;
+ this._remoteProcessName = _remoteProcessName;
+ this._remotePID = _remotePID;
+ this._remoteParentPID = _remoteParentPID;
+ this._configStore = _configStore;
+ this._shadow = _shadow;
+ }
+
+ private UUID _id;
+ private ConnectionConfigType _configType;
+ private ConfiguredObject<ConnectionConfigType, ConnectionConfig> _parent;
+ private boolean _durable;
+ private long _createTime;
+ private VirtualHostConfig _virtualHost;
+ private String _address;
+ private Boolean _incoming;
+ private Boolean _systemConnection;
+ private Boolean _federationLink;
+ private String _authId;
+ private String _remoteProcessName;
+ private Integer _remotePID;
+ private Integer _remoteParentPID;
+ private ConfigStore _configStore;
+ private Boolean _shadow;
+
+ @Override
+ public UUID getId()
+ {
+ return _id;
+ }
+
+ @Override
+ public ConnectionConfigType getConfigType()
+ {
+ return _configType;
+ }
+
+ @Override
+ public ConfiguredObject<ConnectionConfigType, ConnectionConfig> getParent()
+ {
+ return _parent;
+ }
+
+ @Override
+ public boolean isDurable()
+ {
+ return _durable;
+ }
+
+ @Override
+ public long getCreateTime()
+ {
+ return _createTime;
+ }
+
+ @Override
+ public VirtualHostConfig getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+ @Override
+ public String getAddress()
+ {
+ return _address;
+ }
+
+ @Override
+ public Boolean isIncoming()
+ {
+ return _incoming;
+ }
+
+ @Override
+ public Boolean isSystemConnection()
+ {
+ return _systemConnection;
+ }
+
+ @Override
+ public Boolean isFederationLink()
+ {
+ return _federationLink;
+ }
+
+ @Override
+ public String getAuthId()
+ {
+ return _authId;
+ }
+
+ @Override
+ public String getRemoteProcessName()
+ {
+ return _remoteProcessName;
+ }
+
+ @Override
+ public Integer getRemotePID()
+ {
+ return _remotePID;
+ }
+
+ @Override
+ public Integer getRemoteParentPID()
+ {
+ return _remoteParentPID;
+ }
+
+ @Override
+ public ConfigStore getConfigStore()
+ {
+ return _configStore;
+ }
+
+ @Override
+ public Boolean isShadow()
+ {
+ return _shadow;
+ }
+
+ @Override
+ public void mgmtClose()
+ {
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
index d2f2ae5eea..e1a5e7d338 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
@@ -24,6 +24,8 @@ import junit.framework.TestCase;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.util.TestApplicationRegistry;
public class QueueConfigurationTest extends TestCase
{
@@ -43,11 +45,71 @@ public class QueueConfigurationTest extends TestCase
fullEnv.setProperty("queues.maximumMessageSize", 1);
fullEnv.setProperty("queues.maximumMessageCount", 1);
fullEnv.setProperty("queues.minimumAlertRepeatGap", 1);
+ fullEnv.setProperty("queues.deadLetterQueues", true);
+ fullEnv.setProperty("queues.maximumDeliveryCount", 5);
_fullHostConf = new VirtualHostConfiguration("test", fullEnv);
}
+ public void testMaxDeliveryCount() throws Exception
+ {
+ try
+ {
+ ApplicationRegistry registry = new TestApplicationRegistry(new ServerConfiguration(_env));
+ ApplicationRegistry.initialise(registry);
+
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _emptyConf);
+ assertEquals("Unexpected default server configuration for max delivery count ", 0, qConf.getMaxDeliveryCount());
+
+ // Check explicit value
+ VirtualHostConfiguration vhostConfig = overrideConfiguration("maximumDeliveryCount", 7);
+ qConf = new QueueConfiguration("test", vhostConfig);
+ assertEquals("Unexpected host configuration for max delivery count", 7, qConf.getMaxDeliveryCount());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _fullHostConf);
+ assertEquals("Unexpected queue configuration for max delivery count", 5, qConf.getMaxDeliveryCount());
+
+ }
+ finally
+ {
+ ApplicationRegistry.remove();
+ }
+ }
+
+ /**
+ * Tests that the default setting for DLQ configuration is disabled, and verifies that it can be overridden
+ * at a broker or virtualhost level.
+ * @throws Exception
+ */
+ public void testIsDeadLetterQueueEnabled() throws Exception
+ {
+ try
+ {
+ ApplicationRegistry registry = new TestApplicationRegistry(new ServerConfiguration(_env));
+ ApplicationRegistry.initialise(registry);
+
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _emptyConf);
+ assertFalse("Unexpected queue configuration for dead letter enabled attribute", qConf.isDeadLetterQueueEnabled());
+
+ // Check explicit value
+ VirtualHostConfiguration vhostConfig = overrideConfiguration("deadLetterQueues", true);
+ qConf = new QueueConfiguration("test", vhostConfig);
+ assertTrue("Unexpected queue configuration for dead letter enabled attribute", qConf.isDeadLetterQueueEnabled());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _fullHostConf);
+ assertTrue("Unexpected queue configuration for dead letter enabled attribute", qConf.isDeadLetterQueueEnabled());
+ }
+ finally
+ {
+ ApplicationRegistry.remove();
+ }
+ }
+
public void testGetMaximumMessageAge() throws ConfigurationException
{
// Check default value
@@ -129,7 +191,19 @@ public class QueueConfigurationTest extends TestCase
assertEquals(1, qConf.getMinimumAlertRepeatGap());
}
- private VirtualHostConfiguration overrideConfiguration(String property, int value)
+ public void testSortQueueConfiguration() throws ConfigurationException
+ {
+ //Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _emptyConf);
+ assertNull(qConf.getQueueSortKey());
+
+ // Check explicit value
+ final VirtualHostConfiguration vhostConfig = overrideConfiguration("sortKey", "test-sort-key");
+ qConf = new QueueConfiguration("test", vhostConfig);
+ assertEquals("test-sort-key", qConf.getQueueSortKey());
+ }
+
+ private VirtualHostConfiguration overrideConfiguration(String property, Object value)
throws ConfigurationException
{
PropertiesConfiguration queueConfig = new PropertiesConfiguration();
@@ -141,5 +215,4 @@ public class QueueConfigurationTest extends TestCase
return new VirtualHostConfiguration("test", config);
}
-
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
index 9afd2a45a9..7739f9976e 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -25,6 +25,7 @@ import static org.apache.qpid.transport.ConnectionSettings.WILDCARD_ADDRESS;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.Writer;
import java.util.Locale;
import org.apache.commons.configuration.ConfigurationException;
@@ -303,6 +304,18 @@ public class ServerConfigurationTest extends QpidTestCase
assertEquals(false, _serverConfig.getManagementEnabled());
}
+ public void testGetManagementRightsInferAllAccess() throws Exception
+ {
+ _serverConfig.initialise();
+
+ //check default
+ assertTrue("default should be true", _serverConfig.getManagementRightsInferAllAccess());
+
+ //update it
+ _config.setProperty("management.managementRightsInferAllAccess", "false");
+ assertFalse("New value should be false", _serverConfig.getManagementRightsInferAllAccess());
+ }
+
public void testGetHeartBeatDelay() throws ConfigurationException
{
// Check default
@@ -1447,4 +1460,117 @@ public class ServerConfigurationTest extends QpidTestCase
ce.getMessage());
}
}
+
+ public void testMaxDeliveryCountDefault() throws Exception
+ {
+ final ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaxDeliveryCount());
+ }
+
+ public void testMaxDeliveryCount() throws Exception
+ {
+ _config.setProperty("maximumDeliveryCount", 5);
+ final ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(5, serverConfig.getMaxDeliveryCount());
+ }
+
+ /**
+ * Test XML configuration file correctly enables dead letter queues
+ */
+ public void testDeadLetterQueueConfigurationFile() throws Exception
+ {
+ // Write config
+ File xml = File.createTempFile(getClass().getName(), "xml");
+ xml.deleteOnExit();
+ FileWriter config = new FileWriter(xml);
+ config.write("<broker>\n");
+ writeSecurity(config);
+ config.write("<deadLetterQueues>true</deadLetterQueues>\n");
+ config.write("<virtualhosts>\n");
+ config.write("<virtualhost>\n");
+ config.write("<name>test</name>\n");
+ config.write("<test>\n");
+ config.write("<queues>\n");
+ config.write("<deadLetterQueues>false</deadLetterQueues>\n");
+ config.write("<queue>\n");
+ config.write("<name>biggles</name>\n");
+ config.write("<biggles>\n");
+ config.write("<deadLetterQueues>true</deadLetterQueues>\n");
+ config.write("</biggles>\n");
+ config.write("</queue>\n");
+ config.write("<queue>\n");
+ config.write("<name>beetle</name>\n");
+ config.write("<beetle />\n");
+ config.write("</queue>\n");
+ config.write("</queues>\n");
+ config.write("</test>\n");
+ config.write("</virtualhost>\n");
+ config.write("<virtualhost>\n");
+ config.write("<name>extra</name>\n");
+ config.write("<extra>\n");
+ config.write("<queues>\n");
+ config.write("<queue>\n");
+ config.write("<name>r2d2</name>\n");
+ config.write("<r2d2>\n");
+ config.write("<deadLetterQueues>false</deadLetterQueues>\n");
+ config.write("</r2d2>\n");
+ config.write("</queue>\n");
+ config.write("<queue>\n");
+ config.write("<name>c3p0</name>\n");
+ config.write("<c3p0 />\n");
+ config.write("</queue>\n");
+ config.write("</queues>\n");
+ config.write("</extra>\n");
+ config.write("</virtualhost>\n");
+ config.write("</virtualhosts>\n");
+ config.write("</broker>\n");
+ config.close();
+
+ // Load config
+ ApplicationRegistry.remove();
+ ApplicationRegistry registry = new ConfigurationFileApplicationRegistry(xml);
+ ApplicationRegistry.initialise(registry);
+ ServerConfiguration serverConfiguration = ApplicationRegistry.getInstance().getConfiguration();
+
+ VirtualHostConfiguration test = serverConfiguration.getVirtualHostConfig("test");
+ assertNotNull("Host 'test' is not found", test);
+ VirtualHostConfiguration extra = serverConfiguration.getVirtualHostConfig("extra");
+ assertNotNull("Host 'extra' is not found", test);
+
+ QueueConfiguration biggles = test.getQueueConfiguration("biggles");
+ QueueConfiguration beetle = test.getQueueConfiguration("beetle");
+ QueueConfiguration r2d2 = extra.getQueueConfiguration("r2d2");
+ QueueConfiguration c3p0 = extra.getQueueConfiguration("c3p0");
+
+ // Validate config
+ assertTrue("Broker DLQ should be configured as enabled", serverConfiguration.isDeadLetterQueueEnabled());
+ assertFalse("Test vhost DLQ should be configured as disabled", test.isDeadLetterQueueEnabled());
+ assertTrue("Extra vhost DLQ should be enabled, using broker default", extra.isDeadLetterQueueEnabled());
+ assertTrue("Biggles queue DLQ should be configured as enabled", biggles.isDeadLetterQueueEnabled());
+ assertFalse("Beetle queue DLQ should be disabled, using test vhost default", beetle.isDeadLetterQueueEnabled());
+ assertFalse("R2D2 queue DLQ should be configured as disabled", r2d2.isDeadLetterQueueEnabled());
+ assertTrue("C3P0 queue DLQ should be enabled, using broker default", c3p0.isDeadLetterQueueEnabled());
+ }
+
+ /**
+ * Convenience method to output required security preamble for broker config
+ */
+ private void writeSecurity(Writer out) throws Exception
+ {
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<pd-auth-manager>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t\t<jmx-access>/dev/null</jmx-access>\n");
+ out.write("\t\t</pd-auth-manager>\n");
+ out.write("\t</security>\n");
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
index b133d53ac5..f6cd397217 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
@@ -21,7 +21,6 @@ package org.apache.qpid.server.configuration;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.XMLConfiguration;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.queue.AMQPriorityQueue;
import org.apache.qpid.server.queue.AMQQueue;
@@ -34,19 +33,6 @@ public class VirtualHostConfigurationTest extends InternalBrokerBaseCase
{
@Override
- public void setUp() throws Exception
- {
- super.setUp();
- // Set the default configuration items
- getConfigXml().clear();
- getConfigXml().addProperty("virtualhosts.virtualhost(-1).name", "test");
- getConfigXml().addProperty("virtualhosts.virtualhost(-1).test.store.class", TestableMemoryMessageStore.class.getName());
-
- getConfigXml().addProperty("virtualhosts.virtualhost.name", getName());
- getConfigXml().addProperty("virtualhosts.virtualhost."+getName()+".store.class", TestableMemoryMessageStore.class.getName());
- }
-
- @Override
public void createBroker()
{
// Prevent auto broker startup
@@ -134,6 +120,88 @@ public class VirtualHostConfigurationTest extends InternalBrokerBaseCase
assertEquals(3, bTest.getMaximumMessageAge());
}
+ public void testMaxDeliveryCount() throws Exception
+ {
+ // Set up vhosts and queues
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues.maximumDeliveryCount", 5);
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues(-1).queue(-1).name", "biggles");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues.queue.biggles.maximumDeliveryCount", 4);
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues(-1).queue(-1).name", "beetle");
+
+ // Start the broker now.
+ super.createBroker();
+
+ // Get vhosts
+ VirtualHost test = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(getName());
+
+ // Enabled specifically
+ assertEquals("Test vhost MDC was configured as enabled", 5 ,test.getConfiguration().getMaxDeliveryCount());
+
+ // Enabled by test vhost default
+ assertEquals("beetle queue DLQ was configured as enabled", test.getConfiguration().getMaxDeliveryCount(), test.getConfiguration().getQueueConfiguration("beetle").getMaxDeliveryCount());
+
+ // Disabled specifically
+ assertEquals("Biggles queue DLQ was configured as disabled", 4, test.getConfiguration().getQueueConfiguration("biggles").getMaxDeliveryCount());
+ }
+
+ /**
+ * Tests the full set of configuration options for enabling DLQs in the broker configuration.
+ */
+ public void testIsDeadLetterQueueEnabled() throws Exception
+ {
+ // Set up vhosts and queues
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues.deadLetterQueues", "true");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues(-1).queue(-1).name", "biggles");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues.queue.biggles.deadLetterQueues", "false");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + ".queues(-1).queue(-1).name", "beetle");
+
+
+ getConfigXml().addProperty("virtualhosts.virtualhost.name", getName() + "Extra");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + "Extra.queues(-1).queue(-1).name", "r2d2");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + "Extra.queues.queue.r2d2.deadLetterQueues", "true");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + "Extra.queues(-1).queue(-1).name", "c3p0");
+ getConfigXml().addProperty("virtualhosts.virtualhost." + getName() + "Extra.store.class", TestableMemoryMessageStore.class.getName());
+
+ // Start the broker now.
+ super.createBroker();
+
+ // Get vhosts
+ VirtualHost test = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(getName());
+ VirtualHost extra = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(getName() + "Extra");
+
+ // Enabled specifically
+ assertTrue("Test vhost DLQ was configured as enabled", test.getConfiguration().isDeadLetterQueueEnabled());
+ assertTrue("r2d2 queue DLQ was configured as enabled", extra.getConfiguration().getQueueConfiguration("r2d2").isDeadLetterQueueEnabled());
+
+ // Enabled by test vhost default
+ assertTrue("beetle queue DLQ was configured as enabled", test.getConfiguration().getQueueConfiguration("beetle").isDeadLetterQueueEnabled());
+
+ // Disabled specifically
+ assertFalse("Biggles queue DLQ was configured as disabled", test.getConfiguration().getQueueConfiguration("biggles").isDeadLetterQueueEnabled());
+
+ // Using broker default of disabled
+ assertFalse("Extra vhost DLQ disabled, using broker default", extra.getConfiguration().isDeadLetterQueueEnabled());
+ assertFalse("c3p0 queue DLQ was configured as disabled", extra.getConfiguration().getQueueConfiguration("c3p0").isDeadLetterQueueEnabled());
+
+ // Get queues
+ AMQQueue biggles = test.getQueueRegistry().getQueue(new AMQShortString("biggles"));
+ AMQQueue beetle = test.getQueueRegistry().getQueue(new AMQShortString("beetle"));
+ AMQQueue r2d2 = extra.getQueueRegistry().getQueue(new AMQShortString("r2d2"));
+ AMQQueue c3p0 = extra.getQueueRegistry().getQueue(new AMQShortString("c3p0"));
+
+ // Disabled specifically for this queue, overriding virtualhost setting
+ assertNull("Biggles queue should not have alt exchange as DLQ should be configured as disabled: " + biggles.getAlternateExchange(), biggles.getAlternateExchange());
+
+ // Enabled for all queues on the virtualhost
+ assertNotNull("Beetle queue should have an alt exchange as DLQ should be enabled, using test vhost default", beetle.getAlternateExchange());
+
+ // Enabled specifically for this queue, overriding the default broker setting of disabled
+ assertNotNull("R2D2 queue should have an alt exchange as DLQ should be configured as enabled", r2d2.getAlternateExchange());
+
+ // Disabled by the default broker setting
+ assertNull("C3PO queue should not have an alt exchange as DLQ should be disabled, using broker default", c3p0.getAlternateExchange());
+ }
+
/**
* Test that the house keeping pool sizes is correctly processed
*
@@ -173,7 +241,7 @@ public class VirtualHostConfigurationTest extends InternalBrokerBaseCase
vhost.getHouseKeepingTaskCount());
// Currently the two are tasks:
- // ExpiredMessageTask from VirtualHost
+ // ExpiredMessageTask from VirtualHost
// UpdateTask from the QMF ManagementExchange
}
@@ -214,7 +282,7 @@ public class VirtualHostConfigurationTest extends InternalBrokerBaseCase
{
getConfigXml().addProperty("virtualhosts.virtualhost.testSecurityAuthenticationNameRejected.security.authentication.name",
"testdb");
-
+
try
{
super.createBroker();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
index 886396acb8..a0a29cf734 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -20,9 +20,17 @@
*/
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.log4j.Logger;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -52,17 +60,6 @@ import org.apache.qpid.server.store.StoredMessage;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-
public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase
{
private static final Logger _log = Logger.getLogger(AbstractHeadersExchangeTestBase.class);
@@ -488,6 +485,32 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase
{
return false;
}
+
+ public QueueEntry getNextNode()
+ {
+ return null;
+ }
+
+ public QueueEntry getNextValidEntry()
+ {
+ return null;
+ }
+
+ @Override
+ public int getDeliveryCount()
+ {
+ return 0;
+ }
+
+ @Override
+ public void incrementDeliveryCount()
+ {
+ }
+
+ @Override
+ public void decrementDeliveryCount()
+ {
+ }
};
if(action != null)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
index 71e92b5294..68021f0b07 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
-
+import org.apache.commons.lang.ArrayUtils;
import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.queue.AMQQueue;
@@ -34,9 +33,11 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.TabularData;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Iterator;
/**
* Unit test class for testing different Exchange MBean operations
@@ -47,10 +48,20 @@ public class ExchangeMBeanTest extends InternalBrokerBaseCase
private QueueRegistry _queueRegistry;
private VirtualHost _virtualHost;
- /**
- * Test for direct exchange mbean
- * @throws Exception
- */
+ public void testGeneralProperties() throws Exception
+ {
+ DirectExchange exchange = new DirectExchange();
+ exchange.initialise(_virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ // test general exchange properties
+ assertEquals("Unexpected exchange name", "amq.direct", mbean.getName());
+ assertEquals("Unexpected exchange type", "direct", mbean.getExchangeType());
+ assertEquals("Unexpected ticket number", Integer.valueOf(0), mbean.getTicketNo());
+ assertFalse("Unexpected durable flag", mbean.isDurable());
+ assertTrue("Unexpected auto delete flag", mbean.isAutoDelete());
+ }
public void testDirectExchangeMBean() throws Exception
{
@@ -65,20 +76,8 @@ public class ExchangeMBeanTest extends InternalBrokerBaseCase
TabularData data = mbean.bindings();
ArrayList<Object> list = new ArrayList<Object>(data.values());
assertTrue(list.size() == 2);
-
- // test general exchange properties
- assertEquals(mbean.getName(), "amq.direct");
- assertEquals(mbean.getExchangeType(), "direct");
- assertTrue(mbean.getTicketNo() == 0);
- assertTrue(!mbean.isDurable());
- assertTrue(mbean.isAutoDelete());
}
- /**
- * Test for "topic" exchange mbean
- * @throws Exception
- */
-
public void testTopicExchangeMBean() throws Exception
{
TopicExchange exchange = new TopicExchange();
@@ -92,42 +91,81 @@ public class ExchangeMBeanTest extends InternalBrokerBaseCase
TabularData data = mbean.bindings();
ArrayList<Object> list = new ArrayList<Object>(data.values());
assertTrue(list.size() == 2);
+ }
- // test general exchange properties
- assertEquals(mbean.getName(), "amq.topic");
- assertEquals(mbean.getExchangeType(), "topic");
- assertTrue(mbean.getTicketNo() == 0);
- assertTrue(!mbean.isDurable());
- assertTrue(mbean.isAutoDelete());
+ public void testHeadersExchangeMBean() throws Exception
+ {
+ HeadersExchange exchange = new HeadersExchange();
+ exchange.initialise(_virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,key1=binding1,key2=binding2");
+
+ TabularData data = mbean.bindings();
+ ArrayList<Object> list = new ArrayList<Object>(data.values());
+ assertEquals("Unexpected number of bindings", 1, list.size());
+
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) data.values().iterator();
+ CompositeDataSupport row = rowItr.next();
+ assertBinding(1, _queue.getName(), new String[]{"x-match=any","key1=binding1","key2=binding2"}, row);
}
/**
- * Test for "Headers" exchange mbean
- * @throws Exception
+ * Included to ensure 0-10 Specification compliance:
+ * 2.3.1.4 "the field in the bind arguments has no value and a field of the same name is present in the message headers
*/
-
- public void testHeadersExchangeMBean() throws Exception
+ public void testHeadersExchangeMBeanMatchPropertyNoValue() throws Exception
{
HeadersExchange exchange = new HeadersExchange();
exchange.initialise(_virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true);
ManagedObject managedObj = exchange.getManagedObject();
ManagedExchange mbean = (ManagedExchange)managedObj;
- mbean.createNewBinding(_queue.getNameShortString().toString(), "key1=binding1,key2=binding2");
- mbean.createNewBinding(_queue.getNameShortString().toString(), "key3=binding3");
+ mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,key4,key5=");
TabularData data = mbean.bindings();
ArrayList<Object> list = new ArrayList<Object>(data.values());
- assertTrue(list.size() == 2);
+ assertEquals("Unexpected number of bindings", 1, list.size());
- // test general exchange properties
- assertEquals(mbean.getName(), "amq.match");
- assertEquals(mbean.getExchangeType(), "headers");
- assertTrue(mbean.getTicketNo() == 0);
- assertTrue(!mbean.isDurable());
- assertTrue(mbean.isAutoDelete());
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) data.values().iterator();
+ CompositeDataSupport row = rowItr.next();
+ assertBinding(1, _queue.getName(), new String[]{"x-match=any","key4=","key5="}, row);
}
-
+
+ public void testInvalidHeaderBindingMalformed() throws Exception
+ {
+ HeadersExchange exchange = new HeadersExchange();
+ exchange.initialise(_virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ try
+ {
+ mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,=value4");
+ fail("Exception not thrown");
+ }
+ catch (JMException jme)
+ {
+ //pass
+ }
+ }
+
+ private void assertBinding(final int expectedBindingNo, final String expectedQueueName, final String[] expectedBindingArray,
+ final CompositeDataSupport row)
+ {
+ final Number bindingNumber = (Number) row.get(ManagedExchange.HDR_BINDING_NUMBER);
+ final String queueName = (String) row.get(ManagedExchange.HDR_QUEUE_NAME);
+ final String[] bindings = (String[]) row.get(ManagedExchange.HDR_QUEUE_BINDINGS);
+ assertEquals("Unexpected binding number", expectedBindingNo, bindingNumber);
+ assertEquals("Unexpected queue name", expectedQueueName, queueName);
+ assertEquals("Unexpected no of bindings", expectedBindingArray.length, bindings.length);
+ for(String binding : bindings)
+ {
+ assertTrue("Expected binding not found: " + binding, ArrayUtils.contains(expectedBindingArray, binding));
+ }
+ }
+
/**
* Test adding bindings and removing them from the default exchange via JMX.
* <p>
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/flow/WindowCreditManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/flow/WindowCreditManagerTest.java
new file mode 100644
index 0000000000..2011dfbda6
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/flow/WindowCreditManagerTest.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class WindowCreditManagerTest extends QpidTestCase
+{
+ WindowCreditManager _creditManager;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _creditManager = new WindowCreditManager();
+ }
+
+ /**
+ * Tests that after the credit limit is cleared (e.g. from a message.stop command), credit is
+ * restored (e.g. from completed MessageTransfer) without increasing the available credit, and
+ * more credit is added, that the 'used' count is correct and the proper values for bytes
+ * and message credit are returned along with appropriate 'hasCredit' results (QPID-3592).
+ */
+ public void testRestoreCreditDecrementsUsedCountAfterCreditClear()
+ {
+ assertEquals("unexpected credit value", 0, _creditManager.getMessageCredit());
+ assertEquals("unexpected credit value", 0, _creditManager.getBytesCredit());
+
+ //give some message credit
+ _creditManager.addCredit(1, 0);
+ assertFalse("Manager should not 'haveCredit' due to having 0 bytes credit", _creditManager.hasCredit());
+ assertEquals("unexpected credit value", 1, _creditManager.getMessageCredit());
+ assertEquals("unexpected credit value", 0, _creditManager.getBytesCredit());
+
+ //give some bytes credit
+ _creditManager.addCredit(0, 1);
+ assertTrue("Manager should 'haveCredit'", _creditManager.hasCredit());
+ assertEquals("unexpected credit value", 1, _creditManager.getMessageCredit());
+ assertEquals("unexpected credit value", 1, _creditManager.getBytesCredit());
+
+ //use all the credit
+ _creditManager.useCreditForMessage(1);
+ assertEquals("unexpected credit value", 0, _creditManager.getBytesCredit());
+ assertEquals("unexpected credit value", 0, _creditManager.getMessageCredit());
+ assertFalse("Manager should not 'haveCredit'", _creditManager.hasCredit());
+
+ //clear credit out (eg from a message.stop command)
+ _creditManager.clearCredit();
+ assertEquals("unexpected credit value", 0, _creditManager.getBytesCredit());
+ assertEquals("unexpected credit value", 0, _creditManager.getMessageCredit());
+ assertFalse("Manager should not 'haveCredit'", _creditManager.hasCredit());
+
+ //restore credit (e.g the original message transfer command got completed)
+ //this should not increase credit, because it is now limited to 0
+ _creditManager.restoreCredit(1, 1);
+ assertEquals("unexpected credit value", 0, _creditManager.getBytesCredit());
+ assertEquals("unexpected credit value", 0, _creditManager.getMessageCredit());
+ assertFalse("Manager should not 'haveCredit'", _creditManager.hasCredit());
+
+ //give more credit to open the window again
+ _creditManager.addCredit(1, 1);
+ assertEquals("unexpected credit value", 1, _creditManager.getBytesCredit());
+ assertEquals("unexpected credit value", 1, _creditManager.getMessageCredit());
+ assertTrue("Manager should 'haveCredit'", _creditManager.hasCredit());
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
index 4df051edb5..e1dae5fcc1 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
@@ -20,23 +20,21 @@
*/
package org.apache.qpid.server.protocol;
-import junit.framework.TestCase;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.management.common.mbeans.ManagedConnection;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import org.apache.qpid.server.virtualhost.VirtualHost;
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.store.MessageStore;
import org.apache.qpid.server.store.SkeletonMessageStore;
-
-import javax.management.JMException;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularData;
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.virtualhost.VirtualHost;
/** Test class to test MBean operations for AMQMinaProtocolSession. */
@@ -67,7 +65,7 @@ public class AMQProtocolSessionMBeanTest extends InternalBrokerBaseCase
assertTrue(channelCount == 2);
// general properties test
- _mbean.setMaximumNumberOfChannels(1000L);
+ _protocolSession.setMaximumNumberOfChannels(1000L);
assertTrue(_mbean.getMaximumNumberOfChannels() == 1000L);
// check APIs
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
index 5a411c6807..3c76252cb2 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
@@ -43,6 +43,9 @@ import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.transport.TestNetworkConnection;
@@ -120,6 +123,11 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr
{
}
+ public ClientDeliveryMethod createDeliveryMethod(int channelId)
+ {
+ return new InternalWriteDeliverMethod(channelId);
+ }
+
public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
{
}
@@ -213,4 +221,41 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr
((AMQChannel)session).getProtocolSession().closeSession();
}
+
+ private class InternalWriteDeliverMethod implements ClientDeliveryMethod
+ {
+ private int _channelId;
+
+ public InternalWriteDeliverMethod(int channelId)
+ {
+ _channelId = channelId;
+ }
+
+
+ public void deliverToClient(Subscription sub, QueueEntry entry, long deliveryTag) throws AMQException
+ {
+ _deliveryCount.incrementAndGet();
+
+ synchronized (_channelDelivers)
+ {
+ Map<AMQShortString, LinkedList<DeliveryPair>> consumers = _channelDelivers.get(_channelId);
+
+ if (consumers == null)
+ {
+ consumers = new HashMap<AMQShortString, LinkedList<DeliveryPair>>();
+ _channelDelivers.put(_channelId, consumers);
+ }
+
+ LinkedList<DeliveryPair> consumerDelivers = consumers.get(((SubscriptionImpl)sub).getConsumerTag());
+
+ if (consumerDelivers == null)
+ {
+ consumerDelivers = new LinkedList<DeliveryPair>();
+ consumers.put(((SubscriptionImpl)sub).getConsumerTag(), consumerDelivers);
+ }
+
+ consumerDelivers.add(new DeliveryPair(deliveryTag, (AMQMessage)entry.getMessage()));
+ }
+ }
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
index 3961b3b355..2ce43052d9 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
@@ -21,12 +21,12 @@ package org.apache.qpid.server.queue;
*/
import java.util.ArrayList;
-
+import junit.framework.AssertionFailedError;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.FieldTable;
-import junit.framework.AssertionFailedError;
+import org.apache.qpid.server.message.AMQMessage;
public class AMQPriorityQueueTest extends SimpleAMQQueueTest
{
@@ -35,7 +35,7 @@ public class AMQPriorityQueueTest extends SimpleAMQQueueTest
public void setUp() throws Exception
{
_arguments = new FieldTable();
- _arguments.put(AMQQueueFactory.X_QPID_PRIORITIES, 3);
+ _arguments.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), 3);
super.setUp();
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
index 27891289fb..2b7d1d7f26 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
@@ -20,39 +20,76 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.DefaultExchangeFactory;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.logging.SystemOutMessageLogger;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.test.utils.QpidTestCase;
-public class AMQQueueFactoryTest extends InternalBrokerBaseCase
+public class AMQQueueFactoryTest extends QpidTestCase
{
QueueRegistry _queueRegistry;
VirtualHost _virtualHost;
- int _defaultQueueCount;
@Override
public void setUp() throws Exception
{
super.setUp();
- ApplicationRegistry registry = (ApplicationRegistry) ApplicationRegistry.getInstance();
- _virtualHost = registry.getVirtualHostRegistry().getVirtualHost("test");
+ CurrentActor.set(new TestLogActor(new SystemOutMessageLogger()));
+
+ XMLConfiguration configXml = new XMLConfiguration();
+ configXml.addProperty("virtualhosts.virtualhost(-1).name", getName());
+ configXml.addProperty("virtualhosts.virtualhost(-1)."+getName()+".store.class", TestableMemoryMessageStore.class.getName());
+
+ ServerConfiguration configuration = new ServerConfiguration(configXml);
+
+ ApplicationRegistry registry = new TestApplicationRegistry(configuration);
+ ApplicationRegistry.initialise(registry);
+ registry.getVirtualHostRegistry().setDefaultVirtualHostName(getName());
+
+ _virtualHost = registry.getVirtualHostRegistry().getVirtualHost(getName());
_queueRegistry = _virtualHost.getQueueRegistry();
- _defaultQueueCount = _queueRegistry.getQueues().size();
}
@Override
public void tearDown() throws Exception
{
- assertEquals("Queue was not registered in virtualhost", _defaultQueueCount + 1, _queueRegistry.getQueues().size());
- super.tearDown();
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ ApplicationRegistry.remove();
+ }
+ }
+
+ private void verifyRegisteredQueueCount(int count)
+ {
+ assertEquals("Queue was not registered in virtualhost", count, _queueRegistry.getQueues().size());
}
+ private void verifyQueueRegistered(String queueName)
+ {
+ assertNotNull("Queue " + queueName + " was not created", _queueRegistry.getQueue(queueName));
+ }
+
public void testPriorityQueueRegistration() throws Exception
{
FieldTable fieldTable = new FieldTable();
@@ -63,13 +100,314 @@ public class AMQQueueFactoryTest extends InternalBrokerBaseCase
false, _virtualHost, fieldTable);
assertEquals("Queue not a priorty queue", AMQPriorityQueue.class, queue.getClass());
+ verifyQueueRegistered("testPriorityQueue");
+ verifyRegisteredQueueCount(1);
}
public void testSimpleQueueRegistration() throws Exception
{
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false,
+ AMQShortString queueName = new AMQShortString("testSimpleQueueRegistration");
+ AMQShortString dlQueueName = new AMQShortString(queueName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false,
false, _virtualHost, null);
assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass());
+ verifyQueueRegistered("testSimpleQueueRegistration");
+
+ //verify that no alternate exchange or DLQ were produced
+ QueueRegistry qReg = _virtualHost.getQueueRegistry();
+
+ assertNull("Queue should not have an alternate exchange as DLQ wasnt enabled", queue.getAlternateExchange());
+ assertNull("The DLQ should not exist", qReg.getQueue(dlQueueName));
+
+ verifyRegisteredQueueCount(1);
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_DLQ_ENABLED} argument true does
+ * cause the alternate exchange to be set and DLQ to be produced.
+ * @throws AMQException
+ */
+ public void testDeadLetterQueueEnabled() throws AMQException
+ {
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.setBoolean(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+
+ AMQShortString queueName = new AMQShortString("testDeadLetterQueueEnabled");
+ AMQShortString dlExchangeName = new AMQShortString(queueName + DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ AMQShortString dlQueueName = new AMQShortString(queueName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+
+ QueueRegistry qReg = _virtualHost.getQueueRegistry();
+ ExchangeRegistry exReg = _virtualHost.getExchangeRegistry();
+
+ assertNull("The DLQ should not yet exist", qReg.getQueue(dlQueueName));
+ assertNull("The alternate exchange should not yet exist", exReg.getExchange(dlExchangeName));
+
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false, false,
+ _virtualHost, fieldTable);
+
+ Exchange altExchange = queue.getAlternateExchange();
+ assertNotNull("Queue should have an alternate exchange as DLQ is enabled", altExchange);
+ assertEquals("Alternate exchange name was not as expected", dlExchangeName, altExchange.getName());
+ assertEquals("Alternate exchange type was not as expected", ExchangeDefaults.FANOUT_EXCHANGE_CLASS, altExchange.getType().getName());
+
+ assertNotNull("The alternate exchange was not registered as expected", exReg.getExchange(dlExchangeName));
+ assertEquals("The registered exchange was not the expected exchange instance", altExchange, exReg.getExchange(dlExchangeName));
+
+ AMQQueue dlQueue = qReg.getQueue(dlQueueName);
+ assertNotNull("The DLQ was not registered as expected", dlQueue);
+ assertTrue("DLQ should have been bound to the alternate exchange", altExchange.isBound(dlQueue));
+ assertNull("DLQ should have no alternate exchange", dlQueue.getAlternateExchange());
+ assertEquals("DLQ should have a zero maximum delivery count", 0, dlQueue.getMaximumDeliveryCount());
+
+ //2 queues should have been registered
+ verifyRegisteredQueueCount(2);
+ }
+
+ /**
+ * Tests that the deadLetterQueues/maximumDeliveryCount settings from the configuration
+ * are not applied to the DLQ itself.
+ * @throws AMQException
+ */
+ public void testDeadLetterQueueDoesNotInheritDLQorMDCSettings() throws AMQException
+ {
+ ApplicationRegistry.getInstance().getConfiguration().getConfig().addProperty("deadLetterQueues","true");
+ ApplicationRegistry.getInstance().getConfiguration().getConfig().addProperty("maximumDeliveryCount","5");
+
+ AMQShortString queueName = new AMQShortString("testDeadLetterQueueEnabled");
+ AMQShortString dlExchangeName = new AMQShortString(queueName + DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ AMQShortString dlQueueName = new AMQShortString(queueName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+
+ QueueRegistry qReg = _virtualHost.getQueueRegistry();
+ ExchangeRegistry exReg = _virtualHost.getExchangeRegistry();
+
+ assertNull("The DLQ should not yet exist", qReg.getQueue(dlQueueName));
+ assertNull("The alternate exchange should not yet exist", exReg.getExchange(dlExchangeName));
+
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false, false,
+ _virtualHost, null);
+
+ assertEquals("Unexpected maximum delivery count", 5, queue.getMaximumDeliveryCount());
+ Exchange altExchange = queue.getAlternateExchange();
+ assertNotNull("Queue should have an alternate exchange as DLQ is enabled", altExchange);
+ assertEquals("Alternate exchange name was not as expected", dlExchangeName, altExchange.getName());
+ assertEquals("Alternate exchange type was not as expected", ExchangeDefaults.FANOUT_EXCHANGE_CLASS, altExchange.getType().getName());
+
+ assertNotNull("The alternate exchange was not registered as expected", exReg.getExchange(dlExchangeName));
+ assertEquals("The registered exchange was not the expected exchange instance", altExchange, exReg.getExchange(dlExchangeName));
+
+ AMQQueue dlQueue = qReg.getQueue(dlQueueName);
+ assertNotNull("The DLQ was not registered as expected", dlQueue);
+ assertTrue("DLQ should have been bound to the alternate exchange", altExchange.isBound(dlQueue));
+ assertNull("DLQ should have no alternate exchange", dlQueue.getAlternateExchange());
+ assertEquals("DLQ should have a zero maximum delivery count", 0, dlQueue.getMaximumDeliveryCount());
+
+ //2 queues should have been registered
+ verifyRegisteredQueueCount(2);
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_DLQ_ENABLED} argument false does not
+ * result in the alternate exchange being set and DLQ being created.
+ * @throws AMQException
+ */
+ public void testDeadLetterQueueDisabled() throws AMQException
+ {
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.setBoolean(AMQQueueFactory.X_QPID_DLQ_ENABLED, false);
+
+ AMQShortString queueName = new AMQShortString("testDeadLetterQueueDisabled");
+ AMQShortString dlExchangeName = new AMQShortString(queueName + DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ AMQShortString dlQueueName = new AMQShortString(queueName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+
+ QueueRegistry qReg = _virtualHost.getQueueRegistry();
+ ExchangeRegistry exReg = _virtualHost.getExchangeRegistry();
+
+ assertNull("The DLQ should not yet exist", qReg.getQueue(dlQueueName));
+ assertNull("The alternate exchange should not exist", exReg.getExchange(dlExchangeName));
+
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false, false,
+ _virtualHost, fieldTable);
+
+ assertNull("Queue should not have an alternate exchange as DLQ is disabled", queue.getAlternateExchange());
+ assertNull("The alternate exchange should still not exist", exReg.getExchange(dlExchangeName));
+
+ assertNull("The DLQ should still not exist", qReg.getQueue(dlQueueName));
+
+ //only 1 queue should have been registered
+ verifyRegisteredQueueCount(1);
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_DLQ_ENABLED} argument true but
+ * creating an auto-delete queue, does not result in the alternate exchange
+ * being set and DLQ being created.
+ * @throws AMQException
+ */
+ public void testDeadLetterQueueNotCreatedForAutodeleteQueues() throws AMQException
+ {
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.setBoolean(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+
+ AMQShortString queueName = new AMQShortString("testDeadLetterQueueNotCreatedForAutodeleteQueues");
+ AMQShortString dlExchangeName = new AMQShortString(queueName + DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ AMQShortString dlQueueName = new AMQShortString(queueName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+
+ QueueRegistry qReg = _virtualHost.getQueueRegistry();
+ ExchangeRegistry exReg = _virtualHost.getExchangeRegistry();
+
+ assertNull("The DLQ should not yet exist", qReg.getQueue(dlQueueName));
+ assertNull("The alternate exchange should not exist", exReg.getExchange(dlExchangeName));
+
+ //create an autodelete queue
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), true, false,
+ _virtualHost, fieldTable);
+ assertTrue("Queue should be autodelete", queue.isAutoDelete());
+
+ //ensure that the autodelete property overrides the request to enable DLQ
+ assertNull("Queue should not have an alternate exchange as queue is autodelete", queue.getAlternateExchange());
+ assertNull("The alternate exchange should not exist as queue is autodelete", exReg.getExchange(dlExchangeName));
+ assertNull("The DLQ should not exist as queue is autodelete", qReg.getQueue(dlQueueName));
+
+ //only 1 queue should have been registered
+ verifyRegisteredQueueCount(1);
+ }
+
+ /**
+ * Tests that setting the {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument has
+ * the desired effect.
+ */
+ public void testMaximumDeliveryCount() throws Exception
+ {
+ final FieldTable fieldTable = new FieldTable();
+ fieldTable.setInteger(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, 5);
+
+ final AMQShortString queueName = new AMQShortString("testMaximumDeliveryCount");
+
+ final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false, false,
+ _virtualHost, fieldTable);
+
+ assertNotNull("The queue was not registered as expected ", queue);
+ assertEquals("Maximum delivery count not as expected", 5, queue.getMaximumDeliveryCount());
+
+ verifyRegisteredQueueCount(1);
+ }
+
+ /**
+ * Tests that omitting the {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument means
+ * that queue is created with a default maximumDeliveryCount of zero (unless set in config).
+ */
+ public void testMaximumDeliveryCountDefault() throws Exception
+ {
+
+ final AMQShortString queueName = new AMQShortString("testMaximumDeliveryCount");
+
+ final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, new AMQShortString("owner"), false, false,
+ _virtualHost, null);
+
+ assertNotNull("The queue was not registered as expected ", queue);
+ assertEquals("Maximum delivery count not as expected", 0, queue.getMaximumDeliveryCount());
+
+ verifyRegisteredQueueCount(1);
+ }
+
+ /**
+ * Tests queue creation with queue name set to null
+ */
+ public void testQueueNameNullValidation()
+ {
+ try
+ {
+ AMQQueueFactory.createAMQQueueImpl(null, false, new AMQShortString("owner"), true, false, _virtualHost, null);
+ fail("queue with null name can not be created!");
+ }
+ catch (Exception e)
+ {
+ assertTrue(e instanceof IllegalArgumentException);
+ assertEquals("Queue name must not be null", e.getMessage());
+ }
+ }
+
+ /**
+ * Tests queue creation with queue name length less 255 characters but
+ * corresponding DLQ name length greater than 255.
+ */
+ public void testQueueNameWithLengthLessThan255ButDLQNameWithLengthGreaterThan255()
+ {
+ String queueName = "test-" + generateStringWithLength('a', 245);
+ try
+ {
+ // change DLQ name to make its length bigger than exchange name
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterExchangeSuffix", "_DLE");
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterQueueSuffix", "_DLQUEUE");
+
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.setBoolean(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+ AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), false, new AMQShortString("owner"),
+ false, false, _virtualHost, fieldTable);
+ fail("queue with DLQ name having more than 255 characters can not be created!");
+ }
+ catch (Exception e)
+ {
+ assertTrue("Unexpected exception is thrown!", e instanceof IllegalArgumentException);
+ assertTrue("Unexpected exception message!", e.getMessage().contains("DLQ queue name")
+ && e.getMessage().contains("length exceeds limit of 255"));
+ }
+ finally
+ {
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterExchangeSuffix", DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterQueueSuffix", AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+ }
+
+ /**
+ * Tests queue creation with queue name length less 255 characters but
+ * corresponding DL exchange name length greater than 255.
+ */
+ public void testQueueNameWithLengthLessThan255ButDLExchangeNameWithLengthGreaterThan255()
+ {
+ String queueName = "test-" + generateStringWithLength('a', 245);
+ try
+ {
+ // change DLQ name to make its length bigger than exchange name
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterExchangeSuffix", "_DLEXCHANGE");
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterQueueSuffix", "_DLQ");
+
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.setBoolean(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+ AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), false, new AMQShortString("owner"),
+ false, false, _virtualHost, fieldTable);
+ fail("queue with DLE name having more than 255 characters can not be created!");
+ }
+ catch (Exception e)
+ {
+ assertTrue("Unexpected exception is thrown!", e instanceof IllegalArgumentException);
+ assertTrue("Unexpected exception message!", e.getMessage().contains("DL exchange name")
+ && e.getMessage().contains("length exceeds limit of 255"));
+ }
+ finally
+ {
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterExchangeSuffix", DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ ApplicationRegistry.getInstance().getConfiguration().getConfig()
+ .addProperty("deadLetterQueueSuffix", AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+ }
+
+ private String generateStringWithLength(char ch, int length)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < length; i++)
+ {
+ sb.append(ch);
+ }
+ return sb.toString();
}
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
index 070d105805..f70250132a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
@@ -20,13 +20,14 @@
*/
package org.apache.qpid.server.queue;
+import org.apache.commons.lang.time.FastDateFormat;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.ContentHeaderBody;
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.management.common.mbeans.ManagedQueue;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.util.InternalBrokerBaseCase;
import org.apache.qpid.server.message.AMQMessage;
@@ -39,11 +40,21 @@ import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
/**
- * Test class to test AMQQueueMBean attribtues and operations
+ * Test class to test AMQQueueMBean attributes and operations
*/
public class AMQQueueMBeanTest extends InternalBrokerBaseCase
{
@@ -139,6 +150,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
verifyBrokerState();
}
+
// todo: collect to a general testing class -duplicated from Systest/MessageReturntest
private void verifyBrokerState()
{
@@ -219,7 +231,43 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
assertFalse("Exclusive property should be false.", getQueue().isExclusive());
}
- public void testExceptions() throws Exception
+ /**
+ * Tests view messages with two test messages. The first message is non-persistent, the second persistent
+ * and has timestamp/expiration.
+ *
+ */
+ public void testViewMessages() throws Exception
+ {
+ sendMessages(1, false);
+ final Date msg2Timestamp = new Date();
+ final Date msg2Expiration = new Date(msg2Timestamp.getTime() + 1000);
+ sendMessages(1, true, msg2Timestamp.getTime(), msg2Expiration.getTime());
+
+ final TabularData tab = _queueMBean.viewMessages(1l, 2l);
+ assertEquals("Unexpected number of rows in table", 2, tab.size());
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) tab.values().iterator();
+
+ // Check row1
+ final CompositeDataSupport row1 = rowItr.next();
+ assertEquals("Message should have AMQ message id", 1l, row1.get(ManagedQueue.MSG_AMQ_ID));
+ assertNotNull("Expected message header array", row1.get(ManagedQueue.MSG_HEADER));
+ final Map<String, String> row1Headers = headerArrayToMap((String[])row1.get(ManagedQueue.MSG_HEADER));
+ assertEquals("Unexpected JMSPriority within header", "Non_Persistent", row1Headers.get("JMSDeliveryMode"));
+ assertEquals("Unexpected JMSTimestamp within header", "null", row1Headers.get("JMSTimestamp"));
+ assertEquals("Unexpected JMSExpiration within header", "null", row1Headers.get("JMSExpiration"));
+
+ final CompositeDataSupport row2 = rowItr.next();
+ assertEquals("Message should have AMQ message id", 2l, row2.get(ManagedQueue.MSG_AMQ_ID));
+ assertNotNull("Expected message header array", row2.get(ManagedQueue.MSG_HEADER));
+ final Map<String, String> row2Headers = headerArrayToMap((String[])row2.get(ManagedQueue.MSG_HEADER));
+ assertEquals("Unexpected JMSPriority within header", "Persistent", row2Headers.get("JMSDeliveryMode"));
+ assertEquals("Unexpected JMSTimestamp within header", FastDateFormat.getInstance(AMQQueueMBean.JMSTIMESTAMP_DATETIME_FORMAT).format(msg2Timestamp),
+ row2Headers.get("JMSTimestamp"));
+ assertEquals("Unexpected JMSExpiration within header", FastDateFormat.getInstance(AMQQueueMBean.JMSTIMESTAMP_DATETIME_FORMAT).format(msg2Expiration),
+ row2Headers.get("JMSExpiration"));
+ }
+
+ public void testViewMessageWithIllegalStartEndRanges() throws Exception
{
try
{
@@ -228,7 +276,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
}
catch (JMException ex)
{
-
+ // PASS
}
try
@@ -238,7 +286,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
}
catch (JMException ex)
{
-
+ // PASS
}
try
@@ -248,7 +296,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
}
catch (JMException ex)
{
-
+ // PASS
}
try
@@ -260,45 +308,24 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
}
catch (JMException ex)
{
-
+ // PASS
}
+ }
- IncomingMessage msg = message(false, false);
- getQueue().clearQueue();
- ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
- qs.add(getQueue());
- msg.enqueue(qs);
- MessageMetaData mmd = msg.headersReceived();
- msg.setStoredMessage(getMessageStore().addMessage(mmd));
- long id = msg.getMessageNumber();
-
- msg.addContentBodyFrame(new ContentChunk()
- {
- byte[] _data = new byte[((int)MESSAGE_SIZE)];
-
- public int getSize()
- {
- return (int) MESSAGE_SIZE;
- }
-
- public byte[] getData()
- {
- return _data;
- }
+ public void testViewMessageContent() throws Exception
+ {
+ final List<AMQMessage> sentMessages = sendMessages(1, true);
+ final Long id = sentMessages.get(0).getMessageId();
- public void reduceToFit()
- {
+ final CompositeData messageData = _queueMBean.viewMessageContent(id);
+ assertNotNull(messageData);
+ }
- }
- });
+ public void testViewMessageContentWithUnknownMessageId() throws Exception
+ {
+ final List<AMQMessage> sentMessages = sendMessages(1, true);
+ final Long id = sentMessages.get(0).getMessageId();
- AMQMessage m = new AMQMessage(msg.getStoredMessage());
- for(BaseQueue q : msg.getDestinationQueues())
- {
- q.enqueue(m);
- }
-// _queue.process(_storeContext, new QueueEntry(_queue, msg), false);
- _queueMBean.viewMessageContent(id);
try
{
_queueMBean.viewMessageContent(id + 1);
@@ -306,7 +333,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
}
catch (JMException ex)
{
-
+ // PASS
}
}
@@ -364,47 +391,35 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
assertFalse(channel.getBlocking());
}
- private IncomingMessage message(final boolean immediate, boolean persistent) throws AMQException
+ public void testMaximumDeliveryCount() throws IOException
{
- MessagePublishInfo publish = new MessagePublishInfo()
- {
+ assertEquals("Unexpected default maximum delivery count", Integer.valueOf(0), _queueMBean.getMaximumDeliveryCount());
+ }
- public AMQShortString getExchange()
- {
- return null;
- }
+ public void testViewAllMessages() throws Exception
+ {
+ final int messageCount = 5;
+ sendPersistentMessages(messageCount);
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
- public boolean isImmediate()
- {
- return immediate;
- }
+ final TabularData messageTable = _queueMBean.viewMessages(1L, 5L);
+ assertNotNull("Message table should not be null", messageTable);
+ assertEquals("Unexpected number of rows", messageCount, messageTable.size());
- public boolean isMandatory()
- {
- return false;
- }
- public AMQShortString getRoutingKey()
- {
- return null;
- }
- };
-
- ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
- contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes
- contentHeaderBody.setProperties(new BasicContentHeaderProperties());
- ((BasicContentHeaderProperties) contentHeaderBody.getProperties()).setDeliveryMode((byte) (persistent ? 2 : 1));
- IncomingMessage msg = new IncomingMessage(publish);
- msg.setContentHeaderBody(contentHeaderBody);
- return msg;
+ final Iterator rowIterator = messageTable.values().iterator();
+ // Get its message ID
+ final CompositeDataSupport row1 = (CompositeDataSupport) rowIterator.next();
+ final Long msgId = (Long) row1.get("AMQ MessageId");
+ final Long queuePosition = (Long) row1.get("Queue Position");
+ final Integer deliveryCount = (Integer) row1.get("Delivery Count");
+ assertNotNull("Row should have value for queue position", queuePosition);
+ assertNotNull("Row should have value for msgid", msgId);
+ assertNotNull("Row should have value for deliveryCount", deliveryCount);
}
+
@Override
public void setUp() throws Exception
{
@@ -418,11 +433,25 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
ApplicationRegistry.remove();
}
- private void sendMessages(int messageCount, boolean persistent) throws AMQException
+ private void sendPersistentMessages(int messageCount) throws AMQException
+ {
+ sendMessages(messageCount, true);
+ assertEquals("Expected " + messageCount + " messages in the queue", messageCount, _queueMBean
+ .getMessageCount().intValue());
+ }
+
+ private List<AMQMessage> sendMessages(int messageCount, boolean persistent) throws AMQException
+ {
+ return sendMessages(messageCount, persistent, 0l, 0l);
+ }
+
+ private List<AMQMessage> sendMessages(int messageCount, boolean persistent, long timestamp, long expiration) throws AMQException
{
+ final List<AMQMessage> sentMessages = new ArrayList<AMQMessage>();
+
for (int i = 0; i < messageCount; i++)
{
- IncomingMessage currentMessage = message(false, persistent);
+ IncomingMessage currentMessage = createIncomingMessage(false, persistent, timestamp, expiration);
ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
qs.add(getQueue());
currentMessage.enqueue(qs);
@@ -431,7 +460,7 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
MessageMetaData mmd = currentMessage.headersReceived();
currentMessage.setStoredMessage(getMessageStore().addMessage(mmd));
- // Add the body so we have somthing to test later
+ // Add the body so we have something to test later
currentMessage.addContentBodyFrame(
getSession().getMethodRegistry()
.getProtocolVersionMethodConverter()
@@ -444,7 +473,78 @@ public class AMQQueueMBeanTest extends InternalBrokerBaseCase
q.enqueue(m);
}
+ sentMessages.add(m);
+ }
+ return sentMessages;
+ }
+
+ private IncomingMessage createIncomingMessage(final boolean immediate, boolean persistent, long timestamp, long expiration) throws AMQException
+ {
+ MessagePublishInfo publish = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ }
+
+ public boolean isImmediate()
+ {
+ return immediate;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes
+ final BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+ contentHeaderBody.setProperties(props);
+ props.setDeliveryMode((byte) (persistent ? 2 : 1));
+ if (timestamp > 0)
+ {
+ props.setTimestamp(timestamp);
+ }
+ if (expiration > 0)
+ {
+ props.setExpiration(expiration);
}
+ IncomingMessage msg = new IncomingMessage(publish);
+ msg.setContentHeaderBody(contentHeaderBody);
+ return msg;
}
+
+ /**
+ *
+ * Utility method to convert array of Strings in the form x = y into a
+ * map with key/value x =&gt; y.
+ *
+ */
+ private Map<String,String> headerArrayToMap(final String[] headerArray)
+ {
+ final Map<String, String> headerMap = new HashMap<String, String>();
+ final List<String> headerList = Arrays.asList(headerArray);
+ for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();)
+ {
+ final String nameValuePair = iterator.next();
+ final String[] nameValue = nameValuePair.split(" *= *", 2);
+ headerMap.put(nameValue[0], nameValue[1]);
+ }
+ return headerMap;
+ }
+
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
index 0f5374b3e5..5d559c9d0d 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
@@ -30,6 +30,7 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.store.StoredMessage;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.util.InternalBrokerBaseCase;
@@ -143,16 +144,19 @@ public class AckTest extends InternalBrokerBaseCase
qs.add(_queue);
msg.enqueue(qs);
MessageMetaData mmd = msg.headersReceived();
- msg.setStoredMessage(_messageStore.addMessage(mmd));
+ final StoredMessage storedMessage = _messageStore.addMessage(mmd);
+ msg.setStoredMessage(storedMessage);
+ final AMQMessage message = new AMQMessage(storedMessage);
if(msg.allContentReceived())
{
ServerTransaction txn = new AutoCommitTransaction(_messageStore);
- txn.enqueue(_queue, msg, new ServerTransaction.Action() {
+ txn.enqueue(_queue, message, new ServerTransaction.Action() {
public void postCommit()
{
try
{
- _queue.enqueue(new AMQMessage(msg.getStoredMessage()));
+
+ _queue.enqueue(message);
}
catch (AMQException e)
{
@@ -170,6 +174,15 @@ public class AckTest extends InternalBrokerBaseCase
// we manually send the message to the subscription
//_subscription.send(new QueueEntry(_queue,msg), _queue);
}
+ try
+ {
+ Thread.sleep(2000L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace(); //TODO.
+ }
+
}
/**
@@ -181,9 +194,8 @@ public class AckTest extends InternalBrokerBaseCase
_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();
- assertEquals("",msgCount,map.size());
+ assertEquals("Unextpected size for unacknowledge message map",msgCount,map.size());
Set<Long> deliveryTagSet = map.getDeliveryTags();
int i = 1;
@@ -206,7 +218,6 @@ public class AckTest extends InternalBrokerBaseCase
_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.getMessageCount() == 0);
@@ -243,7 +254,7 @@ public class AckTest extends InternalBrokerBaseCase
_channel.acknowledgeMessage(5, false);
UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == msgCount - 1);
+ assertEquals("Map not expected size",msgCount - 1,map.size());
Set<Long> deliveryTagSet = map.getDeliveryTags();
int i = 1;
@@ -270,6 +281,8 @@ public class AckTest extends InternalBrokerBaseCase
final int msgCount = 10;
publishMessages(msgCount);
+
+
_channel.acknowledgeMessage(5, true);
UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
assertTrue(map.size() == 5);
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
index 7000df157e..12369bd7d4 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
@@ -20,24 +20,23 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.AMQMessage;
public class MockAMQMessage extends AMQMessage
{
public MockAMQMessage(long messageId)
- throws AMQException
{
super(new MockStoredMessage(messageId));
}
-
-
+ public MockAMQMessage(long messageId, String headerName, Object headerValue)
+ {
+ super(new MockStoredMessage(messageId, headerName, headerValue));
+ }
@Override
public long getSize()
{
return 0l;
}
-
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
index 4c31092983..0daf79122c 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
@@ -611,4 +611,21 @@ public class MockAMQQueue implements AMQQueue
{
}
+
+ @Override
+ public int getMaximumDeliveryCount()
+ {
+ return 0;
+ }
+
+ @Override
+ public void setMaximumDeliveryCount(int maximumDeliveryCount)
+ {
+ }
+
+ @Override
+ public void setAlternateExchange(String exchangeName)
+ {
+ }
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
index ab8850c18c..7ad002c248 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
@@ -234,4 +234,31 @@ public class MockQueueEntry implements QueueEntry
return false;
}
+ public QueueEntry getNextNode()
+ {
+ return null;
+ }
+
+ public QueueEntry getNextValidEntry()
+ {
+ return null;
+ }
+
+ @Override
+ public int getDeliveryCount()
+ {
+ return 0;
+ }
+
+ @Override
+ public void incrementDeliveryCount()
+ {
+ }
+
+ @Override
+ public void decrementDeliveryCount()
+ {
+ }
+
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
index 0f812c9c7a..e2418a85be 100755
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.queue;
+import org.apache.qpid.framing.FieldTable;
+
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.TransactionLog;
import org.apache.qpid.server.store.StoredMessage;
@@ -36,16 +38,32 @@ public class MockStoredMessage implements StoredMessage<MessageMetaData>
private MessageMetaData _metaData;
private ByteBuffer _content;
-
public MockStoredMessage(long messageId)
{
- this(messageId, new MockMessagePublishInfo(), new ContentHeaderBody(new BasicContentHeaderProperties(), 60));
+ this(messageId, (String)null, null);
+ }
+
+ public MockStoredMessage(long messageId, String headerName, Object headerValue)
+ {
+ this(messageId, new MockMessagePublishInfo(), new ContentHeaderBody(new BasicContentHeaderProperties(), 60), headerName, headerValue);
}
public MockStoredMessage(long messageId, MessagePublishInfo info, ContentHeaderBody chb)
{
+ this(messageId, info, chb, null, null);
+ }
+
+ public MockStoredMessage(long messageId, MessagePublishInfo info, ContentHeaderBody chb, String headerName, Object headerValue)
+ {
_messageId = messageId;
+ if (headerName != null)
+ {
+ FieldTable headers = new FieldTable();
+ headers.setString(headerName, headerValue == null? null :String.valueOf(headerValue));
+ ((BasicContentHeaderProperties)chb.getProperties()).setHeaders(headers);
+ }
_metaData = new MessageMetaData(info, chb, 0);
+ _content = ByteBuffer.allocate(_metaData.getContentSize());
}
public MessageMetaData getMetaData()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java
index d8afd8d829..d336132316 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java
@@ -19,9 +19,7 @@
package org.apache.qpid.server.queue;
import java.lang.reflect.Field;
-
import junit.framework.TestCase;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.queue.QueueEntry.EntryState;
@@ -30,18 +28,27 @@ import org.apache.qpid.server.subscription.Subscription;
/**
* Tests for {@link QueueEntryImpl}
- *
*/
-public class QueueEntryImplTest extends TestCase
+public abstract class QueueEntryImplTestBase extends TestCase
{
// tested entry
- private QueueEntryImpl _queueEntry;
+ protected QueueEntryImpl _queueEntry;
+ protected QueueEntryImpl _queueEntry2;
+ protected QueueEntryImpl _queueEntry3;
+
+ public abstract QueueEntryImpl getQueueEntryImpl(int msgid) throws AMQException;
+
+ public abstract void testCompareTo();
+
+ public abstract void testTraverseWithNoDeletedEntries();
+
+ public abstract void testTraverseWithDeletedEntries();
public void setUp() throws Exception
{
- AMQMessage message = new MockAMQMessage(1);
- SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
- _queueEntry = new QueueEntryImpl(queueEntryList, message, 1);
+ _queueEntry = getQueueEntryImpl(1);
+ _queueEntry2 = getQueueEntryImpl(2);
+ _queueEntry3 = getQueueEntryImpl(3);
}
public void testAquire()
@@ -105,61 +112,6 @@ public class QueueEntryImplTest extends TestCase
}
/**
- * Tests if entries in DEQUQUED or DELETED state are not returned by getNext method.
- */
- public void testGetNext()
- {
- int numberOfEntries = 5;
- QueueEntryImpl[] entries = new QueueEntryImpl[numberOfEntries];
- SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
-
- // create test entries
- for(int i = 0; i < numberOfEntries ; i++)
- {
- AMQMessage message = null;;
- try
- {
- message = new MockAMQMessage(i);
- }
- catch (AMQException e)
- {
- fail("Failure to create a mock message:" + e.getMessage());
- }
- QueueEntryImpl entry = (QueueEntryImpl)queueEntryList.add(message);
- entries[i] = entry;
- }
-
- // test getNext for not acquired entries
- for(int i = 0; i < numberOfEntries ; i++)
- {
- QueueEntryImpl queueEntry = entries[i];
- QueueEntryImpl next = queueEntry.getNext();
- if (i < numberOfEntries - 1)
- {
- assertEquals("Unexpected entry from QueueEntryImpl#getNext()", entries[i + 1], next);
- }
- else
- {
- assertNull("The next entry after the last should be null", next);
- }
- }
-
- // delete second
- entries[1].acquire();
- entries[1].delete();
-
- // dequeue third
- entries[2].acquire();
- entries[2].dequeue();
-
- QueueEntryImpl next = entries[0].getNext();
- assertEquals("expected forth entry",entries[3], next);
- next = next.getNext();
- assertEquals("expected fifth entry", entries[4], next);
- next = next.getNext();
- assertNull("The next entry after the last should be null", next);
- }
- /**
* A helper method to put tested object into deleted state and assert the state
*/
private void delete()
@@ -244,4 +196,52 @@ public class QueueEntryImplTest extends TestCase
assertTrue("Queue entry should have been rejected by the subscription", _queueEntry.isRejectedBy(subId));
assertTrue("Queue entry should have been rejected by the subscription", _queueEntry.isRejectedBy(sub2Id));
}
+
+ /**
+ * Tests if entries in DEQUQUED or DELETED state are not returned by getNext method.
+ */
+ public void testGetNext()
+ {
+ int numberOfEntries = 5;
+ QueueEntryImpl[] entries = new QueueEntryImpl[numberOfEntries];
+ SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
+
+ // create test entries
+ for(int i = 0; i < numberOfEntries ; i++)
+ {
+ AMQMessage message = new MockAMQMessage(i);
+ QueueEntryImpl entry = (QueueEntryImpl)queueEntryList.add(message);
+ entries[i] = entry;
+ }
+
+ // test getNext for not acquired entries
+ for(int i = 0; i < numberOfEntries ; i++)
+ {
+ QueueEntryImpl queueEntry = entries[i];
+ QueueEntry next = queueEntry.getNextValidEntry();
+ if (i < numberOfEntries - 1)
+ {
+ assertEquals("Unexpected entry from QueueEntryImpl#getNext()", entries[i + 1], next);
+ }
+ else
+ {
+ assertNull("The next entry after the last should be null", next);
+ }
+ }
+
+ // delete second
+ entries[1].acquire();
+ entries[1].delete();
+
+ // dequeue third
+ entries[2].acquire();
+ entries[2].dequeue();
+
+ QueueEntry next = entries[0].getNextValidEntry();
+ assertEquals("expected forth entry",entries[3], next);
+ next = next.getNextValidEntry();
+ assertEquals("expected fifth entry", entries[4], next);
+ next = next.getNextValidEntry();
+ assertNull("The next entry after the last should be null", next);
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java
new file mode 100644
index 0000000000..7a3f6f701c
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+
+/**
+ * Abstract test class for QueueEntryList implementations.
+ */
+public abstract class QueueEntryListTestBase extends TestCase
+{
+ protected static final AMQQueue _testQueue = new MockAMQQueue("test");
+ public abstract QueueEntryList<QueueEntry> getTestList();
+ public abstract long getExpectedFirstMsgId();
+ public abstract int getExpectedListLength();
+ public abstract ServerMessage getTestMessageToAdd() throws AMQException;
+
+ public void testGetQueue()
+ {
+ assertEquals("Unexpected head entry returned by getHead()", getTestList().getQueue(), _testQueue);
+ }
+
+ /**
+ * Test to add a message with properties specific to the queue type.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getTestMessageToAdd()
+ * @throws AMQException
+ */
+ public void testAddSpecificMessage() throws AMQException
+ {
+ final QueueEntryList<QueueEntry> list = getTestList();
+ list.add(getTestMessageToAdd());
+
+ final QueueEntryIterator<?> iter = list.iterator();
+ int count = 0;
+ while(iter.advance())
+ {
+ iter.getNode();
+ count++;
+ }
+ assertEquals("List did not grow by one entry after an add", getExpectedListLength() + 1, count);
+ }
+
+ /**
+ * Test to add a generic mock message.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getExpectedListLength()
+ * @see MockAMQMessage
+ * @throws AMQException
+ */
+ public void testAddGenericMessage() throws AMQException
+ {
+ final QueueEntryList<QueueEntry> list = getTestList();
+ list.add(new MockAMQMessage(666));
+
+ final QueueEntryIterator<?> iter = list.iterator();
+ int count = 0;
+ while(iter.advance())
+ {
+ iter.getNode();
+ count++;
+ }
+ assertEquals("List did not grow by one entry after a generic message added", getExpectedListLength() + 1, count);
+
+ }
+
+ /**
+ * Test for getting the next element in a queue list.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getExpectedListLength()
+ */
+ public void testListNext()
+ {
+ final QueueEntryList<QueueEntry> entryList = getTestList();
+ QueueEntry entry = entryList.getHead();
+ int count = 0;
+ while(entryList.next(entry) != null)
+ {
+ entry = entryList.next(entry);
+ count++;
+ }
+ assertEquals("Get next didnt get all the list entries", getExpectedListLength(), count);
+ }
+
+ /**
+ * Basic test for the associated QueueEntryIterator implementation.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getExpectedListLength()
+ */
+ public void testIterator()
+ {
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count = 0;
+ while(iter.advance())
+ {
+ iter.getNode();
+ count++;
+ }
+ assertEquals("Iterator invalid", getExpectedListLength(), count);
+ }
+
+ /**
+ * Test for associated QueueEntryIterator implementation that checks it handles "removed" messages.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getExpectedListLength()
+ */
+ public void testDequedMessagedNotPresentInIterator() throws Exception
+ {
+ final int numberOfMessages = getExpectedListLength();
+ final QueueEntryList<QueueEntry> entryList = getTestList();
+
+ // dequeue all even messages
+ final QueueEntryIterator<?> it1 = entryList.iterator();
+ int counter = 0;
+ while (it1.advance())
+ {
+ final QueueEntry queueEntry = it1.getNode();
+ if(counter++ % 2 == 0)
+ {
+ queueEntry.acquire();
+ queueEntry.dequeue();
+ }
+ }
+
+ // iterate and check that dequeued messages are not returned by iterator
+ final QueueEntryIterator<?> it2 = entryList.iterator();
+ int counter2 = 0;
+ while(it2.advance())
+ {
+ it2.getNode();
+ counter2++;
+ }
+ final int expectedNumber = numberOfMessages / 2;
+ assertEquals("Expected " + expectedNumber + " number of entries in iterator but got " + counter2,
+ expectedNumber, counter2);
+ }
+
+ /**
+ * Test to verify the head of the queue list is returned as expected.
+ * @see QueueEntryListTestBase#getTestList()
+ * @see QueueEntryListTestBase#getExpectedFirstMsgId()
+ */
+ public void testGetHead()
+ {
+ final QueueEntry head = getTestList().getHead();
+ assertNull("Head entry should not contain an actual message", head.getMessage());
+ assertEquals("Unexpected message id for first list entry", getExpectedFirstMsgId(), getTestList().next(head)
+ .getMessage().getMessageNumber().longValue());
+ }
+
+ /**
+ * Test to verify the entry deletion handled correctly.
+ * @see QueueEntryListTestBase#getTestList()
+ */
+ public void testEntryDeleted()
+ {
+ final QueueEntry head = getTestList().getHead();
+
+ final QueueEntry first = getTestList().next(head);
+ first.delete();
+
+ final QueueEntry second = getTestList().next(head);
+ assertNotSame("After deletion the next entry should be different", first.getMessage().getMessageNumber(), second
+ .getMessage().getMessageNumber());
+
+ final QueueEntry third = getTestList().next(first);
+ assertEquals("After deletion the deleted nodes next node should be the same as the next from head", second
+ .getMessage().getMessageNumber(), third.getMessage().getMessageNumber());
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java
deleted file mode 100644
index b67723dd25..0000000000
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java
+++ /dev/null
@@ -1,97 +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.test.utils.QpidTestCase;
-
-/**
- *
- * Tests QueueEntry
- *
- */
-public class QueueEntryTest extends QpidTestCase
-{
- private QueueEntryImpl _queueEntry1 = null;
- private QueueEntryImpl _queueEntry2 = null;
- private QueueEntryImpl _queueEntry3 = null;
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
-
- int i = 0;
-
- SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(null);
- _queueEntry1 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
- _queueEntry2 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
- _queueEntry3 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
- }
-
- public void testCompareTo()
- {
- assertTrue(_queueEntry1.compareTo(_queueEntry2) < 0);
- assertTrue(_queueEntry2.compareTo(_queueEntry1) > 0);
- assertTrue(_queueEntry1.compareTo(_queueEntry1) == 0);
- }
-
- /**
- * Tests that the getNext() can be used to traverse the list.
- */
- public void testTraverseWithNoDeletedEntries()
- {
- QueueEntryImpl current = _queueEntry1;
-
- current = current.getNext();
- assertSame("Unexpected current entry",_queueEntry2, current);
-
- current = current.getNext();
- assertSame("Unexpected current entry",_queueEntry3, current);
-
- current = current.getNext();
- assertNull(current);
-
- }
-
- /**
- * Tests that the getNext() can be used to traverse the list but deleted
- * entries are skipped and de-linked from the chain of entries.
- */
- public void testTraverseWithDeletedEntries()
- {
- // Delete 2nd queue entry
- _queueEntry2.delete();
- assertTrue(_queueEntry2.isDeleted());
-
-
- QueueEntryImpl current = _queueEntry1;
-
- current = current.getNext();
- assertSame("Unexpected current entry",_queueEntry3, current);
-
- current = current.getNext();
- assertNull(current);
-
- // Assert the side effects of getNext()
- assertSame("Next node of entry 1 should now be entry 3",
- _queueEntry3, _queueEntry1.nextNode());
- }
-}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java
new file mode 100644
index 0000000000..7ff693e4c4
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.Assert;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour;
+
+/**
+ * Test extension of SortedQueueEntryList that provides data structure validation tests.
+ * @see SortedQueueEntryList
+ */
+public class SelfValidatingSortedQueueEntryList extends SortedQueueEntryList
+{
+ public SelfValidatingSortedQueueEntryList(AMQQueue queue, String propertyName)
+ {
+ super(queue, propertyName);
+ }
+
+ @Override /** Overridden to automatically check queue properties before and after. */
+ public SortedQueueEntryImpl add(final ServerMessage message)
+ {
+ assertQueueProperties(); //before add
+ final SortedQueueEntryImpl result = super.add(message);
+ assertQueueProperties(); //after add
+ return result;
+ }
+
+ @Override /** Overridden to automatically check queue properties before and after. */
+ public void entryDeleted(SortedQueueEntryImpl entry)
+ {
+ assertQueueProperties(); //before delete
+ super.entryDeleted(entry);
+ assertQueueProperties(); //after delete
+ }
+
+ public void assertQueueProperties()
+ {
+ assertRootIsBlack();
+ assertTreeIntegrity();
+ assertChildrenOfRedAreBlack();
+ assertLeavesSameBlackPath();
+ }
+
+ public void assertRootIsBlack()
+ {
+ if(!isNodeColour(getRoot(), Colour.BLACK))
+ {
+ Assert.fail("Root Not Black");
+ }
+ }
+
+ public void assertTreeIntegrity()
+ {
+ assertTreeIntegrity(getRoot());
+ }
+
+ public void assertTreeIntegrity(final SortedQueueEntryImpl node)
+ {
+ if(node == null)
+ {
+ return;
+ }
+ if(node.getLeft() != null)
+ {
+ if(node.getLeft().getParent() == node)
+ {
+ assertTreeIntegrity(node.getLeft());
+ }
+ else
+ {
+ Assert.fail("Tree integrity compromised");
+ }
+ }
+ if(node.getRight() != null)
+ {
+ if(node.getRight().getParent() == node)
+ {
+ assertTreeIntegrity(node.getRight());
+ }
+ else
+ {
+ Assert.fail("Tree integrity compromised");
+ }
+
+ }
+ }
+
+ public void assertLeavesSameBlackPath()
+ {
+ assertLeavesSameBlackPath(getRoot());
+ }
+
+ public int assertLeavesSameBlackPath(final SortedQueueEntryImpl node)
+ {
+ if(node == null)
+ {
+ return 1;
+ }
+ final int left = assertLeavesSameBlackPath(node.getLeft());
+ final int right = assertLeavesSameBlackPath(node.getLeft());
+ if(left == right)
+ {
+ return isNodeColour(node, Colour.BLACK) ? 1 + left : left;
+ }
+ else
+ {
+ Assert.fail("Unequal paths to leaves");
+ return 1; //compiler
+ }
+ }
+
+ public void assertChildrenOfRedAreBlack()
+ {
+ assertChildrenOfRedAreBlack(getRoot());
+ }
+
+ public void assertChildrenOfRedAreBlack(final SortedQueueEntryImpl node)
+ {
+ if(node == null)
+ {
+ return;
+ }
+ else if(node.getColour() == Colour.BLACK)
+ {
+ assertChildrenOfRedAreBlack(node.getLeft());
+ assertChildrenOfRedAreBlack(node.getRight());
+ }
+ else
+ {
+ if(isNodeColour(node.getLeft(), Colour.BLACK)
+ && isNodeColour(node.getRight(), Colour.BLACK))
+ {
+ assertChildrenOfRedAreBlack(node.getLeft());
+ assertChildrenOfRedAreBlack(node.getRight());
+ }
+ else
+ {
+ Assert.fail("Children of Red are not both black");
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
index f4cdbbe02c..6c7094cac0 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -21,8 +21,12 @@
package org.apache.qpid.server.queue;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration.PropertiesConfiguration;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInternalException;
import org.apache.qpid.AMQSecurityException;
@@ -51,12 +55,6 @@ import org.apache.qpid.server.util.InternalBrokerBaseCase;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostImpl;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
public class SimpleAMQQueueTest extends InternalBrokerBaseCase
{
@@ -190,6 +188,13 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
// Check sending a message ends up with the subscriber
AMQMessage messageA = createMessage(new Long(24));
_queue.enqueue(messageA);
+ try
+ {
+ Thread.sleep(2000L);
+ }
+ catch(InterruptedException e)
+ {
+ }
assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
assertNull(((QueueContext)_subscription.getQueueContext())._releasedEntry);
@@ -431,6 +436,13 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
// Check sending a message ends up with the subscriber
AMQMessage messageA = createMessage(new Long(24));
_queue.enqueue(messageA);
+ try
+ {
+ Thread.sleep(2000L);
+ }
+ catch (InterruptedException e)
+ {
+ }
assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
// Check we cannot add a second subscriber to the queue
@@ -724,7 +736,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
assertEquals("No messages should have been delivered yet", 0, sub3.getMessages().size());
// call processQueue to deliver the messages
- testQueue.processQueue(new QueueRunner(testQueue, 1)
+ testQueue.processQueue(new QueueRunner(testQueue)
{
@Override
public void run()
@@ -827,7 +839,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
/**
* Tests that dequeued message is not copied as part of invocation of
- * {@link SimpleAMQQueue#copyMessagesToAnotherQueue(long, long, String, StoreContext)}
+ * {@link SimpleAMQQueue#copyMessagesToAnotherQueue(long, long, String, ServerTransaction)}
*/
public void testCopyMessagesWithDequeuedEntry()
{
@@ -845,7 +857,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
SimpleAMQQueue queue = createQueue(anotherQueueName);
// create transaction
- ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore());
// copy messages into another queue
_queue.copyMessagesToAnotherQueue(0, messageNumber, anotherQueueName, txn);
@@ -877,7 +889,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
/**
* Tests that dequeued message is not moved as part of invocation of
- * {@link SimpleAMQQueue#moveMessagesToAnotherQueue(long, long, String, StoreContext)}
+ * {@link SimpleAMQQueue#moveMessagesToAnotherQueue(long, long, String, ServerTransaction)}
*/
public void testMovedMessagesWithDequeuedEntry()
{
@@ -895,7 +907,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
SimpleAMQQueue queue = createQueue(anotherQueueName);
// create transaction
- ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore());
// move messages into another queue
_queue.moveMessagesToAnotherQueue(0, messageNumber, anotherQueueName, txn);
@@ -928,7 +940,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
/**
* Tests that messages in given range including dequeued one are deleted
* from the queue on invocation of
- * {@link SimpleAMQQueue#removeMessagesFromQueue(long, long, StoreContext)}
+ * {@link SimpleAMQQueue#removeMessagesFromQueue(long, long)}
*/
public void testRemoveMessagesFromQueueWithDequeuedEntry()
{
@@ -955,7 +967,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
/**
* Tests that dequeued message on the top is not accounted and next message
* is deleted from the queue on invocation of
- * {@link SimpleAMQQueue#deleteMessageFromTop(StoreContext)}
+ * {@link SimpleAMQQueue#deleteMessageFromTop()}
*/
public void testDeleteMessageFromTopWithDequeuedEntryOnTop()
{
@@ -984,7 +996,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
/**
* Tests that all messages including dequeued one are deleted from the queue
- * on invocation of {@link SimpleAMQQueue#clearQueue(StoreContext)}
+ * on invocation of {@link SimpleAMQQueue#clearQueue()}
*/
public void testClearQueueWithDequeuedEntry()
{
@@ -1050,10 +1062,12 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
{
/**
* Send a message and decrement latch
+ * @param entry
+ * @param batch
*/
- public void send(QueueEntry msg) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
- super.send(msg);
+ super.send(entry, batch);
latch.countDown();
}
};
@@ -1064,7 +1078,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
testQueue.registerSubscription(subscription, false);
// process queue
- testQueue.processQueue(new QueueRunner(testQueue, 1)
+ testQueue.processQueue(new QueueRunner(testQueue)
{
public void run()
{
@@ -1110,9 +1124,9 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
* Entries with even message id are considered
* dequeued!
*/
- protected QueueEntryImpl createQueueEntry(final ServerMessage message)
+ protected SimpleQueueEntryImpl createQueueEntry(final ServerMessage message)
{
- return new QueueEntryImpl(this, message)
+ return new SimpleQueueEntryImpl(this, message)
{
public boolean isDequeued()
{
@@ -1128,6 +1142,19 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
{
return !(((AMQMessage) message).getMessageId().longValue() % 2 == 0);
}
+
+ @Override
+ public boolean acquire(Subscription sub)
+ {
+ if(((AMQMessage) message).getMessageId().longValue() % 2 == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return super.acquire(sub);
+ }
+ }
};
}
};
@@ -1244,6 +1271,14 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
fail("Failure to put message on queue:" + e.getMessage());
}
}
+ try
+ {
+ Thread.sleep(2000L);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
}
/**
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java
new file mode 100644
index 0000000000..d8d78bbb84
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java
@@ -0,0 +1,59 @@
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SimpleQueueEntryImplTest extends QueueEntryImplTestBase {
+
+ private SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
+
+ public QueueEntryImpl getQueueEntryImpl(int msgId) throws AMQException {
+ ServerMessage message = new MockAMQMessage(msgId);
+ return queueEntryList.add(message);
+ }
+
+ public void testCompareTo()
+ {
+ assertTrue(_queueEntry.compareTo(_queueEntry2) < 0);
+ assertTrue(_queueEntry2.compareTo(_queueEntry3) < 0);
+ assertTrue(_queueEntry.compareTo(_queueEntry3) < 0);
+
+ assertTrue(_queueEntry2.compareTo(_queueEntry) > 0);
+ assertTrue(_queueEntry3.compareTo(_queueEntry2) > 0);
+ assertTrue(_queueEntry3.compareTo(_queueEntry) > 0);
+
+ assertTrue(_queueEntry.compareTo(_queueEntry) == 0);
+ assertTrue(_queueEntry2.compareTo(_queueEntry2) == 0);
+ assertTrue(_queueEntry3.compareTo(_queueEntry3) == 0);
+ }
+
+ public void testTraverseWithNoDeletedEntries()
+ {
+ QueueEntry current = _queueEntry;
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry2, current);
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry3, current);
+
+ current = current.getNextValidEntry();
+ assertNull(current);
+
+ }
+
+ public void testTraverseWithDeletedEntries()
+ {
+ // Delete 2nd queue entry
+ _queueEntry2.delete();
+ assertTrue(_queueEntry2.isDeleted());
+
+ QueueEntry current = _queueEntry;
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry3, current);
+
+ current = current.getNextValidEntry();
+ assertNull(current);
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
index 7136f07ca5..f3ba6a5495 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
@@ -22,21 +22,28 @@ package org.apache.qpid.server.queue;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
-import junit.framework.TestCase;
-
-public class SimpleQueueEntryListTest extends TestCase
+public class SimpleQueueEntryListTest extends QueueEntryListTestBase
{
+ private SimpleQueueEntryList _sqel;
+
private static final String SCAVENGE_PROP = "qpid.queue.scavenge_count";
String oldScavengeValue = null;
-
+
@Override
protected void setUp()
{
oldScavengeValue = System.setProperty(SCAVENGE_PROP, "9");
+ _sqel = new SimpleQueueEntryList(_testQueue);
+ for(int i = 1; i <= 100; i++)
+ {
+ final ServerMessage msg = new MockAMQMessage(i);
+ final QueueEntry bleh = _sqel.add(msg);
+ assertNotNull("QE should not have been null", bleh);
+ }
}
@Override
@@ -52,19 +59,28 @@ public class SimpleQueueEntryListTest extends TestCase
}
}
- /**
- * Tests the behavior of the next(QueuyEntry) method.
- */
- public void testNext() throws Exception
+ @Override
+ public QueueEntryList getTestList()
{
- SimpleQueueEntryList sqel = new SimpleQueueEntryList(null);
- int i = 0;
+ return _sqel;
+ }
+
+ @Override
+ public long getExpectedFirstMsgId()
+ {
+ return 1;
+ }
- QueueEntry queueEntry1 = sqel.add(new MockAMQMessage(i++));
- QueueEntry queueEntry2 = sqel.add(new MockAMQMessage(i++));
+ @Override
+ public int getExpectedListLength()
+ {
+ return 100;
+ }
- assertSame(queueEntry2, sqel.next(queueEntry1));
- assertNull(sqel.next(queueEntry2));
+ @Override
+ public AMQMessage getTestMessageToAdd() throws AMQException
+ {
+ return new MockAMQMessage(1l);
}
public void testScavenge() throws Exception
@@ -82,7 +98,7 @@ public class SimpleQueueEntryListTest extends TestCase
entriesMap.put(i,bleh);
}
- QueueEntryImpl head = ((QueueEntryImpl) sqel.getHead());
+ SimpleQueueEntryImpl head = sqel.getHead();
//We shall now delete some specific messages mid-queue that will lead to
//requiring a scavenge once the requested threshold of 9 deletes is passed
@@ -99,11 +115,10 @@ public class SimpleQueueEntryListTest extends TestCase
assertTrue("Failed to delete QueueEntry", entriesMap.remove(14).delete());
verifyDeletedButPresentBeforeScavenge(head, 14);
-
//Delete message 20 only
assertTrue("Failed to delete QueueEntry", entriesMap.remove(20).delete());
verifyDeletedButPresentBeforeScavenge(head, 20);
-
+
//Delete messages 81 to 84
assertTrue("Failed to delete QueueEntry", entriesMap.remove(81).delete());
verifyDeletedButPresentBeforeScavenge(head, 81);
@@ -113,35 +128,35 @@ public class SimpleQueueEntryListTest extends TestCase
verifyDeletedButPresentBeforeScavenge(head, 83);
assertTrue("Failed to delete QueueEntry", entriesMap.remove(84).delete());
verifyDeletedButPresentBeforeScavenge(head, 84);
-
+
//Delete message 99 - this is the 10th message deleted that is after the queue head
//and so will invoke the scavenge() which is set to go after 9 previous deletions
assertTrue("Failed to delete QueueEntry", entriesMap.remove(99).delete());
verifyAllDeletedMessagedNotPresent(head, entriesMap);
}
-
- private void verifyDeletedButPresentBeforeScavenge(QueueEntryImpl head, long messageId)
+
+ private void verifyDeletedButPresentBeforeScavenge(SimpleQueueEntryImpl head, long messageId)
{
//Use the head to get the initial entry in the queue
- QueueEntryImpl entry = head._next;
-
+ SimpleQueueEntryImpl entry = head.getNextNode();
+
for(long i = 1; i < messageId ; i++)
{
assertEquals("Expected QueueEntry was not found in the list", i, (long) entry.getMessage().getMessageNumber());
- entry = entry._next;
+ entry = entry.getNextNode();
}
-
+
assertTrue("Entry should have been deleted", entry.isDeleted());
}
-
- private void verifyAllDeletedMessagedNotPresent(QueueEntryImpl head, Map<Integer,QueueEntry> remainingMessages)
+
+ private void verifyAllDeletedMessagedNotPresent(SimpleQueueEntryImpl head, Map<Integer,QueueEntry> remainingMessages)
{
//Use the head to get the initial entry in the queue
- QueueEntryImpl entry = head._next;
-
+ SimpleQueueEntryImpl entry = head.getNextNode();
+
assertNotNull("Initial entry should not have been null", entry);
-
+
int count = 0;
while (entry != null)
@@ -149,62 +164,56 @@ public class SimpleQueueEntryListTest extends TestCase
assertFalse("Entry " + entry.getMessage().getMessageNumber() + " should not have been deleted", entry.isDeleted());
assertNotNull("QueueEntry was not found in the list of remaining entries",
remainingMessages.get(entry.getMessage().getMessageNumber().intValue()));
-
+
count++;
- entry = entry._next;
+ entry = entry.getNextNode();
}
-
+
assertEquals("Count should have been equal",count,remainingMessages.size());
}
- public void testDequedMessagedNotPresentInIterator()
+ public void testGettingNextElement()
{
- int numberOfMessages = 10;
- SimpleQueueEntryList entryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
- QueueEntry[] entries = new QueueEntry[numberOfMessages];
+ final int numberOfEntries = 5;
+ final SimpleQueueEntryImpl[] entries = new SimpleQueueEntryImpl[numberOfEntries];
+ final SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test"));
- for(int i = 0; i < numberOfMessages ; i++)
+ // create test entries
+ for(int i = 0; i < numberOfEntries; i++)
{
- AMQMessage message = null;;
- try
- {
- message = new MockAMQMessage(i);
- }
- catch (AMQException e)
- {
- fail("Failure to create a mock message:" + e.getMessage());
- }
- QueueEntry entry = entryList.add(message);
- assertNotNull("QE should not be null", entry);
- entries[i]= entry;
+ AMQMessage message = new MockAMQMessage(i);
+ entries[i] = queueEntryList.add(message);
}
- // dequeue all even messages
- for (QueueEntry queueEntry : entries)
+ // test getNext for not acquired entries
+ for(int i = 0; i < numberOfEntries; i++)
{
- long i = ((AMQMessage)queueEntry.getMessage()).getMessageId().longValue();
- if (i%2 == 0)
+ final SimpleQueueEntryImpl next = entries[i].getNextValidEntry();
+
+ if(i < numberOfEntries - 1)
+ {
+ assertEquals("Unexpected entry from QueueEntryImpl#getNext()", entries[i + 1], next);
+ }
+ else
{
- queueEntry.acquire();
- queueEntry.dequeue();
+ assertNull("The next entry after the last should be null", next);
}
}
- // iterate and check that dequeued messages are not returned by iterator
- QueueEntryIterator it = entryList.iterator();
- int counter = 0;
- int i = 1;
- while (it.advance())
- {
- QueueEntry entry = it.getNode();
- Long id = ((AMQMessage)entry.getMessage()).getMessageId();
- assertEquals("Expected message with id " + i + " but got message with id "
- + id, new Long(i), id);
- counter++;
- i += 2;
- }
- int expectedNumber = numberOfMessages / 2;
- assertEquals("Expected " + expectedNumber + " number of entries in iterator but got " + counter,
- expectedNumber, counter);
+ // delete second
+ entries[1].acquire();
+ entries[1].delete();
+
+ // dequeue third
+ entries[2].acquire();
+ entries[2].dequeue();
+
+ SimpleQueueEntryImpl next = entries[2].getNextValidEntry();
+ assertEquals("expected forth entry", entries[3], next);
+ next = next.getNextValidEntry();
+ assertEquals("expected fifth entry", entries[4], next);
+ next = next.getNextValidEntry();
+ assertNull("The next entry after the last should be null", next);
}
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java
new file mode 100644
index 0000000000..43fb5b4cb3
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java
@@ -0,0 +1,62 @@
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SortedQueueEntryImplTest extends QueueEntryImplTestBase {
+
+ public final static String keys[] = { "CCC", "AAA", "BBB" };
+
+ private SelfValidatingSortedQueueEntryList queueEntryList = new SelfValidatingSortedQueueEntryList(new MockAMQQueue("test"),"KEY");
+
+ public QueueEntryImpl getQueueEntryImpl(int msgId) throws AMQException {
+ final ServerMessage message = new MockAMQMessage(msgId, "KEY", keys[msgId-1]);
+ return queueEntryList.add(message);
+ }
+
+ public void testCompareTo()
+ {
+ assertTrue(_queueEntry.compareTo(_queueEntry2) > 0);
+ assertTrue(_queueEntry.compareTo(_queueEntry3) > 0);
+
+ assertTrue(_queueEntry2.compareTo(_queueEntry3) < 0);
+ assertTrue(_queueEntry2.compareTo(_queueEntry) < 0);
+
+ assertTrue(_queueEntry3.compareTo(_queueEntry2) > 0);
+ assertTrue(_queueEntry3.compareTo(_queueEntry) < 0);
+
+ assertTrue(_queueEntry.compareTo(_queueEntry) == 0);
+ assertTrue(_queueEntry2.compareTo(_queueEntry2) == 0);
+ assertTrue(_queueEntry3.compareTo(_queueEntry3) == 0);
+ }
+
+ public void testTraverseWithNoDeletedEntries()
+ {
+ QueueEntry current = _queueEntry2;
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry3, current);
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry, current);
+
+ current = current.getNextValidEntry();
+ assertNull(current);
+
+ }
+
+ public void testTraverseWithDeletedEntries()
+ {
+ // Delete 2nd queue entry
+ _queueEntry3.delete();
+ assertTrue(_queueEntry3.isDeleted());
+
+ QueueEntry current = _queueEntry2;
+
+ current = current.getNextValidEntry();
+ assertSame("Unexpected current entry",_queueEntry, current);
+
+ current = current.getNextValidEntry();
+ assertNull(current);
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java
new file mode 100644
index 0000000000..eca845644e
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java
@@ -0,0 +1,323 @@
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.message.AMQMessage;
+
+import java.util.Arrays;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SortedQueueEntryListTest extends QueueEntryListTestBase
+{
+ private static SelfValidatingSortedQueueEntryList _sqel;
+
+ public final static String keys[] = { " 73", " 18", " 11", "127", "166", "163", " 69", " 60", "191", "144",
+ " 17", "161", "145", "140", "157", " 47", "136", " 56", "176", " 81",
+ "195", " 96", " 2", " 68", "101", "141", "159", "187", "149", " 45",
+ " 64", "100", " 83", " 51", " 79", " 82", "180", " 26", " 61", " 62",
+ " 78", " 46", "147", " 91", "120", "164", " 92", "172", "188", " 50",
+ "111", " 89", " 4", " 8", " 16", "151", "122", "178", " 33", "124",
+ "171", "165", "116", "113", "155", "148", " 29", " 0", " 37", "131",
+ "146", " 57", "112", " 97", " 23", "108", "123", "117", "167", " 52",
+ " 98", " 6", "160", " 25", " 49", " 34", "182", "185", " 30", " 66",
+ "152", " 58", " 86", "118", "189", " 84", " 36", "104", " 7", " 76",
+ " 87", " 1", " 80", " 10", "142", " 59", "137", " 12", " 67", " 22",
+ " 9", "106", " 75", "109", " 93", " 42", "177", "134", " 77", " 88",
+ "114", " 43", "143", "135", " 55", "181", " 32", "174", "175", "184",
+ "133", "107", " 28", "126", "103", " 85", " 38", "158", " 39", "162",
+ "129", "194", " 15", " 24", " 19", " 35", "186", " 31", " 65", " 99",
+ "192", " 74", "156", " 27", " 95", " 54", " 70", " 13", "110", " 41",
+ " 90", "173", "125", "196", "130", "183", "102", "190", "132", "105",
+ " 21", " 53", "139", " 94", "115", " 48", " 44", "179", "128", " 14",
+ " 72", "119", "153", "168", "197", " 40", "150", "138", " 5", "154",
+ "169", " 71", "199", "198", "170", " 3", "121", " 20", " 63", "193" };
+
+ public final static String textkeys[] = { "AAA", "BBB", "CCC", "DDD", "EEE", "FFF", "GGG", "HHH", "III", "JJJ",
+ "KKK", "LLL", "MMM", "NNN", "OOO", "PPP", "QQQ", "RRR", "SSS", "TTT",
+ "UUU", "VVV", "XXX", "YYY", "ZZZ"};
+
+ private final static String keysSorted[] = keys.clone();
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ // Create result array
+ Arrays.sort(keysSorted);
+
+ // Create test list
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ // Build test list
+ long messageId = 0L;
+ for(final String key : keys)
+ {
+ final ServerMessage msg = generateTestMessage(messageId++, key);
+ _sqel.add(msg);
+ }
+
+ }
+
+ public QueueEntryList getTestList()
+ {
+ return _sqel;
+ }
+
+ public int getExpectedListLength()
+ {
+ return keys.length;
+ }
+
+ public long getExpectedFirstMsgId()
+ {
+ return 67L;
+ }
+
+ public ServerMessage getTestMessageToAdd() throws AMQException
+ {
+ return generateTestMessage(1, "test value");
+ }
+
+ private ServerMessage generateTestMessage(final long id, final String keyValue) throws AMQException
+ {
+ return new AMQMessage(new MockStoredMessage(id, "KEY", keyValue));
+ }
+
+ public void testIterator()
+ {
+ super.testIterator();
+
+ // Test sorted order of list
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count = 0;
+ while(iter.advance())
+ {
+ assertEquals("Sorted queue entry value does not match sorted key array",
+ keysSorted[count++], getSortedKeyValue(iter));
+ }
+ }
+
+ private Object getSortedKeyValue(QueueEntryIterator<?> iter)
+ {
+ return ((SortedQueueEntryImpl) iter.getNode()).getMessage().getMessageHeader().getHeader("KEY");
+ }
+
+ private Long getMessageId(QueueEntryIterator<?> iter)
+ {
+ return ((SortedQueueEntryImpl) iter.getNode()).getMessage().getMessageNumber();
+ }
+
+ public void testNonUniqueSortKeys() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ // Build test list
+ long messageId = 0L;
+ while(messageId < 200)
+ {
+ final ServerMessage msg = generateTestMessage(messageId++, "samekey");
+ _sqel.add(msg);
+ }
+
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count=0;
+ while(iter.advance())
+ {
+ assertEquals("Sorted queue entry value is not as expected", "samekey", getSortedKeyValue(iter));
+ assertEquals("Message id not as expected", Long.valueOf(count++), getMessageId(iter));
+ }
+ }
+
+ public void testNullSortKeys() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ // Build test list
+ long messageId = 0L;
+ while(messageId < 200)
+ {
+ final ServerMessage msg = generateTestMessage(messageId++, null);
+ _sqel.add(msg);
+ }
+
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count=0;
+ while(iter.advance())
+ {
+ assertNull("Sorted queue entry value is not as expected", getSortedKeyValue(iter));
+ assertEquals("Message id not as expected", Long.valueOf(count++), getMessageId(iter)); }
+ }
+
+ public void testAscendingSortKeys() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ // Build test list
+ long messageId = 0L;
+ for(String textKey : textkeys)
+ {
+ final ServerMessage msg = generateTestMessage(messageId, textKey);
+ messageId++;
+ _sqel.add(msg);
+ }
+
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count=0;
+ while(iter.advance())
+ {
+ assertEquals("Sorted queue entry value is not as expected", textkeys[count], getSortedKeyValue(iter));
+ assertEquals("Message id not as expected", Long.valueOf(count), getMessageId(iter));
+ count++;
+ }
+ }
+
+ public void testDescendingSortKeys() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ // Build test list
+ long messageId = 0L;
+ for(int i=textkeys.length-1; i >=0; i--)
+ {
+ final ServerMessage msg = generateTestMessage(messageId, textkeys[i]);
+ messageId++;
+ _sqel.add(msg);
+ }
+
+ final QueueEntryIterator<?> iter = getTestList().iterator();
+ int count=0;
+ while(iter.advance())
+ {
+ assertEquals("Sorted queue entry value is not as expected", textkeys[count], getSortedKeyValue(iter));
+ assertEquals("Message id not as expected", Long.valueOf(textkeys.length-count-1), getMessageId(iter));
+ count++;
+ }
+ }
+
+ public void testInsertAfter() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ ServerMessage msg = generateTestMessage(1, "A");
+ _sqel.add(msg);
+
+ SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 1);
+
+ msg = generateTestMessage(2, "B");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "B", 2);
+ }
+
+ public void testInsertBefore() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ ServerMessage msg = generateTestMessage(1, "B");
+ _sqel.add(msg);
+
+ SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "B", 1);
+
+ msg = generateTestMessage(2, "A");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 2);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "B", 1);
+ }
+
+ public void testInsertInbetween() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ ServerMessage msg = generateTestMessage(1, "A");
+ _sqel.add(msg);
+ SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 1);
+
+ msg = generateTestMessage(2, "C");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "C", 2);
+
+ msg = generateTestMessage(3, "B");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "B", 3);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "C", 2);
+ }
+
+ public void testInsertAtHead() throws Exception
+ {
+ _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY");
+
+ ServerMessage msg = generateTestMessage(1, "B");
+ _sqel.add(msg);
+
+ SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "B", 1);
+
+ msg = generateTestMessage(2, "D");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "B", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "D", 2);
+
+ msg = generateTestMessage(3, "C");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "B", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "C", 3);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "D", 2);
+
+ msg = generateTestMessage(4, "A");
+ _sqel.add(msg);
+
+ entry = _sqel.next(_sqel.getHead());
+ validateEntry(entry, "A", 4);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "B", 1);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "C", 3);
+
+ entry = _sqel.next(entry);
+ validateEntry(entry, "D", 2);
+ }
+
+ private void validateEntry(final SortedQueueEntryImpl entry, final String expectedSortKey, final long expectedMessageId)
+ {
+ assertEquals("Sorted queue entry value is not as expected",
+ expectedSortKey, entry.getMessage().getMessageHeader().getHeader("KEY"));
+ assertEquals("Sorted queue entry id is not as expected",
+ Long.valueOf(expectedMessageId), entry.getMessage().getMessageNumber());
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java
deleted file mode 100644
index 6ca88d1796..0000000000
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java
+++ /dev/null
@@ -1,81 +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.store;
-
-import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import org.apache.qpid.server.protocol.InternalTestProtocolSession;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-
-import java.util.List;
-
-public class MessageStoreShutdownTest extends InternalBrokerBaseCase
-{
-
- public void test()
- {
- subscribe(getSession(), getChannel(), getQueue());
-
- try
- {
- publishMessages(getSession(), getChannel(), 1);
- }
- catch (AMQException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- fail(e.getMessage());
- }
-
- try
- {
- getRegistry().close();
- }
- catch (Exception e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- fail(e.getMessage());
- }
-
- assertTrue("Session should now be closed", getSession().isClosed());
-
-
- //Test attempting to modify the broker state after session has been closed.
-
- //The Message should have been removed from the unacked list.
-
- //Ack Messages
- List<InternalTestProtocolSession.DeliveryPair> list = getSession().getDelivers(getChannel().getChannelId(), new AMQShortString("sgen_1"), 1);
-
- InternalTestProtocolSession.DeliveryPair pair = list.get(0);
-
- try
- {
- // The message should now be requeued and so unable to ack it.
- getChannel().acknowledgeMessage(pair.getDeliveryTag(), false);
- }
- catch (AMQException e)
- {
- assertEquals("Incorrect exception thrown", "Single ack on delivery tag 1 not known for channel:1", e.getMessage());
- }
-
- }
-
-}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
index 3acd064fd7..1d0a9d6316 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
@@ -689,7 +689,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase
if (usePriority)
{
queueArguments = new FieldTable();
- queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+ queueArguments.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), DEFAULT_PRIORTY_LEVEL);
}
if (lastValueQueue)
@@ -767,7 +767,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase
private void bindAllQueuesToExchange(Exchange exchange, AMQShortString routingKey)
{
FieldTable queueArguments = new FieldTable();
- queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+ queueArguments.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), DEFAULT_PRIORTY_LEVEL);
QueueRegistry queueRegistry = getVirtualHost().getQueueRegistry();
@@ -781,7 +781,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase
private void bindAllTopicQueuesToExchange(Exchange exchange, AMQShortString routingKey)
{
FieldTable queueArguments = new FieldTable();
- queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+ queueArguments.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), DEFAULT_PRIORTY_LEVEL);
QueueRegistry queueRegistry = getVirtualHost().getQueueRegistry();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
index be3e1228a6..4a74596d02 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
@@ -125,6 +125,12 @@ public class MockSubscription implements Subscription
return queue;
}
+ public boolean trySendLock()
+ {
+ return _stateChangeLock.tryLock();
+ }
+
+
public void getSendLock()
{
_stateChangeLock.lock();
@@ -202,7 +208,11 @@ public class MockSubscription implements Subscription
{
}
- public void send(QueueEntry entry) throws AMQException
+ public void releaseQueueEntry(QueueEntry queueEntry)
+ {
+ }
+
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
if (messages.contains(entry))
{
@@ -211,6 +221,12 @@ public class MockSubscription implements Subscription
messages.add(entry);
}
+ @Override
+ public void flushBatched()
+ {
+
+ }
+
public void setQueueContext(AMQQueue.Context queueContext)
{
_queueContext = queueContext;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java
new file mode 100644
index 0000000000..78ba8c1645
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java
@@ -0,0 +1,229 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.transport;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.server.configuration.MockConnectionConfig;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.transport.Binary;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
+
+public class ServerConnectionMBeanTest extends InternalBrokerBaseCase
+{
+ private ServerConnection _serverConnection;
+ private ServerSessionMock _serverSession;
+ private ServerConnectionMBean _mbean;
+ private List<Session> _sessions = new ArrayList<Session>();
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ final VirtualHost vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+ _serverConnection = new ServerConnection(1)
+ {
+ protected Collection<Session> getChannels()
+ {
+ return _sessions;
+ }
+ public Session getSession(int channelId)
+ {
+ for(Session session : _sessions)
+ {
+ if (session.getChannel() == channelId)
+ {
+ return session;
+ }
+ }
+ return null;
+ }
+ @Override
+ public AtomicLong getLastIoTime()
+ {
+ return new AtomicLong(1);
+ }
+ };
+ final MockConnectionConfig config = new MockConnectionConfig(UUID.randomUUID(), null, null,
+ false, 1, vhost, "address", Boolean.TRUE, Boolean.TRUE, Boolean.TRUE,
+ "authid", "remoteProcessName", new Integer(1967), new Integer(1970), vhost.getConfigStore(), Boolean.FALSE);
+ _serverConnection.setConnectionConfig(config);
+ _serverConnection.setVirtualHost(vhost);
+ _serverConnection.setConnectionDelegate(new ServerConnectionDelegate(getRegistry(), ""));
+ _serverSession = new ServerSessionMock(_serverConnection, 1);
+ _mbean = (ServerConnectionMBean) _serverConnection.getManagedObject();
+ }
+
+ public void testChannels() throws Exception
+ {
+ // check the channel count is correct
+ TabularData tabularData = _mbean.channels();
+
+ int channelCount = tabularData.size();
+ assertEquals("Unexpected number of channels",1,channelCount);
+ _sessions.add(new ServerSession(_serverConnection, new ServerSessionDelegate(),
+ new Binary(getName().getBytes()), 2 , _serverConnection.getConfig()));
+
+ channelCount = _mbean.channels().size();
+ assertEquals("Unexpected number of channels",2,channelCount);
+
+ final CompositeData chanresult = tabularData.get(new Integer[]{1});
+ assertNotNull(chanresult);
+ assertEquals("Unexpected channel id", new Integer(1),(Integer)chanresult.get(ManagedConnection.CHAN_ID));
+ assertNull("Unexpected default queue", chanresult.get(ManagedConnection.DEFAULT_QUEUE));
+ assertFalse("Unexpected transactional flag", (Boolean)chanresult.get(ManagedConnection.TRANSACTIONAL));
+ assertFalse("Flow should have been blocked", (Boolean)chanresult.get(ManagedConnection.FLOW_BLOCKED));
+ assertEquals("Unexpected unack'd count", new Integer(1967), (Integer)chanresult.get(ManagedConnection.UNACKED_COUNT));
+ }
+
+ public void testMaxChannels() throws Exception
+ {
+ _serverConnection.getConnectionDelegate().setChannelMax(10001);
+ assertEquals("Max channels not got correctly", new Long(10001), _mbean.getMaximumNumberOfChannels());
+ }
+
+ public void testRollback() throws Exception
+ {
+ _mbean.rollbackTransactions(1);
+ assertFalse("Rollback performed despite not being transacted", _serverSession.isRolledback());
+
+ _serverSession.setTransactional(true);
+ _mbean.rollbackTransactions(1);
+ assertTrue("Rollback not performed", _serverSession.isRolledback());
+
+ try
+ {
+ _mbean.rollbackTransactions(2);
+ fail("Exception expected");
+ }
+ catch (JMException jme)
+ {
+ //pass
+ }
+ }
+
+ public void testCommit() throws Exception
+ {
+ _mbean.commitTransactions(1);
+ assertFalse("Commit performed despite not being transacted", _serverSession.isCommitted());
+
+ _serverSession.setTransactional(true);
+ _mbean.commitTransactions(1);
+ assertTrue("Commit not performed", _serverSession.isCommitted());
+
+ try
+ {
+ _mbean.commitTransactions(2);
+ fail("Exception expected");
+ }
+ catch (JMException jme)
+ {
+ //pass
+ }
+ }
+
+ public void testGetName()
+ {
+ assertEquals("Unexpected Object Instance Name", "\"address\"", _mbean.getObjectInstanceName());
+ }
+
+ public void testEnableStatistics()
+ {
+ assertFalse("Unexpected statistics enable flag", _mbean.isStatisticsEnabled());
+ _mbean.setStatisticsEnabled(true);
+ assertTrue("Unexpected statistics enable flag", _mbean.isStatisticsEnabled());
+ }
+
+ public void testLastIOTime()
+ {
+ assertEquals("Unexpected last IO time", new Date(1), _mbean.getLastIoTime());
+ }
+
+ private class ServerSessionMock extends ServerSession
+ {
+ private int _channelId = 0;
+ private boolean _committed = false;
+ private boolean _rolledback = false;
+ private boolean _transacted = false;
+
+ ServerSessionMock(Connection connection, int channelId)
+ {
+ super(connection, new ServerSessionDelegate(), new Binary(String.valueOf(channelId).getBytes()), 1 , _serverConnection.getConfig());
+ _channelId = channelId;
+ _sessions.add(this);
+ }
+
+ public int getChannel()
+ {
+ return _channelId;
+ }
+
+ @Override
+ public void commit()
+ {
+ _committed = true;
+ }
+
+ @Override
+ public void rollback()
+ {
+ _rolledback = true;
+ }
+
+ public boolean isCommitted()
+ {
+ return _committed;
+ }
+
+ public boolean isRolledback()
+ {
+ return _rolledback;
+ }
+
+ @Override
+ public int getUnacknowledgedMessageCount()
+ {
+ return 1967;
+ }
+
+ public boolean isTransactional()
+ {
+ return _transacted;
+ }
+
+ public void setTransactional(boolean transacted)
+ {
+ _transacted = transacted;
+ }
+ }
+}
diff --git a/qpid/java/build.deps b/qpid/java/build.deps
index 17f963ece7..db28b33b21 100644
--- a/qpid/java/build.deps
+++ b/qpid/java/build.deps
@@ -29,6 +29,10 @@ commons-logging=lib/commons-logging-1.0.4.jar
derby-db=lib/derby-10.6.1.0.jar
geronimo-jms=lib/geronimo-jms_1.1_spec-1.0.jar
+geronimo-j2ee=lib/geronimo-j2ee-connector_1.5_spec-2.0.0.jar
+geronimo-jta=lib/geronimo-jta_1.1_spec-1.1.1.jar
+geronimo-kernel=lib/geronimo-kernel-2.2.1.jar
+geronimo-openejb=lib/geronimo-ejb_3.0_spec-1.0.1.jar
junit=lib/junit-3.8.1.jar
@@ -138,7 +142,11 @@ broker-plugins-experimental-info.test.libs=${test.libs} ${servlet-api} ${jetty}
management-eclipse-plugin.test.libs=${test.libs}
management-common.test.libs=${test.libs}
+# JCA Resource adapter
+ra.libs=${geronimo-j2ee} ${geronimo-jta} ${geronimo-jms} ${slf4j-api} ${geronimo-kernel} ${geronimo-openejb}
+
# optional bdbstore module deps
bdb-je=lib/bdbstore/je-4.0.117.jar
bdbstore.libs=${bdb-je}
bdbstore.test.libs=${test.libs}
+
diff --git a/qpid/java/build.xml b/qpid/java/build.xml
index e6c154d3d0..1f7de49df6 100644
--- a/qpid/java/build.xml
+++ b/qpid/java/build.xml
@@ -32,8 +32,9 @@
<property name="modules.management" value="${management}"/>
<property name="modules.plugin" value="${broker-plugins} ${client-plugins}"/>
<property name="modules.opt" value=""/>
+ <property name="modules.jca" value="jca"/>
<property name="modules" value="${modules.core} ${modules.examples}
- ${modules.management} ${modules.tests} ${modules.plugin} ${modules.opt}"/>
+ ${modules.management} ${modules.tests} ${modules.plugin} ${modules.opt} ${modules.jca}"/>
<property name="qpid.jar" location="${build.lib}/qpid-all.jar"/>
<basename property="qpid.jar.name" file="${qpid.jar}"/>
diff --git a/qpid/java/client-plugins/.gitignore b/qpid/java/client-plugins/.gitignore
index e69de29bb2..e5f63e731b 100644
--- a/qpid/java/client-plugins/.gitignore
+++ b/qpid/java/client-plugins/.gitignore
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Holder file to ensure git-svn creates this otherwise empty
+# directory, necessary for supporting older Ant versions.
diff --git a/qpid/java/client/src/main/java/client.bnd b/qpid/java/client/src/main/java/client.bnd
index bd13844e8e..d92d582ec8 100755
--- a/qpid/java/client/src/main/java/client.bnd
+++ b/qpid/java/client/src/main/java/client.bnd
@@ -23,4 +23,5 @@ Bundle-SymbolicName: qpid-client
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
Bundle-RequiredExecutionEnvironment: J2SE-1.5
+DynamicImport-Package: *
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
index c0d4d8a893..b343820d80 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -264,12 +264,30 @@ public class AMQBrokerDetails implements BrokerDetails
public boolean getBooleanProperty(String propName)
{
- if (_options.containsKey(propName))
- {
- return Boolean.parseBoolean(_options.get(propName));
- }
-
- return false;
+ return getBooleanProperty(propName, false);
+ }
+
+ public boolean getBooleanProperty(String propName, boolean defaultValue)
+ {
+ if (_options.containsKey(propName))
+ {
+ if (_options.get(propName).equalsIgnoreCase("false"))
+ {
+ return false;
+ }
+ else if (_options.get(propName).equalsIgnoreCase("true"))
+ {
+ return true;
+ }
+ else
+ {
+ return defaultValue;
+ }
+ }
+ else
+ {
+ return defaultValue;
+ }
}
public void setTimeout(long timeout)
@@ -439,7 +457,7 @@ public class AMQBrokerDetails implements BrokerDetails
if (getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY) != null)
{
conSettings.setTcpNodelay(
- getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY));
+ getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY,true));
}
return conSettings;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
index ad7885f195..6879fe0cfd 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -284,7 +284,10 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10");
- _logger.debug("AMQP version " + amqpVersion);
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("AMQP version " + amqpVersion);
+ }
_failoverPolicy = new FailoverPolicy(connectionURL, this);
BrokerDetails brokerDetails = _failoverPolicy.getCurrentBrokerDetails();
@@ -1485,4 +1488,5 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
return _lastFailoverTime;
}
+
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
index afb0e45f7a..7fc1d25c18 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
@@ -50,6 +50,8 @@ public interface AMQConnectionDelegate
XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
+ XASession createXASession(int ackMode) throws JMSException;
+
void failoverPrep();
void resubscribeSessions() throws JMSException, AMQException, FailoverException;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index 5e4f84ce9f..802cc55b0e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -74,12 +74,6 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
org.apache.qpid.transport.Connection _qpidConnection;
private ConnectionException exception = null;
- static
- {
- // Register any configured SASL client factories.
- org.apache.qpid.client.security.DynamicSaslRegistrar.registerSaslProviders();
- }
-
//--- constructor
public AMQConnectionDelegate_0_10(AMQConnection conn)
{
@@ -170,6 +164,35 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
return session;
}
+ @Override
+ public XASession createXASession(int ackMode)
+ throws JMSException
+ {
+
+ _conn.checkNotClosed();
+
+ if (_conn.channelLimitReached())
+ {
+ throw new ChannelLimitReachedException(_conn.getMaximumChannelCount());
+ }
+
+ int channelId = _conn.getNextChannelID();
+ XASessionImpl session;
+ try
+ {
+ session = new XASessionImpl(_qpidConnection, _conn, channelId, ackMode, (int)_conn.getMaxPrefetch(), (int)_conn.getMaxPrefetch() / 2);
+ _conn.registerSession(channelId, session);
+ if (_conn._started)
+ {
+ session.start();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new JMSAMQException("cannot create session", e);
+ }
+ return session;
+ }
/**
* Make a connection with the broker
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index bff4df0e93..399534e834 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -161,8 +161,8 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
_conn._failoverPolicy.attainedConnection();
_conn._connected = true;
return null;
- }
- else
+ }
+ else
{
return _conn._protocolHandler.getSuggestedProtocolVersion();
}
@@ -175,11 +175,16 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
return createSession(transacted, acknowledgeMode, prefetch, prefetch);
}
+
public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException
{
throw new UnsupportedOperationException("0_8 version does not provide XA support");
}
+ public XASession createXASession(int ackMode) throws JMSException
+ {
+ throw new UnsupportedOperationException("0_8 version does not provide XA support");
+ }
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode,
final int prefetchHigh, final int prefetchLow) throws JMSException
{
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
index f0c003e02a..700073488e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
@@ -46,6 +46,12 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
{
private final ConnectionURL _connectionDetails;
+ // The default constructor is necessary to allow AMQConnectionFactory to be deserialised from JNDI
+ public AMQConnectionFactory()
+ {
+ _connectionDetails = null;
+ }
+
public AMQConnectionFactory(final String url) throws URLSyntaxException
{
if (url == null)
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
index f9f50d9150..ee55eb9ce9 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
@@ -34,7 +34,6 @@ import org.apache.qpid.url.URLSyntaxException;
public class AMQConnectionURL implements ConnectionURL
{
-
private String _url;
private String _failoverMethod;
private Map<String, String> _failoverOptions;
@@ -279,15 +278,6 @@ public class AMQConnectionURL implements ConnectionURL
sb.append(URLHelper.printOptions(_failoverOptions));
sb.append("'");
}
-
- for (String key : _options.keySet())
- {
- if (!key.equals(OPTIONS_FAILOVER) || !key.equals(OPTIONS_BROKERLIST))
- {
- sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR).append(key).append("='");
- sb.append(_options.get(key)).append("'");
- }
- }
return sb.toString();
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
index f9a38138ba..1df809c67c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -75,6 +75,8 @@ public abstract class AMQDestination implements Destination, Referenceable
private boolean _exchangeExistsChecked;
+ private RejectBehaviour _rejectBehaviour;
+
public static final int QUEUE_TYPE = 1;
public static final int TOPIC_TYPE = 2;
public static final int UNKNOWN_TYPE = 3;
@@ -227,6 +229,8 @@ public abstract class AMQDestination implements Destination, Referenceable
_queueName = binding.getQueueName() == null ? null : binding.getQueueName();
_routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey();
_bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys();
+ final String rejectBehaviourValue = binding.getOption(BindingURL.OPTION_REJECT_BEHAVIOUR);
+ _rejectBehaviour = rejectBehaviourValue == null ? null : RejectBehaviour.valueOf(rejectBehaviourValue.toUpperCase());
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName)
@@ -294,7 +298,7 @@ public abstract class AMQDestination implements Destination, Referenceable
_bindingKeys = bindingKeys == null || bindingKeys.length == 0 ? new AMQShortString[0] : bindingKeys;
_destSyntax = DestSyntax.BURL;
_browseOnly = browseOnly;
-
+ _rejectBehaviour = null;
if (_logger.isDebugEnabled())
{
_logger.debug("Based on " + toString() + " the selected destination syntax is " + _destSyntax);
@@ -499,6 +503,13 @@ public abstract class AMQDestination implements Destination, Referenceable
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
+ if (_rejectBehaviour != null)
+ {
+ sb.append(BindingURL.OPTION_REJECT_BEHAVIOUR);
+ sb.append("='" + _rejectBehaviour + "'");
+ sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ }
+
//removeKey the last char '?' if there is no options , ',' if there are.
sb.deleteCharAt(sb.length() - 1);
url = sb.toString();
@@ -842,4 +853,19 @@ public abstract class AMQDestination implements Destination, Referenceable
{
return _addressResolved.get() > time;
}
+
+ /**
+ * This option is only applicable for 0-8/0-9/0-9-1 protocols connection
+ * <p>
+ * It tells the client to delegate the requeue/DLQ decision to the
+ * server .If this option is not specified, the messages won't be moved to
+ * the DLQ (or dropped) when delivery count exceeds the maximum.
+ *
+ * @return destination reject behaviour
+ */
+ public RejectBehaviour getRejectBehaviour()
+ {
+ return _rejectBehaviour;
+ }
+
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
index d96544adf8..3f9eadeef3 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
@@ -30,6 +30,7 @@ import javax.jms.Queue;
import javax.jms.QueueBrowser;
import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
public class AMQQueueBrowser implements QueueBrowser
@@ -112,9 +113,12 @@ public class AMQQueueBrowser implements QueueBrowser
public QueueBrowserEnumeration(BasicMessageConsumer consumer) throws JMSException
{
- _nextMessage = consumer == null ? null : consumer.receiveBrowse();
+ if (consumer != null)
+ {
+ _consumer = consumer;
+ prefetchMessage();
+ }
_logger.info("QB:created with first element:" + _nextMessage);
- _consumer = consumer;
}
public boolean hasMoreElements()
@@ -126,18 +130,46 @@ public class AMQQueueBrowser implements QueueBrowser
public Object nextElement()
{
Message msg = _nextMessage;
+ if (msg == null)
+ {
+ throw new NoSuchElementException("No messages") ;
+ }
try
{
_logger.info("QB:nextElement about to receive");
- _nextMessage = _consumer.receiveBrowse();
+ prefetchMessage();
_logger.info("QB:nextElement received:" + _nextMessage);
}
catch (JMSException e)
{
_logger.warn("Exception caught while queue browsing", e);
_nextMessage = null;
+ try
+ {
+ closeConsumer() ;
+ }
+ catch (final JMSException jmse) {} // ignore
}
return msg;
}
- }
+
+ private void prefetchMessage() throws JMSException
+ {
+ _nextMessage = _consumer.receiveBrowse();
+ if (_nextMessage == null)
+ {
+ closeConsumer() ;
+ }
+ }
+
+ private void closeConsumer() throws JMSException
+ {
+ if (_consumer != null)
+ {
+ BasicMessageConsumer consumer = _consumer ;
+ _consumer = null ;
+ consumer.close() ;
+ }
+ }
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index ef44221ec1..8984b7ca8c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -310,7 +310,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Holds the highest received delivery tag. */
protected final AtomicLong _highestDeliveryTag = new AtomicLong(-1);
private final AtomicLong _rollbackMark = new AtomicLong(-1);
-
+
+ /** Pre-fetched message tags */
+ protected ConcurrentLinkedQueue<Long> _prefetchedMessageTags = new ConcurrentLinkedQueue<Long>();
+
/** All the not yet acknowledged message tags */
protected ConcurrentLinkedQueue<Long> _unacknowledgedMessageTags = new ConcurrentLinkedQueue<Long>();
@@ -2925,11 +2928,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_producers.put(new Long(producerId), producer);
}
- private void rejectAllMessages(boolean requeue)
- {
- rejectMessagesForConsumerTag(0, requeue, true);
- }
-
/**
* @param consumerTag The consumerTag to prune from queue or all if null
* @param requeue Should the removed messages be requeued (or discarded. Possibly to DLQ)
@@ -3235,7 +3233,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
for (C consumer : _consumers.values())
{
List<Long> tags = consumer.drainReceiverQueueAndRetrieveDeliveryTags();
- _unacknowledgedMessageTags.addAll(tags);
+ _prefetchedMessageTags.addAll(tags);
}
setConnectionStopped(isStopped);
@@ -3345,7 +3343,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else if (_usingDispatcherForCleanup)
{
- _unacknowledgedMessageTags.add(deliveryTag);
+ _prefetchedMessageTags.add(deliveryTag);
}
else
{
@@ -3548,4 +3546,5 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_logger.debug("Rollback mark is set to " + _rollbackMark.get());
}
}
+
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index 7e5edef38d..756b5cacb0 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -27,11 +27,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
import javax.jms.Destination;
import javax.jms.JMSException;
@@ -47,8 +50,8 @@ import org.apache.qpid.client.message.AMQMessageDelegateFactory;
import org.apache.qpid.client.message.FieldTableSupport;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import org.apache.qpid.client.message.UnprocessedMessage_0_10;
+import org.apache.qpid.client.messaging.address.AddressHelper;
import org.apache.qpid.client.messaging.address.Link;
-import org.apache.qpid.client.messaging.address.Link.Reliability;
import org.apache.qpid.client.messaging.address.Node.ExchangeNode;
import org.apache.qpid.client.messaging.address.Node.QueueNode;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
@@ -142,9 +145,9 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
private int unackedCount = 0;
/**
- * USed to store the range of in tx messages
+ * Used to store the range of in tx messages
*/
- private RangeSet _txRangeSet = new RangeSet();
+ private final RangeSet _txRangeSet = new RangeSet();
private int _txSize = 0;
//--- constructors
@@ -457,18 +460,33 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public void sendRecover() throws AMQException, FailoverException
{
// release all unacked messages
- RangeSet ranges = gatherUnackedRangeSet();
- getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ RangeSet all = new RangeSet();
+ RangeSet delivered = gatherRangeSet(_unacknowledgedMessageTags);
+ RangeSet prefetched = gatherRangeSet(_prefetchedMessageTags);
+ for (Iterator<Range> deliveredIter = delivered.iterator(); deliveredIter.hasNext();)
+ {
+ Range range = deliveredIter.next();
+ all.add(range);
+ }
+ for (Iterator<Range> prefetchedIter = prefetched.iterator(); prefetchedIter.hasNext();)
+ {
+ Range range = prefetchedIter.next();
+ all.add(range);
+ }
+ flushProcessed(all, false);
+ getQpidSession().messageRelease(delivered, Option.SET_REDELIVERED);
+ getQpidSession().messageRelease(prefetched);
+
// We need to sync so that we get notify of an error.
sync();
}
- private RangeSet gatherUnackedRangeSet()
+ private RangeSet gatherRangeSet(ConcurrentLinkedQueue<Long> messageTags)
{
RangeSet ranges = new RangeSet();
while (true)
{
- Long tag = _unacknowledgedMessageTags.poll();
+ Long tag = messageTags.poll();
if (tag == null)
{
break;
@@ -480,12 +498,15 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
return ranges;
}
-
public void releaseForRollback()
{
- getQpidSession().messageRelease(_txRangeSet, Option.SET_REDELIVERED);
- _txRangeSet.clear();
- _txSize = 0;
+ if (_txSize > 0)
+ {
+ flushProcessed(_txRangeSet, false);
+ getQpidSession().messageRelease(_txRangeSet, Option.SET_REDELIVERED);
+ _txRangeSet.clear();
+ _txSize = 0;
+ }
}
/**
@@ -499,7 +520,15 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
// The value of requeue is always true
RangeSet ranges = new RangeSet();
ranges.add((int) deliveryTag);
- getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ flushProcessed(ranges, false);
+ if (requeue)
+ {
+ getQpidSession().messageRelease(ranges);
+ }
+ else
+ {
+ getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ }
//I don't think we need to sync
}
@@ -737,7 +766,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
Map<String,Object> arguments = new HashMap<String,Object>();
if (noLocal)
{
- arguments.put("no-local", true);
+ arguments.put(AddressHelper.NO_LOCAL, true);
}
getQpidSession().queueDeclare(queueName.toString(), "" , arguments,
@@ -1316,11 +1345,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
protected void acknowledgeImpl()
{
- RangeSet range = gatherUnackedRangeSet();
+ RangeSet ranges = gatherRangeSet(_unacknowledgedMessageTags);
- if(range.size() > 0 )
+ if(ranges.size() > 0 )
{
- messageAcknowledge(range, true);
+ messageAcknowledge(ranges, true);
getQpidSession().sync();
}
}
@@ -1333,6 +1362,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
// messages sent by the brokers following the first rollback
// after failover
_highestDeliveryTag.set(-1);
+ // Clear txRangeSet/unacknowledgedMessageTags so we don't complete commands corresponding to
+ //messages that came from the old broker.
+ _txRangeSet.clear();
+ _txSize = 0;
+ _unacknowledgedMessageTags.clear();
+ _prefetchedMessageTags.clear();
super.resubscribe();
+ getQpidSession().sync();
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index e33410f5fe..96df463481 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -21,6 +21,7 @@
package org.apache.qpid.client;
+import java.util.ArrayList;
import java.util.Map;
import javax.jms.Destination;
@@ -40,7 +41,6 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.AMQState;
import org.apache.qpid.client.state.AMQStateManager;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
-import org.apache.qpid.common.AMQPFilterTypes;
import org.apache.qpid.filter.MessageFilter;
import org.apache.qpid.framing.AMQFrame;
import org.apache.qpid.framing.AMQMethodBody;
@@ -62,7 +62,6 @@ import org.apache.qpid.framing.ExchangeBoundOkBody;
import org.apache.qpid.framing.ExchangeDeclareBody;
import org.apache.qpid.framing.ExchangeDeclareOkBody;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.FieldTableFactory;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.framing.QueueBindOkBody;
import org.apache.qpid.framing.QueueDeclareBody;
@@ -223,6 +222,8 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendRecover() throws AMQException, FailoverException
{
+ enforceRejectBehaviourDuringRecover();
+ _prefetchedMessageTags.clear();
_unacknowledgedMessageTags.clear();
if (isStrictAMQP())
@@ -259,6 +260,49 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
}
}
+ private void enforceRejectBehaviourDuringRecover()
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Prefetched message: _unacknowledgedMessageTags :" + _unacknowledgedMessageTags);
+ }
+ ArrayList<BasicMessageConsumer_0_8> consumersToCheck = new ArrayList<BasicMessageConsumer_0_8>(_consumers.values());
+ boolean messageListenerFound = false;
+ boolean serverRejectBehaviourFound = false;
+ for(BasicMessageConsumer_0_8 consumer : consumersToCheck)
+ {
+ if (consumer.isMessageListenerSet())
+ {
+ messageListenerFound = true;
+ }
+ if (RejectBehaviour.SERVER.equals(consumer.getRejectBehaviour()))
+ {
+ serverRejectBehaviourFound = true;
+ }
+ }
+ _logger.debug("about to pre-reject messages for " + consumersToCheck.size() + " consumer(s)");
+
+ if (serverRejectBehaviourFound)
+ {
+ //reject(false) any messages we don't want returned again
+ switch(_acknowledgeMode)
+ {
+ case Session.DUPS_OK_ACKNOWLEDGE:
+ case Session.AUTO_ACKNOWLEDGE:
+ if (!messageListenerFound)
+ {
+ break;
+ }
+ case Session.CLIENT_ACKNOWLEDGE:
+ for(Long tag : _unacknowledgedMessageTags)
+ {
+ rejectMessage(tag, false);
+ }
+ break;
+ }
+ }
+ }
+
public void releaseForRollback()
{
// Reject all the messages that have been received in this session and
@@ -267,6 +311,17 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
// Otherwise messages will be able to arrive out of order to a second
// consumer on the queue. Whilst this is within the JMS spec it is not
// user friendly and avoidable.
+ boolean normalRejectBehaviour = true;
+ for (BasicMessageConsumer_0_8 consumer : _consumers.values())
+ {
+ if(RejectBehaviour.SERVER.equals(consumer.getRejectBehaviour()))
+ {
+ normalRejectBehaviour = false;
+ //no need to consult other consumers now, found server behaviour.
+ break;
+ }
+ }
+
while (true)
{
Long tag = _deliveredMessageTags.poll();
@@ -275,13 +330,14 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
break;
}
- rejectMessage(tag, true);
+ rejectMessage(tag, normalRejectBehaviour);
}
}
public void rejectMessage(long deliveryTag, boolean requeue)
{
- if ((_acknowledgeMode == CLIENT_ACKNOWLEDGE) || (_acknowledgeMode == SESSION_TRANSACTED))
+ if ((_acknowledgeMode == CLIENT_ACKNOWLEDGE) || (_acknowledgeMode == SESSION_TRANSACTED)||
+ ((_acknowledgeMode == AUTO_ACKNOWLEDGE || _acknowledgeMode == DUPS_OK_ACKNOWLEDGE ) && hasMessageListeners()))
{
if (_logger.isDebugEnabled())
{
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
index 7bb400fada..c6e5fbb019 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
@@ -147,7 +147,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
private List<StackTraceElement> _closedStack = null;
-
protected BasicMessageConsumer(int channelId, AMQConnection connection, AMQDestination destination,
String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory,
AMQSession session, AMQProtocolHandler protocolHandler,
@@ -211,6 +210,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
ft.put(AMQPFilterTypes.JMS_SELECTOR.getValue(), messageSelector == null ? "" : messageSelector);
_arguments = ft;
+
}
public AMQDestination getDestination()
@@ -814,31 +814,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
}
}
-
- /**
- * Acknowledge up to last message delivered (if any). Used when commiting.
- *
- * @return the lastDeliveryTag to acknowledge
- */
- Long getLastDelivered()
- {
- if (!_receivedDeliveryTags.isEmpty())
- {
- Long lastDeliveryTag = _receivedDeliveryTags.poll();
-
- while (!_receivedDeliveryTags.isEmpty())
- {
- lastDeliveryTag = _receivedDeliveryTags.poll();
- }
-
- assert _receivedDeliveryTags.isEmpty();
-
- return lastDeliveryTag;
- }
-
- return null;
- }
-
void notifyError(Throwable cause)
{
// synchronized (_closed)
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
index 47c20b683c..bb277887aa 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
@@ -470,7 +470,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
}
}
- _0_10session.getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ _0_10session.flushProcessed(ranges, false);
+ _0_10session.getQpidSession().messageRelease(ranges);
clearReceiveQueue();
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
index cf1d7cedeb..efcbfd5532 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
@@ -28,7 +28,10 @@ import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.message.*;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.configuration.ClientProperties;
import org.apache.qpid.framing.*;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.BindingURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +39,8 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
{
protected final Logger _logger = LoggerFactory.getLogger(getClass());
+ private final RejectBehaviour _rejectBehaviour;
+
protected BasicMessageConsumer_0_8(int channelId, AMQConnection connection, AMQDestination destination,
String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
AMQProtocolHandler protocolHandler, FieldTable rawSelector, int prefetchHigh, int prefetchLow,
@@ -55,6 +60,25 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
consumerArguments.put(AMQPFilterTypes.NO_CONSUME.getValue(), Boolean.TRUE);
}
+ if (destination.getRejectBehaviour() != null)
+ {
+ _rejectBehaviour = destination.getRejectBehaviour();
+ }
+ else
+ {
+ ConnectionURL connectionURL = connection.getConnectionURL();
+ String rejectBehaviour = connectionURL.getOption(ConnectionURL.OPTIONS_REJECT_BEHAVIOUR);
+ if (rejectBehaviour != null)
+ {
+ _rejectBehaviour = RejectBehaviour.valueOf(rejectBehaviour.toUpperCase());
+ }
+ else
+ {
+ // use the default value for all connections, if not set
+ rejectBehaviour = System.getProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, RejectBehaviour.NORMAL.toString());
+ _rejectBehaviour = RejectBehaviour.valueOf( rejectBehaviour.toUpperCase());
+ }
+ }
}
void sendCancel() throws AMQException, FailoverException
@@ -89,4 +113,9 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
{
}
+
+ public RejectBehaviour getRejectBehaviour()
+ {
+ return _rejectBehaviour;
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/RejectBehaviour.java b/qpid/java/client/src/main/java/org/apache/qpid/client/RejectBehaviour.java
new file mode 100644
index 0000000000..e3c958044e
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/RejectBehaviour.java
@@ -0,0 +1,32 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+/**
+ * This enum can be used only with for 0-8/0-9/0-9-1 protocols connections to notify
+ * the client to delegate the requeue/DLQ decision to the server
+ * if <code>SERVER</server> value is specified. Otherwise the messages won't be moved to
+ * the DLQ (or dropped) when delivery count exceeds the maximum.
+ */
+public enum RejectBehaviour
+{
+ NORMAL, SERVER;
+}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java
index 81b9940ed5..0f3be4ba18 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java
@@ -123,7 +123,7 @@ public class TopicPublisherAdapter implements TopicPublisher
public void send(Destination dest, Message msg) throws JMSException
{
checkPreConditions();
- checkTopic(_topic);
+ checkTopic(dest);
_delegate.send(dest, msg);
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java b/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
index 97048f39f4..509aa25bd5 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
@@ -5,9 +5,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -75,4 +75,11 @@ public class XAConnectionImpl extends AMQConnection implements XAConnection, XAQ
{
return (XATopicSession) createXASession();
}
+
+ //Specialized call for JCA
+ public XASession createXASession(int ackMode) throws JMSException
+ {
+ checkNotClosed();
+ return _delegate.createXASession(ackMode);
+ }
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java b/qpid/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
index 6b9121811d..aaabf613fc 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
@@ -5,9 +5,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * http://www.apache.org/licenses/LICENSE 2.0
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -43,21 +43,36 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
private Session _jmsSession;
- //-- Constructors
+ // Constructors
/**
* Create a JMS XASession
*/
public XASessionImpl(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
int defaultPrefetchHigh, int defaultPrefetchLow)
{
- super(qpidConnection, con, channelId, false, // this is not a transacted session
- Session.AUTO_ACKNOWLEDGE, // the ack mode is transacted
- MessageFactoryRegistry.newDefaultRegistry(), defaultPrefetchHigh, defaultPrefetchLow,null);
+ this(qpidConnection, con, channelId, false, Session.AUTO_ACKNOWLEDGE,
+ MessageFactoryRegistry.newDefaultRegistry(), defaultPrefetchHigh, defaultPrefetchLow, null);
+ }
+
+ public XASessionImpl(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
+ int ackMode, int defaultPrefetchHigh, int defaultPrefetchLow)
+ {
+ this(qpidConnection, con, channelId, false, ackMode, MessageFactoryRegistry.newDefaultRegistry(),
+ defaultPrefetchHigh, defaultPrefetchLow, null);
+
+ }
+
+ public XASessionImpl(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
+ boolean transacted, int ackMode, MessageFactoryRegistry registry, int defaultPrefetchHigh, int defaultPrefetchLow,
+ String name)
+ {
+ super(qpidConnection, con, channelId, transacted, ackMode, registry, defaultPrefetchHigh, defaultPrefetchLow, name);
createSession();
_xaResource = new XAResourceImpl(this);
- }
+ }
+
- //-- public methods
+ // public methods
/**
* Create a qpid session.
@@ -70,7 +85,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
}
- //--- javax.njms.XASEssion API
+ // javax.njms.XASEssion API
/**
* Gets the session associated with this XASession.
@@ -97,7 +112,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
return _xaResource;
}
- //-- overwritten mehtods
+ // overwritten mehtods
/**
* Throws a {@link TransactionInProgressException}, since it should
* not be called for an XASession object.
@@ -132,7 +147,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
return _qpidDtxSession;
}
- //--- interface XAQueueSession
+ // interface XAQueueSession
/**
* Gets the topic session associated with this <CODE>XATopicSession</CODE>.
*
@@ -144,7 +159,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
return (QueueSession) getSession();
}
- //--- interface XATopicSession
+ // interface XATopicSession
/**
* Gets the topic session associated with this <CODE>XATopicSession</CODE>.
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
index b04a756e80..8855a040ea 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
@@ -6,9 +6,9 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,3 +30,4 @@ CRAM-MD5-HASHED.3=org.apache.qpid.client.security.UsernameHashedPasswordCallback
CRAM-MD5.4=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
AMQPLAIN.5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
PLAIN.6=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
+ANONYMOUS.7=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
index 26641982d7..24d9360cfa 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
@@ -41,7 +41,16 @@ public interface ConnectionURL
public static final String OPTIONS_USE_LEGACY_MAP_MESSAGE_FORMAT = "use_legacy_map_msg_format";
public static final String OPTIONS_BROKERLIST = "brokerlist";
public static final String OPTIONS_FAILOVER = "failover";
- public static final String OPTIONS_FAILOVER_CYCLE = "cyclecount";
+ public static final String OPTIONS_FAILOVER_CYCLE = "cyclecount";
+
+ /**
+ * This option is only applicable for 0-8/0-9/0-9-1 protocols connection
+ * <p>
+ * It tells the client to delegate the requeue/DLQ decision to the
+ * server .If this option is not specified, the messages won't be moved to
+ * the DLQ (or dropped) when delivery count exceeds the maximum.
+ */
+ public static final String OPTIONS_REJECT_BEHAVIOUR = "rejectbehaviour";
public static final String OPTIONS_DEFAULT_TOPIC_EXCHANGE = "defaultTopicExchange";
public static final String OPTIONS_DEFAULT_QUEUE_EXCHANGE = "defaultQueueExchange";
public static final String OPTIONS_TEMPORARY_TOPIC_EXCHANGE = "temporaryTopicExchange";
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQConnectionUnitTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQConnectionUnitTest.java
new file mode 100644
index 0000000000..3a565f0f0d
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQConnectionUnitTest.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.AMQInvalidArgumentException;
+
+public class AMQConnectionUnitTest extends TestCase
+{
+
+ public void testExceptionReceived()
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'";
+ AMQInvalidArgumentException expectedException = new AMQInvalidArgumentException("Test", null);
+ final AtomicReference<JMSException> receivedException = new AtomicReference<JMSException>();
+ try
+ {
+ MockAMQConnection connection = new MockAMQConnection(url);
+ connection.setExceptionListener(new ExceptionListener()
+ {
+
+ @Override
+ public void onException(JMSException jmsException)
+ {
+ receivedException.set(jmsException);
+ }
+ });
+ connection.exceptionReceived(expectedException);
+ }
+ catch (Exception e)
+ {
+ fail("Failure to test exceptionRecived:" + e.getMessage());
+ }
+ JMSException exception = receivedException.get();
+ assertNotNull("Expected JMSException but got null", exception);
+ assertEquals("JMSException error code is incorrect", Integer.toString(expectedException.getErrorCode().getCode()), exception.getErrorCode());
+ assertNotNull("Expected not null message for JMSException", exception.getMessage());
+ assertTrue("JMSException error message is incorrect", exception.getMessage().contains(expectedException.getMessage()));
+ assertEquals("JMSException linked exception is incorrect", expectedException, exception.getLinkedException());
+ }
+
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
index 68531eee84..f53fa8d83c 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
@@ -287,29 +287,6 @@ public class AMQSession_0_10Test extends TestCase
assertNotNull("ExecutionSync was not sent", event);
}
- public void testRejectMessage()
- {
- AMQSession_0_10 session = createAMQSession_0_10();
- session.rejectMessage(1l, true);
- ProtocolEvent event = findSentProtocolEventOfClass(session, MessageRelease.class, false);
- assertNotNull("MessageRelease event was not sent", event);
- }
-
- public void testReleaseForRollback()
- {
- AMQSession_0_10 session = createAMQSession_0_10();
- try
- {
- session.releaseForRollback();
- }
- catch (Exception e)
- {
- fail("Unexpected exception is cought:" + e.getMessage());
- }
- ProtocolEvent event = findSentProtocolEventOfClass(session, MessageRelease.class, false);
- assertNotNull("MessageRelease event was not sent", event);
- }
-
public void testSendQueueDelete()
{
AMQSession_0_10 session = createAMQSession_0_10();
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java
new file mode 100644
index 0000000000..d8d94ba40e
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import javax.jms.Session;
+
+import org.apache.qpid.test.unit.message.TestAMQSession;
+import org.apache.qpid.url.AMQBindingURL;
+
+import junit.framework.TestCase;
+
+public class BasicMessageConsumer_0_8_Test extends TestCase
+{
+ /**
+ * Test that if there is a value for Reject Behaviour specified for the Destination
+ * used to create the Consumer, it overrides the value for the Connection.
+ */
+ public void testDestinationRejectBehaviourOverridesDefaultConnection() throws Exception
+ {
+ /*
+ * Check that when the connection does not have a value applied that this
+ * is successfully overridden with a specific value by the consumer.
+ */
+ String connUrlString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'";
+ AMQConnection conn = new MockAMQConnection(connUrlString);
+
+ String url = "exchangeClass://exchangeName/Destination/Queue?rejectbehaviour='server'";
+ AMQBindingURL burl = new AMQBindingURL(url);
+ AMQDestination queue = new AMQQueue(burl);
+
+ AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
+ BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+
+ assertEquals("Reject behaviour was was not as expected", RejectBehaviour.SERVER, consumer.getRejectBehaviour());
+ }
+
+ /**
+ * Check that when the connection does have a specific value applied that this
+ * is successfully overridden with another specific value by the consumer.
+ */
+ public void testDestinationRejectBehaviourSpecified() throws Exception
+ {
+ final String connUrlString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'&rejectbehaviour='server'";
+ final AMQConnection conn = new MockAMQConnection(connUrlString);
+
+ final String url = "exchangeClass://exchangeName/Destination/Queue?rejectbehaviour='normal'";
+ final AMQBindingURL burl = new AMQBindingURL(url);
+ final AMQDestination queue = new AMQQueue(burl);
+
+ final AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
+ final BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+
+ assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour());
+ }
+
+ /**
+ * Test that if no value for Reject Behaviour is applied to the Destination, then the value
+ * from the connection is used and acts as expected.
+ */
+ public void testRejectBehaviourDetectedFromConnection() throws Exception
+ {
+ /*
+ * Check that when the connection does have a specific value applied that this
+ * is successfully detected by the consumer.
+ */
+ String connUrlString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'&rejectbehaviour='normal'";
+ AMQConnection conn = new MockAMQConnection(connUrlString);
+
+ String url = "exchangeClass://exchangeName/Destination/Queue";
+ AMQBindingURL burl = new AMQBindingURL(url);
+ AMQDestination queue = new AMQQueue(burl);
+
+ assertNull("Reject behaviour should have been null", queue.getRejectBehaviour());
+
+ AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
+ BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+
+ assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour());
+ }
+
+
+ protected RejectBehaviour getRejectBehaviour(AMQDestination destination)
+ {
+ return destination.getRejectBehaviour();
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java b/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
index 73e67469ae..919809edc3 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
@@ -55,4 +55,9 @@ public class MockAMQConnection extends AMQConnection
_protocolHandler.getStateManager().changeState(AMQState.CONNECTION_OPEN);
return null;
}
+
+ public AMQConnectionDelegate getDelegate()
+ {
+ return _delegate;
+ }
}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
index 9095f94960..506185cbaf 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
@@ -20,19 +20,35 @@
*/
package org.apache.qpid.test.unit.client.BrokerDetails;
-import java.util.HashMap;
-import java.util.Map;
-
import junit.framework.TestCase;
import org.apache.qpid.client.AMQBrokerDetails;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.jms.ConnectionURL;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.url.URLSyntaxException;
public class BrokerDetailsTest extends TestCase
{
+ public void testDefaultTCP_NODELAY() throws URLSyntaxException
+ {
+ String brokerURL = "tcp://localhost:5672";
+ AMQBrokerDetails broker = new AMQBrokerDetails(brokerURL);
+
+ assertNull("default value should be null", broker.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY));
+ }
+
+ public void testOverridingTCP_NODELAY() throws URLSyntaxException
+ {
+ String brokerURL = "tcp://localhost:5672?tcp_nodelay='true'";
+ AMQBrokerDetails broker = new AMQBrokerDetails(brokerURL);
+
+ assertTrue("value should be true", Boolean.valueOf(broker.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)));
+
+ brokerURL = "tcp://localhost:5672?tcp_nodelay='false''&maxprefetch='1'";
+ broker = new AMQBrokerDetails(brokerURL);
+
+ assertFalse("value should be false", Boolean.valueOf(broker.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)));
+ }
+
public void testMultiParameters() throws URLSyntaxException
{
String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
@@ -82,9 +98,4 @@ public class BrokerDetailsTest extends TestCase
}
}
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(BrokerDetailsTest.class);
- }
}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index 4624b36fea..392ef1f29b 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -38,7 +38,7 @@ public class ConnectionURLTest extends TestCase
ConnectionURL connectionurl = new AMQConnectionURL(url);
assertTrue(connectionurl.getFailoverMethod().equals("roundrobin"));
- assertEquals("100", connectionurl.getFailoverOption(ConnectionURL.OPTIONS_FAILOVER_CYCLE));
+ assertEquals("100", connectionurl.getFailoverOption(ConnectionURL.OPTIONS_FAILOVER_CYCLE));
assertTrue(connectionurl.getUsername().equals("ritchiem"));
assertTrue(connectionurl.getPassword().equals("bob"));
assertTrue(connectionurl.getVirtualHost().equals("/test"));
@@ -274,6 +274,34 @@ public class ConnectionURLTest extends TestCase
// assertTrue(service.getPort() == 1234);
}
+ /**
+ * Test for QPID-3662 to ensure the {@code toString()} representation is correct.
+ */
+ public void testConnectionURLOptionToString() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@client/localhost?maxprefetch='1'&brokerlist='tcp://localhost:1234?tcp_nodelay='true''";
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertNull(connectionurl.getFailoverMethod());
+ assertEquals("guest", connectionurl.getUsername());
+ assertEquals("guest", connectionurl.getPassword());
+ assertEquals("client", connectionurl.getClientName());
+ assertEquals("/localhost", connectionurl.getVirtualHost());
+ assertEquals("1", connectionurl.getOption("maxprefetch"));
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 1234);
+ assertTrue(service.getProperties().containsKey("tcp_nodelay"));
+ assertEquals("true", service.getProperties().get("tcp_nodelay"));
+
+ String nopasswd = "amqp://guest:********@client/localhost?maxprefetch='1'&brokerlist='tcp://localhost:1234?tcp_nodelay='true''";
+ String tostring = connectionurl.toString();
+ assertEquals(tostring.indexOf("maxprefetch"), tostring.lastIndexOf("maxprefetch"));
+ assertEquals(nopasswd, tostring);
+ }
public void testSingleTransportMultiOptionURL() throws URLSyntaxException
{
@@ -338,7 +366,7 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getPassword().equals("pass"));
assertTrue(connectionurl.getVirtualHost().equals("/test"));
assertTrue(connectionurl.getClientName().equals("client_id"));
-
+
assertTrue(connectionurl.getBrokerCount() == 1);
}
@@ -457,7 +485,6 @@ public class ConnectionURLTest extends TestCase
assertTrue(service.getTransport().equals("tcp"));
-
assertTrue(service.getHost().equals("localhost"));
assertTrue(service.getPort() == 5672);
assertEquals("jim",service.getProperty("foo"));
@@ -468,7 +495,7 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getOption("timeout").equals("200"));
assertTrue(connectionurl.getOption("immediatedelivery").equals("true"));
}
-
+
/**
* Test that options other than failover and brokerlist are returned in the string representation.
* <p>
@@ -477,7 +504,7 @@ public class ConnectionURLTest extends TestCase
public void testOptionToString() throws Exception
{
ConnectionURL url = new AMQConnectionURL("amqp://user:pass@temp/test?maxprefetch='12345'&brokerlist='tcp://localhost:5672'");
-
+
assertTrue("String representation should contain options and values", url.toString().contains("maxprefetch='12345'"));
}
@@ -493,10 +520,10 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getBrokerCount() == 1);
BrokerDetails service = connectionurl.getBrokerDetails(0);
- assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getTransport().equals("tcp"));
assertTrue(service.getHost().equals("under_score"));
assertTrue(service.getPort() == 6672);
-
+
url = "amqp://guest:guest@clientid/test?brokerlist='tcp://under_score'";
connectionurl = new AMQConnectionURL(url);
@@ -507,11 +534,44 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getBrokerCount() == 1);
service = connectionurl.getBrokerDetails(0);
- assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getTransport().equals("tcp"));
assertTrue(service.getHost().equals("under_score"));
assertTrue(service.getPort() == 5672);
}
-
+
+
+ public void testRejectBehaviourPresent() throws Exception
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'&rejectbehaviour='server'";
+
+ ConnectionURL connectionURL = new AMQConnectionURL(url);
+
+ assertTrue(connectionURL.getFailoverMethod() == null);
+ assertTrue(connectionURL.getUsername().equals("guest"));
+ assertTrue(connectionURL.getPassword().equals("guest"));
+ assertTrue(connectionURL.getVirtualHost().equals("/test"));
+
+ //check that the reject behaviour option is returned as expected
+ assertEquals("Reject behaviour option was not as expected", "server",
+ connectionURL.getOption(ConnectionURL.OPTIONS_REJECT_BEHAVIOUR));
+ }
+
+ public void testRejectBehaviourNotPresent() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'&foo='bar'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ //check that the reject behaviour option is null as expected
+ assertNull("Reject behaviour option was not as expected",
+ connectionurl.getOption(ConnectionURL.OPTIONS_REJECT_BEHAVIOUR));
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(ConnectionURLTest.class);
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
index 7de09cff45..2c32e4c559 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
@@ -22,8 +22,11 @@ package org.apache.qpid.test.unit.client.destinationurl;
import junit.framework.TestCase;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.RejectBehaviour;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -190,6 +193,67 @@ public class DestinationURLTest extends TestCase
assertTrue(dest.getQueueName().equals("test:testQueueD"));
}
+ public void testRejectBehaviourPresent() throws URISyntaxException
+ {
+ String url = "exchangeClass://exchangeName/Destination/Queue?rejectbehaviour='server'";
+
+ AMQBindingURL burl = new AMQBindingURL(url);
+
+ assertTrue(url.equals(burl.toString()));
+ assertTrue(burl.getExchangeClass().equals("exchangeClass"));
+ assertTrue(burl.getExchangeName().equals("exchangeName"));
+ assertTrue(burl.getDestinationName().equals("Destination"));
+ assertTrue(burl.getQueueName().equals("Queue"));
+
+ //check that the MaxDeliveryCount property has the right value
+ assertEquals("server",burl.getOption(BindingURL.OPTION_REJECT_BEHAVIOUR));
+
+ //check that the MaxDeliveryCount value is correctly returned from an AMQDestination
+ class MyTestAMQDestination extends AMQDestination
+ {
+ public MyTestAMQDestination(BindingURL url)
+ {
+ super(url);
+ }
+ public boolean isNameRequired()
+ {
+ return false;
+ }
+ };
+
+ AMQDestination dest = new MyTestAMQDestination(burl);
+ assertEquals("Reject behaviour is unexpected", RejectBehaviour.SERVER, dest.getRejectBehaviour());
+ }
+
+ public void testRejectBehaviourNotPresent() throws URISyntaxException
+ {
+ String url = "exchangeClass://exchangeName/Destination/Queue";
+
+ AMQBindingURL burl = new AMQBindingURL(url);
+
+ assertTrue(url.equals(burl.toString()));
+
+ assertTrue(burl.getExchangeClass().equals("exchangeClass"));
+ assertTrue(burl.getExchangeName().equals("exchangeName"));
+ assertTrue(burl.getDestinationName().equals("Destination"));
+ assertTrue(burl.getQueueName().equals("Queue"));
+
+ class MyTestAMQDestination extends AMQDestination
+ {
+ public MyTestAMQDestination(BindingURL url)
+ {
+ super(url);
+ }
+ public boolean isNameRequired()
+ {
+ return false;
+ }
+ };
+
+ AMQDestination dest = new MyTestAMQDestination(burl);
+ assertNull("Reject behaviour is unexpected", dest.getRejectBehaviour());
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(DestinationURLTest.class);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
index 62ded5b2d8..a36e7c214e 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
@@ -102,6 +102,20 @@ public class ClientProperties
*/
public static final int DEFAULT_SYNC_OPERATION_TIMEOUT = 60000;
+ /**
+ * System properties to change the default value used for TCP_NODELAY
+ */
+ public static final String QPID_TCP_NODELAY_PROP_NAME = "qpid.tcp_nodelay";
+ public static final String AMQJ_TCP_NODELAY_PROP_NAME = "amqj.tcp_nodelay";
+
+ /**
+ * System property to set the reject behaviour. default value will be 'normal' but can be
+ * changed to 'server' in which case the server decides whether a message should be requeued
+ * or dead lettered.
+ * This can be overridden by the more specific settings at connection or binding URL level.
+ */
+ public static final String REJECT_BEHAVIOUR_PROP_NAME = "qpid.reject.behaviour";
+
/*
public static final QpidProperty<Boolean> IGNORE_SET_CLIENTID_PROP_NAME =
QpidProperty.booleanProperty(false,"qpid.ignore_set_client_id","ignore_setclientID");
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
index 37a8e594c0..2ee507e2ec 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
@@ -22,6 +22,8 @@ package org.apache.qpid.transport;
import java.util.Map;
+import org.apache.qpid.configuration.ClientProperties;
+
/**
* A ConnectionSettings object can only be associated with
* one Connection object. I have added an assertion that will
@@ -38,7 +40,8 @@ public class ConnectionSettings
String username = "guest";
String password = "guest";
int port = 5672;
- boolean tcpNodelay = Boolean.getBoolean("amqj.tcp_nodelay");
+ boolean tcpNodelay = Boolean.valueOf(System.getProperty(ClientProperties.QPID_TCP_NODELAY_PROP_NAME,
+ System.getProperty(ClientProperties.AMQJ_TCP_NODELAY_PROP_NAME, "true")));
int maxChannelCount = 32767;
int maxFrameSize = 65535;
int heartbeatInterval;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
index e1d1596ec5..838a662402 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -60,7 +60,8 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
LOGGER.debug("SO_RCVBUF : %s", _socket.getReceiveBufferSize());
LOGGER.debug("SO_SNDBUF : %s", _socket.getSendBufferSize());
-
+ LOGGER.debug("TCP_NODELAY : %s", _socket.getTcpNoDelay());
+
InetAddress address = InetAddress.getByName(settings.getHost());
_socket.connect(new InetSocketAddress(address, settings.getPort()));
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
index d4b5975e54..5b714434d9 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
@@ -33,6 +33,8 @@ import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.net.ssl.SSLSocket;
+
/**
* IoReceiver
*
@@ -94,7 +96,7 @@ final class IoReceiver implements Runnable, Closeable
{
try
{
- if (shutdownBroken)
+ if (shutdownBroken || socket instanceof SSLSocket)
{
socket.close();
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
index 17f89c34ef..08934004a8 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.transport.network.security;
import org.apache.qpid.ssl.SSLContextFactory;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
index 9996fff311..0e6c865a16 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
@@ -37,6 +37,15 @@ public interface BindingURL
public static final String OPTION_ROUTING_KEY = "routingkey";
public static final String OPTION_BINDING_KEY = "bindingkey";
+ /**
+ * This option is only applicable for 0-8/0-9/0-9-1 protocols connection
+ * <p>
+ * It tells the client to delegate the requeue/DLQ decision to the
+ * server .If this option is not specified, the messages won't be moved to
+ * the DLQ (or dropped) when delivery count exceeds the maximum.
+ */
+ public static final String OPTION_REJECT_BEHAVIOUR = "rejectbehaviour";
+
String getURL();
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionSettingsTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionSettingsTest.java
new file mode 100644
index 0000000000..57c0549193
--- /dev/null
+++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionSettingsTest.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class ConnectionSettingsTest extends QpidTestCase
+{
+ ConnectionSettings _conConnectionSettings;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _conConnectionSettings = new ConnectionSettings();
+ }
+
+ public void testDefaultTCP_NODELAY()
+ {
+ assertTrue("Default for isTcpNodelay() should be true", _conConnectionSettings.isTcpNodelay());
+ }
+
+ public void testSystemPropertyOverrideTrueForTCP_NODELAY()
+ {
+ systemPropertyOverrideForTCP_NODELAYImpl(ClientProperties.QPID_TCP_NODELAY_PROP_NAME, true);
+ }
+
+ public void testSystemPropertyOverrideFalseForTCP_NODELAY()
+ {
+ systemPropertyOverrideForTCP_NODELAYImpl(ClientProperties.QPID_TCP_NODELAY_PROP_NAME, false);
+ }
+
+ public void testLegacySystemPropertyOverrideTrueForTCP_NODELAY()
+ {
+ systemPropertyOverrideForTCP_NODELAYImpl(ClientProperties.AMQJ_TCP_NODELAY_PROP_NAME, true);
+ }
+
+ public void testLegacySystemPropertyOverrideFalseForTCP_NODELAY()
+ {
+ systemPropertyOverrideForTCP_NODELAYImpl(ClientProperties.AMQJ_TCP_NODELAY_PROP_NAME, false);
+ }
+
+ private void systemPropertyOverrideForTCP_NODELAYImpl(String propertyName, boolean value)
+ {
+ //set the default via system property
+ setTestSystemProperty(propertyName, String.valueOf(value));
+
+ _conConnectionSettings = new ConnectionSettings();
+ assertEquals("Value for isTcpNodelay() is incorrect", value, _conConnectionSettings.isTcpNodelay());
+ }
+}
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/default.properties b/qpid/java/common/src/test/java/org/apache/qpid/util/default.properties
index cb522ea9a7..8214cc1fee 100644
--- a/qpid/java/common/src/test/java/org/apache/qpid/util/default.properties
+++ b/qpid/java/common/src/test/java/org/apache/qpid/util/default.properties
@@ -1,2 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Used by FileUtilsTests
src=default.properties \ No newline at end of file
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties b/qpid/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties
index 6a49d927d0..c0a21d08d1 100644
--- a/qpid/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties
+++ b/qpid/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties
@@ -1,2 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Used by FileUtilsTests
src=mydefaults \ No newline at end of file
diff --git a/qpid/java/jca/README-GERONIMO.txt b/qpid/java/jca/README-GERONIMO.txt
new file mode 100644
index 0000000000..3b72a7e094
--- /dev/null
+++ b/qpid/java/jca/README-GERONIMO.txt
@@ -0,0 +1,29 @@
+Qpid JCA Resource Adapter
+
+Apache Geronimo 2.x Installation and Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications.
+Currently the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+
+The following document explains how to configure the resource adapter for deployment in Geronimo 2.x
+
+Configuration and Deployment
+============================
+
+The Apache Geronimo 2.x application server requires the use of an RA deployment plan to deploy and configure
+a resource adapter. A sample deployment plan has been provided as geronimo-ra.xml which is included in the
+META-INF directory of the qpid-ra-<version>.rar file. If you need to modify this file, simply extract
+the RAR file, edit the geronimo-ra.xml file and recompress the file.
+
+Please refer to the general README.txt file for a description of each configuration property
+the adapter supports for resource adapter, managedconnectionfatory and activationspec level configuration.
+
+
+
diff --git a/qpid/java/jca/README-JBOSS.txt b/qpid/java/jca/README-JBOSS.txt
new file mode 100644
index 0000000000..77bf91e6dd
--- /dev/null
+++ b/qpid/java/jca/README-JBOSS.txt
@@ -0,0 +1,168 @@
+Qpid JCA Resource Adapter
+
+JBoss EAP 5.x Installation and Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications.
+Currently the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+The following document explains how to configure the resource adapter for deployment in JBoss EAP 5.x.
+
+
+Deployment
+==========
+To deploy the Qpid JCA adapter for either JBoss EAP, simply copy the qpid-ra-<version>.rar file
+to your JBoss deploy directory. By default this can be found at JBOSS_ROOT/server/<server-name>/deploy,
+where JBOSS_ROOT denotes the root directory of your JBoss installation and <server-name> denotes the
+name of your deployment server. A successful adapter installation will be accompanied by the
+following INFO message:
+
+ INFO [QpidResourceAdapter] Qpid resource adaptor started
+
+At this point the adapter is deployed and ready for configuration.
+
+Configuration Overview
+======================
+The standard configuration mechanism for 1.5 JCA adapters is the ra.xml
+deployment descriptor. Like other EE based descriptors this file can be found
+in the META-INF directory of the provided EE artifact (ie .rar file). A majority
+of the properties in the ra.xml will seem familiar to anyone who has worked with
+Apache Qpid in a standalone environment. A reasonable set of configuration defaults
+have been provided.
+
+The resource adapter configuration properties provide generic properties for both
+inbound and outbound connectivity. These properties can be overridden when deploying
+managed connection factories as well as inbound activations using the standard JBoss
+configuration artifacts, the *-ds.xml file and MDB activation spec . A sample *-ds.xml file,
+qpid-jca-ds.xml, can be found in your Qpid JCA resource adapter directory.
+
+The general README.txt file provides a detailed description of all the properties associated
+with the Qpid JCA Resource adapter. Please consult this file for further explanation of
+how configuration properties are treated within the Qpid JCA adapter.
+
+ConnectionFactory Configuration
+======================================
+As per the JCA specification, the standard outbound-connectivity component is the
+ConnectionFactory. In EAP 5.x ConnectionFactories are configured
+via the *-ds.xml file. As previously mentioned, a sample *-ds.xml file, qpid-jca-ds.xml
+hasbeen provided with your distribution. This file can be easily modified to suit
+your development/deployment needs. The following describes the ConnectionFactory
+portion of the sample file.
+
+XA ConnectionFactory
+====================
+ <tx-connection-factory>
+ <jndi-name>QpidJMSXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>qpid-ra-<ra-version>.rar</rar-name>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <config-property name="connectionURL">amqp://guest:guest@/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''</config-property>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+The QpidJMSXA connection factory defines an XA capable ManagedConnectionFactory. You will need to insert your particular rar version for
+the rar-name property. The jndi-name and connectionURL property are both configurable and can be modified for your environment. After deployment
+the ConnectionFactory will be bound into JNDI under the name
+
+java:<jndi-name>
+
+For the previous example, this would resolve to
+
+java:QpidJMSXA
+
+Local ConnectionFactory
+=======================
+ <tx-connection-factory>
+ <jndi-name>QpidJMS</jndi-name>
+ <rar-name>qpid-ra-0.10.rar</rar-name>
+ <local-transaction/>
+ <config-property name="useLocalTx" type="java.lang.Boolean">true</config-property>
+ <config-property name="connectionURL">amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+The QpidJMS connection factory defines a non XA connection factory. Typically this is used as a specialized ConnectionFactory where either XA
+is not desired, or you are running with a clustered Qpid Broker configuration which at this time, does not support XA. The configuration
+properties mirror those of the XA ConnectionFactory.
+
+Admininstered Object Configuration
+==================================
+Destinations (queues, topics) are configured in EAP via JCA standard Administered Objects (AdminObjects). These objects
+are placed within the *-ds.xml file alongside your ConnectionFactory configurations. The sample file qpid-jca-ds.xml
+provides two such objects
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloQueue">
+ <attribute name="JNDIName">Hello</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=amq.direct
+ </attribute>
+ </mbean>
+
+The above XML defines a JMS Queue which is bound into JNDI as
+
+queue/HelloQueue
+
+This destination can be retrieved from JNDI and be used for the consumption or production of messages. The desinationAddress property
+can be customized for your environment. Please see the Qpid Java Client documentation for specific configuration options.
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloTopic">
+ <attribute name="JNDIName">HelloTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=amq.topic
+ </attribute>
+ </mbean>
+
+
+The above XML defines a JMS Topic which is bound into JNDI as
+
+HelloTopic
+
+This destination can be retrieved from JNDI and be used for the consumption or production of messages. The desinationAddress property
+can be customized for your environment. Please see the Qpid Java Client documentation for specific configuration options.
+
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidConnectionFactory">
+ <attribute name="JNDIName">QpidConnectionFactory</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.ConnectionFactory</attribute>
+ <attribute name="Properties">
+ connectionURL=amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''
+ </attribute>
+ </mbean>
+
+The above XML defines a ConnectionFactory that can be used external to EAP 5.x. Typically this connection factory
+is used by standalone or 'thin' clients that do not require an application server. This object is bound into
+the EAP 5.x JNDI tree as
+
+QpidConnectionFactory
+
+ActivationSpec Configuration
+============================
+The standard method for inbound communication is the MessageDrivenBean architecture with is configured
+via the ActivationSpec mechanism. Please see the general README.tx file for an explanation of the
+QpidActivationSpec, as well as general inbound connectivity options.
+
+An ActivationSpec can either be configured via the Java Annotation mechanism, or in the ejb-jar.xml deployment
+descriptor.
+
+Summary
+=======
+The above description for the Qpid JCA adapter for EAP 5.x is just a general guide for deploying and configuring
+the Qpid JCA adapter. The sample file provided can be easily modified and it is expected you will do so to
+conform to your own environment.
+
diff --git a/qpid/java/jca/README.txt b/qpid/java/jca/README.txt
new file mode 100644
index 0000000000..29e6825c4c
--- /dev/null
+++ b/qpid/java/jca/README.txt
@@ -0,0 +1,241 @@
+Qpid JCA Resource Adapter Installation/Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications. Currently
+the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+The following document explains general configuration information for the Qpid JCA RA. Details for
+specific application server platforms are provided in separate README files typically designated as
+README-<server-platform>.txt.
+
+Configuration
+=============
+As per the JCA specification, there are four main components of a JCA resource adapter:
+
+ The ResourceAdapter JavaBean
+ The ManagedConnectionFactory JavaBean
+ The ActivationSpec JavaBean
+ Administered Objects
+
+Each of these components provide configuration options in the form of properties. The Resource Adapter
+JavaBean provides a set of global configuration options while the ManagedConnectionFactory JavaBean allows
+for the configuration of outbound connectivity options. The ActivationSpec JavaBean provides configuration
+options for inbound connectivity.
+
+When a ManagedConnectionFactory JavaBean or ActivationSpec JavaBean are deployed they can choose to inherit
+the configuration properties from the ResourceAdapter or provide specific properties which in turn will override
+the defaults.
+
+While some of the properties from the three componets are specific to the JCA adapter, a majority of the
+properties directly correspond the the Qpid JMS client. As such, it is strongly encouraged your familiarize
+yourself with the correct syntax, configuration options for the JMS client as well as the JCA adapter. Similarly,
+familiarity with the 1.5 JCA specification is encouraged though not strictly required.
+
+The ResourceAdapter JavaBean
+============================
+
+The ResourceAdapter JavaBean provides global configuration options for both inbound and outbound connectivity.
+The set of ResourceAdapter properties are described below. The ResourceAdapter properties can be found in the META-INF/ra.xml
+deployment descriptor which is provided with the adapter. Note, deploying a ResourceAdapter, ManagedConnectionFactory
+or ActivationSpec is application server specific. As such, this document provides an explanation of these properties
+but not how they are configured as this is environment specific.
+
+ResourceAdapter JavaBean Properties
+===================================
+
+ClientID
+ The unique client identifier. From the JMS API this is used only in the context of durable subscriptions.
+Default: client_id
+
+SetupAttempts
+ The number of attempts the ResourceAdapter will make to successfully setup an inbound activation on deployment, or when an exception
+ occurs at runtime.
+Default: 5
+
+SetupInterval
+ The interval in milliseconds the adapter will wait between setup attempts.
+Default: 5000
+
+UseLocalTx
+ Whether or not to use local transactions instead of XA.
+Default: false
+
+DefaultUserName
+ The default user name to use.
+Default: guest
+
+DefaultPassword
+ The default password to use.
+Default: guest
+
+Host
+ The hostname/ip address of the broker.
+Default: localhost
+
+Port
+ The port of the broker.
+Default: 5672
+
+Path
+ The virtual path for the connection factory.
+Default: test
+
+ConnectionURL
+ The full connection URL to the broker.
+Default:amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'
+
+TransactionManagerLocatorClass
+ The class responsible for locating the transaction manager within a specific application server. This is a ResourceAdapter
+ Java Bean specific property and is application server specific. As such, it is currently commented out. Two examples have
+ been provided.
+Default: none
+
+TransactionManagerLocatorMethod
+ The specific method on the class above used to acquire a reference to the platform specific transaction manager.
+ This is a ResourceAdapter Java Bean specific property and is application server specific.
+ As such, it is currently commented out. Two examples have been provided.
+Default:none
+
+Note, if you require XA support, both the TransactionManagerLocatorClass and the TransactionManagerLocatorMethod
+properties MUST be set. While application servers typically provide a mechanism to do this in the form of a specific
+deployment descriptor, or GUI console, the ra.xml file can also be modified directly.
+
+The ManagedConnectionFactory JavaBean
+=====================================
+
+The ManagedConnectionFactory JavaBean provides outbound connectivity for the Qpid JCA adapter. In addition to most of the properties
+inherited from the ResourceAdapter JavaBean, the ManagedConnectionFactory JavaBean provides specific properties only applicable
+to outbound connectivity.
+
+sessionDefaulType
+ The default type of Session. Currently unused.
+Default: java.jms.Queue
+
+useTryLock
+ Multi-purpose property used to specify both that a lock on the underlying managed connection should be used, as well as the
+ wait duration to aquire the lock. Primarily used for transaction management. A null or zero value will atttempt to acquire
+ the lock without a duration. Anything greater than zero will wait n number of seconds before failing to acquire the lock.
+Default:0
+
+KeyStorePassword
+ The KeyStore password for SSL
+Default:none
+
+KeyStorePath
+ The path to the KeyStore.
+Default:none
+
+CertType
+ The type of certificate.
+Default:SunX509
+
+The ActivationSpec JavaBean
+===========================
+The ActivationSpec JavaBean provides inbound connectivity for the Qpid JCA adapter. In addition to most of the properties
+inherited from the ResourceAdapter JavaBean, the ActivationSpec JavaBean provides specific properties only applicable
+to inbound connectivity. As opposed to the ResourceAdapter and ManagedConnectionFactory JavaBean a majority of the
+ActivationSpec JavaBean properties have no default value. It is expected that these will be provided via Java annotations
+or deployment descriptor configuration properties. The Qpid JCA adapter provides inbound connectivity in conjunction
+with the Message Driven Bean architecture from the EJB 3.x specification.
+
+UseJNDI
+ Whether or not to attempt looking up an inbound destination from JNDI. If false, an attempt will be made to construct
+ the destination from the other ActivationSpec properties.
+Default: true
+
+Destination
+ The name of the destination on which to listen for messages.
+Default:none
+
+DestinationType
+ The type of destination on which to listen. Valid values are javax.jms.Queue or java.jms.Topic.
+Default:none
+
+MessageSelector
+ The JMS properties that will be used in selecting specific message. Please see the JMS specification for further details.
+Default:none
+
+AcknowlegeMode
+ Whether or not the client or consumer will acknowledge any messages it receives. Ignored in a transacted scenario.
+ Please see the JMS specification for more details.
+Default:AUTO_ACKNOWLEDGE
+
+SubscriptionDurablity
+ Whether or not the subscription is durable.
+Default:none
+
+SubscriptionName
+ The name of the subscription.
+Default:none
+
+MaxSession
+ The maximum number of sessions that this activation supports.
+Default:15
+
+TransactionTimeout
+ The timeout for the XA transaction for inbound messages.
+Default:0
+
+PrefetchLow
+ Qpid specific -- TODO more explanation
+
+PrefetchHigh
+ Qpid specific -- TODO more explanation
+
+
+Administered Objects
+======================
+The JCA specification provides for administered objects. Ass per the specification, administered objects are
+JavaBeans that specific to the messaging provider. The Qpid JCA Resource Adapter provides two administered
+objects that can be used to configure JMS destinations and a specialized JMS Connection Factory respectively.
+Both these administered objects have properities to support configuration and deployment.
+
+QpidDestinationProxy
+====================
+ The QpidDestinationProxy allows a developer, deployer or adminstrator to create destinations (queues or topic) and
+ bind these destinations into JNDI. The following lists the properties applicable to the QpidDestinationProxy
+
+destinationType
+ The type of destination to create. Valid values are QUEUE or TOPIC.
+
+destinationAddress
+ The address string of the destination. Please see the Qpid Java JMS client documentation for valid values.
+
+QpidConnectionFactoryProxy
+ The QpidConnectionFactoryProxy allows for a non-JCA ConnectionFactory to be bound into the JNDI tree. This
+ ConnectionFactory can in turn be used outside of the application server. Typically a ConnectionFactory of
+ this sort is used by Swing or other two-tier clients not requiring JCA. The QpidConnectionFactoryProxy provides
+ one property
+
+connectionURL
+ This is the url used to configure the connection factory. Please see the Qpid Java Client documentation for
+ further details.
+
+
+Transaction Support
+===================
+The Qpid JCA Resource Adapter provides three levels of transaction support: XA, LocalTransactions and NoTransaction.
+Typical usage of the Qpid JCA Resource adapter implies the use of XA transactions, though there are certain scenarios
+where this is not preferred. Transaction support configuration is application server specific and as such, is explained
+in the corresponding documentation for each supported application server. However, there are two limitations with
+the Qpid JCA adapter at this time:
+
+1) Currently, the Qpid C++ broker does not support he use of XA within the context of clustered brokers. As such, if
+you are running in a cluster, you will need to configure the adapter to use LocalTransactions.
+
+2)XARecovery is currently not implemented. In the case of a system failure, in doubt transactions will have to be
+manually resolved by and administrator or otherwise qualified personnel.
+
+Conclusion
+==========
+The above documentation provides a general description of the capabilities and configuration properites of the
+Qpid JCA Resource Adapter. As previously mentioned, deploying an adapter in an application server requires
+specific descriptors and configuration mechanisms. Please see the accompanying doc for your application server
+for further details.
+
+
diff --git a/qpid/java/jca/build.xml b/qpid/java/jca/build.xml
new file mode 100644
index 0000000000..3430232003
--- /dev/null
+++ b/qpid/java/jca/build.xml
@@ -0,0 +1,69 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="Qpid JCA RA" default="build">
+
+ <property name="module.depends" value="common client"/>
+ <property name="module.name" value="ra"/>
+
+ <import file="../module.xml"/>
+
+ <property name="module.rar" value="${build.lib}/${project.name}-${module.name}-${project.version}.rar"/>
+ <property name="module.resources" value="src/main/resources"/>
+
+
+ <target name="rar" depends="jar">
+ <jar destfile="${module.rar}">
+ <fileset dir="${module.resources}">
+ <include name="**/*.xml"/>
+ </fileset>
+ <fileset dir="${build.lib}">
+ <include name="${project.name}-ra-${project.version}.jar"/>
+ <include name="${project.name}-client-${project.version}.jar"/>
+ <include name="${project.name}-common-${project.version}.jar"/>
+ </fileset>
+ </jar>
+ </target>
+
+ <!-- Create properties file for examples -->
+ <target name="example-properties-file">
+ <copy file="example/build-properties.xml.temp" tofile="example/build-properties.xml">
+ <filterset>
+ <filter token="project.version" value="${project.version}"/>
+ </filterset>
+ </copy>
+ </target>
+
+ <!-- Copy jars for standalone examples -->
+ <target name="example-jars">
+ <mkdir dir="example/lib"/>
+ <copy todir="example/lib">
+ <fileset dir="${build.lib}">
+ <include name="${project.name}-ra-${project.version}.jar"/>
+ <include name="${project.name}-client-${project.version}.jar"/>
+ <include name="${project.name}-common-${project.version}.jar"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="examples" depends="example-properties-file, example-jars"/>
+
+ <target name="build" depends="rar, examples"/>
+</project>
diff --git a/qpid/java/jca/example/.gitignore b/qpid/java/jca/example/.gitignore
new file mode 100644
index 0000000000..597acff14b
--- /dev/null
+++ b/qpid/java/jca/example/.gitignore
@@ -0,0 +1,2 @@
+build/*
+lib/*
diff --git a/qpid/java/jca/example/README.txt b/qpid/java/jca/example/README.txt
new file mode 100644
index 0000000000..d94bbfa7e5
--- /dev/null
+++ b/qpid/java/jca/example/README.txt
@@ -0,0 +1,277 @@
+Qpid JCA Example
+
+Overview
+=======
+The Qpid JCA example provides a sample JEE application that demonstrates how to
+configure, install and run applications using the Qpid JCA adapter for EE
+connectivity and the Apache Qpid C++ Broker. This example code can be used as a
+convenient starting point for your own development and deployment
+efforts. Currently the example is supported on JBoss EAP 5.x, JBoss 6.x and
+Apache Geronimo 2.x.
+
+Example Components
+===================
+Currently the example application consists of the following components:
+
+Destinations and ConnectionFactories
+
+Any messaging application relies on destinations (queues or topics )
+in order to produce or consume messages.The Qpid JCA example provides
+five destinations by default:
+
+ HelloTopic
+ GoodByeTopic
+ HelloGoodByeTopic
+ HelloQueue
+ GoodByeQueue
+ QpidResponderQueue
+
+
+Similar to destinations, ConnectionFactories are a core component of both JMS
+and JCA. ConnectionFactories provide the necessary starting point to make a connection,
+establish a session and produce or consume (or both) messages from your JMS provider.
+
+The Qpid JCA example provides three connection factories by default:
+
+ QpidJMSXA
+ QpidJMS
+ QpidConnectionFactory
+
+Each of these ConnectionFactories varies in their capabilities and the context in which
+they should be used. These concepts will be explained later in this document.
+
+The deployment configuration for destinations, and ConnectionFactories varies by platform.
+In JBossEAP, the configuration mechanism is a *-ds.xml file. Geronimo 2.2.x has the notion
+of a deployment plan in the form of a geronimo-ra.xml file.
+
+The Qpid JCA Example provides both a qpid-jca-ds.xml file as well as a geronimo-ra.xml deployment
+plan. Both mechanisms provide a reasonable set of defaults to allow you to deploy the Qpid JCA
+adapter in either environment and get up and running quickly.
+
+EJB 3.x
+
+There are a six EJB 3.x components provided as part of the example.
+
+ QpidHelloSubscriberBean - MessageDrivenBean (MDB)
+ QpidGoodByeSubscriberBean - (MDB)
+ QpidHelloListenerBean - (MDB)
+ QpidGoodByeListenerBean - (MDB)
+ QpidJMSResponderBean - (MDB)
+ QpidTestBean - Stateless Session Bean (SLSB)
+
+Servlet 2.5
+
+ QpidTestServlet
+
+A sample EE 2.5 servlet is provided allowing testing from a browser versus a JNDI
+client
+
+EE EAR archive
+ An EAR wrapper for the ejb and web components.
+
+
+ An RMI client used to excercise the EJB 3.x component.
+
+Sample *-ds.xml file
+ A sample *-ds.xml file is provided to create destinations and ManagedConnectionFactories
+ in the JBoss environment.
+
+Sample geronimo-ra.xml
+ A sample geronimo-ra.xml file is provided to create destinations and ManagedConnectionFactories
+ in the Geronimo environment. This file is semantically equivalent to the JBoss *-ds.xml artifact.
+
+A build.xml file
+ An ant build.xml file to configure, install and deploy the aforementioned components.
+
+
+Requirements
+============
+
+Depending upon your target platform (eg. JBoss EAP or Geronimo) you will need to set either
+the JBOSS_HOME or GERONIMO_HOME property. By default, these properties are assumed to be
+set from your environment. This can be modified in the build.xml file.
+
+JBoss EAP 5.x, JBoss 6.x
+ To use the sample application you will need to have JBoss EAP 5.x or JBoss 6.x running.
+
+Geronimo 2.x
+ To use the sample application you will need to have Geronimo 2.x running.
+
+Apache Qpid Broker
+ To run the sample it is assumed you have an Apache Qpid C++ broker configured and running.
+ The example code assumes that the broker will run at localhost on port 5672. This can be
+ modified within the build.xml file if this does not suit your particular environment.
+
+
+Quickstart
+==========
+After satifsying the above requirements you are ready to deploy and run the example application.
+The steps to deploy and run in the supported application servers are largely the same, however,
+if you are targeting JBoss you will either need to modify the property in the example build.xml file
+
+
+ <property name="target.platform" value="geronimo"/>
+
+to be jboss
+
+ <property name="target.platform" value="jboss"/>
+
+or set this property via the command line.
+
+Example:
+
+ ant -Dtarget.platform=jboss <target>
+
+**Note**
+Any time you wish to change platforms, this property needs to be modified and a complete clean
+and rebuild needs to be performed.
+
+Step 1 -- Package, Deploy and configure the Qpid JCA adapter
+
+The core component of the example is the Qpid JCA adapter. The following lists the steps
+for the respective platforms
+
+**Note**
+
+Regardless of platform, if you are building the Qpid JCA adapter from source code
+you will need to use to package the RAR file via the Ant build system. To do this, from
+the example directory execute
+
+ ant deploy-rar
+
+This task packages the adapter and includes the necessary dependent jar files.
+
+
+JBoss
+ There are no additional steps to package the adapter for JBoss deployment. Simply copy
+ the qpid-ra-<qpid.version>rar to your JBoss deploy directory.
+
+ To configure the Qpid JCA Adapter in JBoss the *-ds.xml file mechanism is used. A sample
+ file is provided in the conf directory.
+
+ If the defaults are suitable, you can simply execute
+
+ ant deploy-ds
+
+ While any property can be modified in the qpid-jca-ds.xml file, typically you will want to
+ change the URL of the broker to which you are trying to connect. Rather than modifying
+ the qpid-jca-ds.xml file directly you can modify the
+
+ <property name="broker.url" value="amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''"/>
+
+ line in the build.xml file. This will dynamically insert the broker.url value into the qpid-jca-ds.xml file.
+
+ Once this file is copied to your JBoss deploy directory and you received no exceptions, the adapter is now deployed, configured
+ and ready for use.
+
+Geronimo
+ By default, the Qpid JCA adapter ships with the geronimo-ra.xml deployment plan embedded
+ in the RAR file. This file is located in the META-INF directory alongside the ra.xml file.
+ By default the adapter is configured to access a broker located at localhost with the
+ default port of 5672. The ANONYMOUS security mechanism is also in use. If this is not
+ desirable, you have two approaches to configure the adapter.
+
+
+ 1) Extract the META-INF/ra.xml file from the RAR file, modify and recompress the RAR archive
+ with the updated contents.
+
+ 2) Use the example build system to package the adapter. The example build.xml file includes
+ a target
+
+ package-rar
+
+ that can be used to package the RAR file as well as allowing changes to the geronimo-ra.xml
+ file without having to extract the RAR file by hand. The conf/geronimo-ra.xml file is used
+ when you use the example build system.
+
+ While any property can be modified in the geronimo-ra.xml file, typically you will want to
+ change the URL of the broker to which you are trying to connect. Rather than modifying
+ the geronimo-ra.xml file directly you can modify the
+
+
+ <property name="broker.url" value="amqp://anonymous:@client/test?brokerlist='tcp://10.0.1.44:5672?sasl_mechs='ANONYMOUS''"/>
+
+ line in the build.xml file. This will dynamically insert the broker.url value into the geronimo-ra.xml file.
+
+ Once you have made your modifications you can execute
+
+
+ ant clean package-rar deploy-rar
+
+ Note, your Geronimo server must be running and your GERONIMO_HOME environment variable must be set. Barring any exceptions, the
+ adapter is now deployed and ready for use in Geronimo.
+
+
+Step 2 -- Deploy the application component(s).
+
+As previously mentioned, the adapter comes with a variety of EE components for use in your respective application server. You can choose to deploy
+these components individually, or as a single EAR archive. This document assumes that you will use the EAR to deploy and run the example.
+
+The command to package and deploy the EAR archive is the same across application servers. Executing the following command
+
+ant deploy-ear
+
+will, depending upon platform, package the EAR and deploy the archive in your respective environment. Once this step is executed, the example
+is ready for use.
+
+
+Step 3 -- Test the Example
+
+The Qpid JCA example provides an EJB application, as well as a Web application. Both can be used to test/run the example:
+
+EJB
+If you want to use the EJB application to test the example you can execute
+
+ ant run-client
+
+Running this command will perform a JNDI lookup of the SLSB in either JBoss or Geronimo and send a simple string to the SLSB. The SLSB will receive
+this string, construct a JMS message and place this message on a configured queue. The MDB will in turn receive this message and print the contents
+to the console.
+
+The main properties involved in this task are
+
+server.host
+jndi.context
+
+These vary depending upon which application server you are runnning. These can be modified to suit your environment. Looking at the run-client task you
+will see the following:
+
+
+ <sysproperty key="qpid.ejb.name" value="qpid-jcaex/QpidTestBean/remote"/>
+
+This is the JNDI name of the SLSB component and it varies by application server. Typically you do not have to change this. Also, the task supports another property
+
+
+ <sysproperty key="qpid.message" value="insert-value-here"/>
+
+You can set this property if you want to modify the message contents being routed through the system.
+
+Web
+The Qpid JCA Example comes with a web application. To access the web component, simply use a browser of your choice and navigate to
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid
+
+where server-host and server-port are the host and port where you are running your application server. By default this is localhost:8080. Similar to the EJB component,
+the web application supports a few options:
+
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid?messsage=<yourmessage>
+
+will allow you to customize the message contents that are routed through the system. By default, the Web application posts to a configured queue in the system. If you want to
+test XA functionality, or use an alternate approach, you can specify
+
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid?useEJB=true
+
+instead of posting to a queue, the web application will use the local interface of the EJB component to send the message. This is functionally equivalent to running the
+RMI client.
+
+
+Summary
+=======
+While conceptually simple, the Qpid JCA example provides a majority of the component types and messaging patterns you are most likely to use your development efforts.
+With the Web and EJB components, you can experiment with various aspects of JCA as well as EE development in general using the Qpid Broker as your messaging provider.
+While this documentation highlights the major components and steps needed to take to get the example running, the possiblities for modifcation are numerous. You are
+encouraged to experiment with the example as you develop your own messaging applications.
+
+
diff --git a/qpid/java/jca/example/build-geronimo-properties.xml b/qpid/java/jca/example/build-geronimo-properties.xml
new file mode 100644
index 0000000000..79cf5adc74
--- /dev/null
+++ b/qpid/java/jca/example/build-geronimo-properties.xml
@@ -0,0 +1,169 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="qpid-jca-example-geronimo-properties" basedir="." default="">
+
+ <property name="geronimo.jndi.scheme" value="name"/>
+ <property name="qpid.xacf.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAManagedConnectionFactory/QpidJMSXA"/>
+ <property name="qpid.cf.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/QpidConnectionFactory"/>
+ <property name="qpid.hello.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/HelloQueue"/>
+ <property name="qpid.goodbye.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/GoodByeQueue"/>
+ <property name="qpid.responder.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/ResponderQueue"/>
+ <property name="qpid.hello.topic.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/HelloTopic"/>
+ <property name="qpid.goodbye.topic.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/GoodByeTopic"/>
+ <property name="qpid.ejb.jndi.name" value="name=&quot;QpidTestEJB&quot;"/>
+ <property name="qpid.ejb.name" value="QpidTestBeanRemote"/>
+
+ <property name="jndi.context" value="org.openejb.client.RemoteInitialContextFactory"/>
+ <property name="server.host" value="ejbd://localhost:4201"/>
+ <property name="geronimo.home" location="${env.GERONIMO_HOME}"/>
+ <property name="geronimo.user" value="system"/>
+ <property name="geronimo.password" value="manager"/>
+
+ <property name="geronimo.rar.group.id" value="qpid.jca"/>
+ <property name="geronimo.rar.artifact.id" value="QpidJCAAdapter"/>
+ <property name="geronimo.rar.version" value="1.0"/>
+ <property name="geronimo.rar.type" value="rar"/>
+ <property name="geronimo.rar.id" value="${geronimo.rar.group.id}/${geronimo.rar.artifact.id}/${geronimo.rar.version}/${geronimo.rar.type}"/>
+
+ <property name="geronimo.ejb.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.ejb.artifact.id" value="QpidJCAEJBExample"/>
+ <property name="geronimo.ejb.version" value="1.0"/>
+ <property name="geronimo.ejb.type" value="car"/>
+ <property name="geronimo.ejb.id" value="${geronimo.ejb.group.id}/${geronimo.ejb.artifact.id}/${geronimo.ejb.version}/${geronimo.ejb.type}"/>
+
+ <property name="geronimo.war.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.war.artifact.id" value="QpidJCAWebExample"/>
+ <property name="geronimo.war.version" value="1.0"/>
+ <property name="geronimo.war.type" value="war"/>
+ <property name="geronimo.war.id" value="${geronimo.war.group.id}/${geronimo.war.artifact.id}/${geronimo.war.version}/${geronimo.war.type}"/>
+
+ <property name="geronimo.ear.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.ear.artifact.id" value="QpidJCAEARExample"/>
+ <property name="geronimo.ear.version" value="1.0"/>
+ <property name="geronimo.ear.type" value="ear"/>
+ <property name="geronimo.ear.id" value="${geronimo.ear.group.id}/${geronimo.ear.artifact.id}/${geronimo.ear.version}/${geronimo.ear.type}"/>
+
+ <property name="geronimo.rar.plan" value="${gen.dir}/geronimo-ra.xml"/>
+ <property name="geronimo.ear.plan" value="${gen.dir}/geronimo-application.xml"/>
+
+ <path id="compile.classpath">
+ <fileset dir="${geronimo.home}/repository/org/apache/geronimo/specs">
+ <include name="geronimo-jms_1.1_spec/1.1.1/geronimo-jms_1.1_spec-1.1.1.jar"/>
+ <include name="geronimo-servlet_2.5_spec/1.2/geronimo-servlet_2.5_spec-1.2.jar"/>
+ <include name="geronimo-ejb_3.0_spec/1.0.1/geronimo-ejb_3.0_spec-1.0.1.jar"/>
+ <include name="geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/lib/">
+ <include name="slf4j-api-*.jar"/>
+ </fileset>
+ </path>
+
+ <path id="run.classpath">
+ <fileset dir="${lib.dir}">
+ <include name="qpid-ra-*.jar"/>
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/repository/org/apache/geronimo/specs">
+ <include name="geronimo-j2ee-connector_1.5_spec/2.0.0/geronimo-j2ee-connector_1.5_spec-2.0.0.jar"/>
+ <include name="geronimo-jms_1.1_spec/1.1.1/geronimo-jms_1.1_spec-1.1.1.jar"/>
+ <include name="geronimo-servlet_2.5_spec/1.2/geronimo-servlet_2.5_spec-1.2.jar"/>
+ <include name="geronimo-ejb_3.0_spec/1.0.1/geronimo-ejb_3.0_spec-1.0.1.jar"/>
+ <include name="geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/lib/">
+ <include name="slf4j-api-*.jar"/>
+ <include name="slf4j-log4j*-*.jar"/>
+ <include name="log4j-*.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/repository/org/apache/openejb/openejb-client/3.1.4/"/>
+ </path>
+
+ <filterset id="extra.filterset">
+ <filter token="geronimo.ejb.group.id" value="${geronimo.ejb.group.id}"/>
+ <filter token="geronimo.ejb.artifact.id" value="${geronimo.ejb.artifact.id}"/>
+ <filter token="geronimo.ejb.version" value="${geronimo.ejb.version}"/>
+ <filter token="geronimo.ejb.type" value="${geronimo.ejb.type}"/>
+ <filter token="geronimo.war.group.id" value="${geronimo.war.group.id}"/>
+ <filter token="geronimo.war.artifact.id" value="${geronimo.war.artifact.id}"/>
+ <filter token="geronimo.war.version" value="${geronimo.war.version}"/>
+ <filter token="geronimo.war.type" value="${geronimo.war.type}"/>
+ <filter token="geronimo.ear.group.id" value="${geronimo.ear.group.id}"/>
+ <filter token="geronimo.ear.artifact.id" value="${geronimo.ear.artifact.id}"/>
+ <filter token="geronimo.ear.version" value="${geronimo.ear.version}"/>
+ <filter token="geronimo.ear.type" value="${geronimo.ear.type}"/>
+ </filterset>
+
+ <macrodef name="geronimo">
+ <attribute name="user" default="${geronimo.user}"/>
+ <attribute name="password" default="${geronimo.password}"/>
+ <attribute name="action" default="list-modules"/>
+ <attribute name="module"/>
+ <attribute name="plan" default=""/>
+ <sequential>
+ <exec executable="${geronimo.home}/bin/deploy.sh">
+ <arg line="-u @{user} -p @{password} @{action} @{module} @{plan}"/>
+ </exec>
+ </sequential>
+ </macrodef>
+
+ <!-- Deployment is target specific so is included here -->
+ <target name="deploy-rar" depends="generate" description="Deploy the RAR file.">
+ <geronimo action="deploy" module="${qpid.jca.dir}/${rar.name}" plan="${geronimo.rar.plan}"/>
+ </target>
+
+ <target name="undeploy-rar" description="Undeploys the RAR deployment.">
+ <geronimo action="undeploy" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="start-rar" description="Starts the RAR deployment in the Geronimo environment.">
+ <geronimo action="start" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="stop-rar" description="Stops the RAR deployment in the Geronimo environment.">
+ <geronimo action="stop" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="restart-rar" description="Restarts the RAR deployment in the Geronimo environment.">
+ <geronimo action="restart" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="deploy-ear" depends="package-ear" description="Deploys the EAR archive.">
+ <geronimo action="deploy" module="${build.dir}/${ear.name}" plan="${geronimo.ear.plan}"/>
+ </target>
+
+ <target name="undeploy-ear" description="Undeployes the EAR archive.">
+ <geronimo action="undeploy" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="start-ear" description="Starts the EAR deployment in the Geronimo environment.">
+ <geronimo action="start" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="stop-ear" description="Stops the EAR deployment in the Geronimo environment.">
+ <geronimo action="stop" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="restart-ear" description="Restarts the EAR deployment in the Geronimo environment.">
+ <geronimo action="restart" module="${geronimo.ear.id}"/>
+ </target>
+
+</project>
diff --git a/qpid/java/jca/example/build-jboss-properties.xml b/qpid/java/jca/example/build-jboss-properties.xml
new file mode 100644
index 0000000000..3554488d2d
--- /dev/null
+++ b/qpid/java/jca/example/build-jboss-properties.xml
@@ -0,0 +1,115 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+-->
+<project name="qpid-jca-example-jboss-properties" basedir="." default="">
+
+ <property name="jboss.jndi.scheme" value="mappedName"/>
+ <property name="qpid.xacf.jndi.name" value="java:QpidJMSXA"/>
+ <property name="qpid.cf.jndi.name" value="QpidConnectionFactory"/>
+ <property name="qpid.hello.topic.jndi.name" value="HelloTopic"/>
+ <property name="qpid.goodbye.topic.jndi.name" value="GoodByeTopic"/>
+ <property name="qpid.hello.queue.jndi.name" value="HelloQueue"/>
+ <property name="qpid.goodbye.queue.jndi.name" value="GoodByeQueue"/>
+ <property name="qpid.responder.queue.jndi.name" value="QpidResponderQueue"/>
+ <property name="qpid.ejb.jndi.name" value="mappedName=&quot;QpidTestEJB&quot;"/>
+ <property name="qpid.ejb.ref.name" value="QpidTestBean/local"/>
+ <property name="qpid.ejb.name" value="qpid-jcaex/QpidTestBean/remote"/>
+
+ <property name="jndi.context" value="org.jnp.interfaces.NamingContextFactory"/>
+ <property name="server.host" value="jnp://localhost:1099"/>
+
+ <property name="jboss.home" location="${env.JBOSS_HOME}"/>
+ <property name="jboss.server" value="default"/>
+ <property name="jboss.deploy" location="${jboss.home}/server/${jboss.server}/deploy"/>
+ <property name="jboss.client" location="${jboss.home}/client"/>
+
+ <path id="compile.classpath">
+ <fileset dir="${jboss.client}">
+ <!-- JBoss 5-->
+ <include name="jboss-javaee.jar"/>
+
+ <!-- JBoss 6 -->
+ <include name="jboss-servlet-api_3.0_spec.jar"/>
+ <include name="jboss-jms-api_1.1_spec.jar"/>
+ <include name="jboss-ejb-api_3.1_spec.jar"/>
+ <include name="jboss-transaction-api_1.1_spec.jar"/>
+
+ <!-- Common to JBoss 5/6 -->
+ <include name="slf4j-api.jar"/>
+ </fileset>
+
+ <!-- JBoss 5 -->
+ <fileset dir="${jboss.home}/common/lib">
+ <include name="servlet-api.jar"/>
+ </fileset>
+ </path>
+
+ <path id="run.classpath">
+ <fileset dir="${lib.dir}">
+ <include name="qpid-ra-*.jar"/>
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ </fileset>
+ <fileset dir="${jboss.client}">
+ <!-- Shortcut to get it working!-->
+ <include name="jbossall-client.jar"/>
+ </fileset>
+ </path>
+
+ <filterset id="extra.filterset"/>
+
+ <!-- Deployment is target specific so is included here -->
+ <target name="deploy-rar" description="Deploy the RAR file.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${qpid.jca.dir}">
+ <include name="${rar.name}"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-rar" description="Undeploys the RAR deployment.">
+ <delete file="${jboss.deploy}/${rar.name}"/>
+ </target>
+
+ <target name="deploy-ear" depends="package-ear" description="Deploys the EAR archive.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${build.dir}">
+ <include name="${ear.name}"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-ear" description="Undeploys the EAR archive.">
+ <delete file="${jboss.deploy}/${ear.name}"/>
+ </target>
+
+ <target name="deploy-ds" depends="generate" description="Deploys the ds.xml file to the JBoss environment.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${gen.dir}">
+ <include name="qpid-jca-ds.xml"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-ds" description="Undeploys the ds.xml file from the JBoss environment.">
+ <delete file="${jboss.deploy}/qpid-jca-ds.xml"/>
+ </target>
+
+</project>
diff --git a/qpid/java/systests/etc/config-systests-aclv2-settings.xml b/qpid/java/jca/example/build-properties.xml.temp
index fbf218fdfa..9eae869c27 100644
--- a/qpid/java/systests/etc/config-systests-aclv2-settings.xml
+++ b/qpid/java/jca/example/build-properties.xml.temp
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +18,6 @@
- under the License.
-
-->
-<broker>
- <security>
- <aclv2>${QPID_HOME}/etc/global-default.txt</aclv2>
- </security>
-
- <virtualhosts>${QPID_HOME}/etc/virtualhosts-systests-aclv2.xml</virtualhosts>
-</broker>
-
-
+<project name="qpid-jca-example-build-properties" basedir="." default="">
+ <property name="qpid.ver" value="@project.version@"/>
+</project>
diff --git a/qpid/java/jca/example/build.xml b/qpid/java/jca/example/build.xml
new file mode 100644
index 0000000000..9d0cfc887e
--- /dev/null
+++ b/qpid/java/jca/example/build.xml
@@ -0,0 +1,204 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="qpid-jca-example" default="help" basedir="">
+
+ <!-- Valid target platforms are currently geronimo & jboss -->
+ <property name="target.platform" value="geronimo"/>
+
+ <!-- Change to BURL for older syntax support -->
+ <property name="qpid.dest_syntax" value="ADDR"/>
+
+ <!-- Broker specific properties. By default in the adapter we use localhost here you an override this with host specific info-->
+ <property name="broker.address" value="localhost"/>
+
+ <!-- Properties controlling running sample standalone client -->
+ <property name="client.use.ejb" value="false"/> <!-- uses JNDI/JMS or JNDI/RMI -->
+ <property name="client.message" value="Hello Qpid World"/>
+ <property name="client.message.count" value="1"/>
+ <property name="client.use.topic" value="false"/> <!-- Use topic/queue -->
+ <property name="client.say.goodbye" value="false"/>
+
+ <!-- Pull in environment vars as properties -->
+ <property environment="env"/>
+
+ <!-- QPID version property -->
+ <import file="${basedir}/build-properties.xml"/>
+
+ <import file="${basedir}/qpid-jca-example-properties.xml"/>
+
+ <!-- Target specific properties/targets -->
+ <import file="${basedir}/build-${target.platform}-properties.xml"/>
+
+ <macrodef name="compile">
+ <attribute name="classpath"/>
+ <sequential>
+ <javac srcdir="${gen.dir}"
+ destdir="${build.classes.dir}"
+ classpathref="@{classpath}"
+ debug="true" optimize="false"/>
+ </sequential>
+ </macrodef>
+
+ <echo message="Using Qpid version ${qpid.ver}"/>
+ <echo message="Building for platform ${target.platform}"/>
+ <echo message="Broker url is currently set to ${broker.url}"/>
+ <echo message="Qpid Destination Syntax is ${qpid.dest_syntax}"/>
+
+ <target name="init">
+ <mkdir dir="${build.classes.dir}"/>
+ <mkdir dir="${gen.dir}"/>
+ <mkdir dir="${log.dir}"/>
+ </target>
+
+ <target name="generate" depends="init">
+ <copy todir="${gen.dir}" overwrite="true">
+ <fileset dir="${conf.dir}"/>
+ <filterset>
+ <filter token="rar.name" value="${rar.name}"/>
+ <filter token="ejb.name" value="${ejb.name}"/>
+ <filter token="war.name" value="${war.name}"/>
+
+ <filter token="broker.url" value="${broker.url}"/>
+
+ <filter token="qpid.hello.topic.dest.address" value="${qpid.hello.topic.dest.address}"/>
+ <filter token="qpid.goodbye.topic.dest.address" value="${qpid.goodbye.topic.dest.address}"/>
+ <filter token="qpid.hellogoodbye.topic.dest.address" value="${qpid.hellogoodbye.topic.dest.address}"/>
+ <filter token="qpid.hello.queue.dest.address" value="${qpid.hello.queue.dest.address}"/>
+ <filter token="qpid.goodbye.queue.dest.address" value="${qpid.goodbye.queue.dest.address}"/>
+ <filter token="qpid.responder.queue.dest.address" value="${qpid.responder.queue.dest.address}"/>
+
+ </filterset>
+ <filterset refid="extra.filterset"/>
+ </copy>
+ <copy todir="${gen.dir}">
+ <fileset dir="${src.dir}"/>
+ <filterset>
+ <filter token="rar.name" value="${rar.name}"/>
+ <filter token="broker.url" value="${broker.url}"/>
+ <filter token="jndi.scheme" value="${jndi.scheme}"/>
+ <filter token="qpid.xacf.jndi.name" value="${qpid.xacf.jndi.name}"/>
+ <filter token="qpid.hello.topic.jndi.name" value="${qpid.hello.topic.jndi.name}"/>
+ <filter token="qpid.goodbye.topic.jndi.name" value="${qpid.goodbye.topic.jndi.name}"/>
+ <filter token="qpid.hello.queue.jndi.name" value="${qpid.hello.queue.jndi.name}"/>
+ <filter token="qpid.goodbye.queue.jndi.name" value="${qpid.goodbye.queue.jndi.name}"/>
+ <filter token="qpid.responder.queue.jndi.name" value="${qpid.responder.queue.jndi.name}"/>
+ <filter token="qpid.ejb.jndi.name" value="${qpid.ejb.jndi.name}"/>
+ </filterset>
+ </copy>
+ </target>
+
+ <target name="compile" depends="generate" description="Compiles the source files for the Qpid JCA example">
+ <compile classpath="compile.classpath"/>
+ </target>
+
+ <target name="package-war" depends="compile" description="Packages the WAR file for deployment.">
+ <war destfile="${build.dir}/${war.name}" webxml="${gen.dir}/web.xml">
+ <classes dir="${build.classes.dir}">
+ <include name="org/apache/qpid/jca/example/web/**"/>
+ </classes>
+ <webinf dir="${gen.dir}">
+ <include name="jboss-web.xml"/>
+ </webinf>
+ </war>
+ </target>
+
+ <target name="package-ejb" depends="compile" description="Packages the EJB archive for deployment.">
+ <jar destfile="${build.dir}/${ejb.name}" basedir="${build.classes.dir}">
+ <include name="org/apache/qpid/jca/example/ejb/**/*.class"/>
+ <metainf dir="${gen.dir}">
+ <include name="jboss.xml"/>
+ <include name="ejb-jar.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <target name="package-ear" depends="generate, package-war, package-ejb" description="Packages the EAR archive for deployment.">
+ <jar destfile="${build.dir}/${ear.name}" basedir="${build.dir}">
+ <include name="*.war"/>
+ <include name="*.jar"/>
+ <metainf dir="${gen.dir}">
+ <include name="application.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <target name="run-client" depends="compile" description="Runs the RMI client.">
+ <java classname="org.apache.qpid.jca.example.client.QpidTestClient">
+ <classpath>
+ <pathelement path="${build.classes.dir}"/>
+ <path refid="run.classpath"/>
+ </classpath>
+ <sysproperty key="java.naming.factory.initial" value="${jndi.context}"/>
+ <sysproperty key="java.naming.provider.url" value="${server.host}"/>
+ <sysproperty key="qpid.ejb.name" value="${qpid.ejb.name}"/>
+ <sysproperty key="qpid.cf.name" value="${qpid.cf.jndi.name}"/>
+ <sysproperty key="qpid.dest_syntax" value="${qpid.dest_syntax}"/>
+ <sysproperty key="qpid.dest.name" value="${qpid.hello.queue.jndi.name}"/>
+ <sysproperty key="log4j.configuration" value="file://${conf.dir}/log4j.properties"/>
+
+ <sysproperty key="qpid.message" value="${client.message}"/>
+ <sysproperty key="message.count" value="${client.message.count}"/>
+ <sysproperty key="use.topic" value="${client.use.topic}"/>
+ <sysproperty key="use.ejb" value="${client.use.ejb}"/>
+ <sysproperty key="say.goodbye" value="${client.say.goodbye}"/>
+ </java>
+ </target>
+
+ <target name="run-reqresp" depends="compile">
+ <java classname="org.apache.qpid.jca.example.client.QpidRequestResponseClient">
+ <classpath>
+ <pathelement path="${build.classes.dir}"/>
+ <path refid="run.classpath"/>
+ </classpath>
+ <sysproperty key="java.naming.factory.initial" value="${jndi.context}"/>
+ <sysproperty key="java.naming.provider.url" value="${server.host}"/>
+ <sysproperty key="qpid.message" value="Hello, World"/>
+ <sysproperty key="message.count" value="1"/>
+ <sysproperty key="thread.count" value="5"/>
+ <sysproperty key="qpid.cf.name" value="${qpid.cf.jndi.name}"/>
+ <sysproperty key="qpid.dest.name" value="${qpid.responder.queue.jndi.name}"/>
+ <sysproperty key="log4j.configuration" value="file://${conf.dir}/log4j.properties"/>
+ <sysproperty key="qpid.dest_syntax" value="${qpid.dest_syntax}"/>
+ </java>
+ </target>
+
+ <target name="clean" description="Deletes the build directory and all related files.">
+ <delete dir="${build.dir}"/>
+ </target>
+
+ <target name="help">
+ <echo>
+
+ ant compile
+ This will compile all the source code for the Qpid JCA example project to the ${build.classes.dir} directory.
+
+ ant deploy-rar deploy-ear
+ Deploys a particular component which could be rar, ear (or ds for JBoss)
+
+ ant undeploy-ear undeploy-rar
+ Undeploys a particular component which could be rar, ear (or ds for JBoss)
+
+ ant run-client run-reqresp
+ Runs the RMI/thin client or the request-response client example
+ </echo>
+ </target>
+
+</project>
diff --git a/qpid/java/systests/etc/virtualhosts-systests-aclv2.xml b/qpid/java/jca/example/conf/application.xml
index db396d7ab1..d181bcda67 100644
--- a/qpid/java/systests/etc/virtualhosts-systests-aclv2.xml
+++ b/qpid/java/jca/example/conf/application.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -19,11 +19,19 @@
- under the License.
-
-->
-<configuration>
- <system/>
- <override>
- <xml fileName="${QPID_HOME}/${test.virtualhosts}" optional="true"/>
- <xml fileName="${QPID_HOME}/etc/virtualhosts-systests-aclv2-settings.xml"/>
- <xml fileName="${QPID_HOME}/etc/virtualhosts.xml"/>
- </override>
-</configuration>
+<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd">
+
+ <module>
+ <ejb>@ejb.name@</ejb>
+ </module>
+
+ <module>
+ <web>
+ <web-uri>@war.name@</web-uri>
+ <context-root>/qpid-jca-web</context-root>
+ </web>
+ </module>
+
+</application>
+
diff --git a/qpid/java/jca/example/conf/ejb-jar.xml b/qpid/java/jca/example/conf/ejb-jar.xml
new file mode 100644
index 0000000000..2f513bd3f8
--- /dev/null
+++ b/qpid/java/jca/example/conf/ejb-jar.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </session>
+ </enterprise-beans>
+
+
+</ejb-jar>
diff --git a/qpid/java/jca/example/conf/geronimo-application.xml b/qpid/java/jca/example/conf/geronimo-application.xml
new file mode 100644
index 0000000000..832496e76f
--- /dev/null
+++ b/qpid/java/jca/example/conf/geronimo-application.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application-2.0"
+ xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.2"
+ xmlns:naming="http://geronimo.apache.org/xml/ns/naming-1.2"
+ application-name="QpidJCAExampleApplication">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.ear.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.ear.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.ear.version@</sys:version>
+ <sys:type>@geronimo.ear.type@</sys:type>
+ </sys:moduleId>
+ </sys:environment>
+
+ <!-- Plan for embedded WAR -->
+ <module>
+ <web>qpid-jcaex-web.war</web>
+ <web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.war.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.war.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.war.version@</sys:version>
+ <sys:type>@geronimo.war.type@</sys:type>
+ </sys:moduleId>
+
+ <sys:dependencies>
+ <sys:dependency>
+ <sys:groupId>qpid.jca</sys:groupId>
+ <sys:artifactId>QpidJCAAdapter</sys:artifactId>
+ <sys:version>1.0</sys:version>
+ <sys:type>rar</sys:type>
+ </sys:dependency>
+ </sys:dependencies>
+ </sys:environment>
+
+ <context-root>/qpid-jca-web</context-root>
+
+ <naming:ejb-local-ref>
+ <naming:ref-name>QpidTestBean</naming:ref-name>
+ <naming:ejb-link>QpidTestBean</naming:ejb-link>
+ </naming:ejb-local-ref>
+
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </web-app>
+ </module>
+
+ <!-- Plan for embedded EJBs -->
+ <module>
+ <ejb>qpid-jcaex-ejb.jar</ejb>
+ <openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar-2.1">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.ejb.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.ejb.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.ejb.version@</sys:version>
+ <sys:type>@geronimo.ejb.type@</sys:type>
+ </sys:moduleId>
+
+ <sys:dependencies>
+ <sys:dependency>
+ <sys:groupId>qpid.jca</sys:groupId>
+ <sys:artifactId>QpidJCAAdapter</sys:artifactId>
+ <sys:version>1.0</sys:version>
+ <sys:type>rar</sys:type>
+ </sys:dependency>
+ </sys:dependencies>
+ <sys:hidden-classes/>
+ <sys:non-overridable-classes/>
+ </sys:environment>
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeListenerBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeSubscriberBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </session>
+ </enterprise-beans>
+ </openejb-jar>
+ </module>
+</application>
diff --git a/qpid/java/jca/example/conf/geronimo-ra.xml b/qpid/java/jca/example/conf/geronimo-ra.xml
new file mode 100644
index 0000000000..2943ac0a58
--- /dev/null
+++ b/qpid/java/jca/example/conf/geronimo-ra.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<connector xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2">
+ <dep:environment xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2">
+ <dep:moduleId>
+ <dep:groupId>qpid.jca</dep:groupId>
+ <dep:artifactId>QpidJCAAdapter</dep:artifactId>
+ <dep:version>1.0</dep:version>
+ <dep:type>rar</dep:type>
+ </dep:moduleId>
+ </dep:environment>
+ <resourceadapter>
+ <resourceadapter-instance>
+ <resourceadapter-name>QpidResourceAdapter</resourceadapter-name>
+ <config-property-setting name="ClientId">client_id</config-property-setting>
+ <config-property-setting name="TransactionManagerLocatorClass">org.apache.qpid.ra.tm.GeronimoTransactionManagerLocator</config-property-setting>
+ <config-property-setting name="TransactionManagerLocatorMethod">getTransactionManager</config-property-setting>
+ <!-- Note, currently there is a bug with end/suspend and Geronimo. For now use local transactions-->
+ <config-property-setting name="UseLocalTx">true</config-property-setting>
+ <workmanager>
+ <gbean-link>DefaultWorkManager</gbean-link>
+ </workmanager>
+ </resourceadapter-instance>
+ <outbound-resourceadapter>
+ <connection-definition>
+ <connectionfactory-interface>org.apache.qpid.ra.QpidRAConnectionFactory</connectionfactory-interface>
+ <connectiondefinition-instance>
+ <name>QpidJMSXA</name>
+ <implemented-interface>javax.jms.QueueConnectionFactory</implemented-interface>
+ <implemented-interface>javax.jms.TopicConnectionFactory</implemented-interface>
+ <config-property-setting name="ConnectionURL">@broker.url@</config-property-setting>
+ <connectionmanager>
+ <!-- Note, currently there is a bug with end/suspend and Geronimo. For now use no transactions outbound -->
+ <no-transaction/>
+ <single-pool>
+ <max-size>20</max-size>
+ <min-size>0</min-size>
+ <match-one/>
+ </single-pool>
+ </connectionmanager>
+ </connectiondefinition-instance>
+ </connection-definition>
+ </outbound-resourceadapter>
+ <!-- Note, do not remove this admin object. There appears to be a bug in Geronimo's deployer that does not correctly create JNDI references
+ if an extra admin object is not present -->
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>Dummy</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">amq.topic</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hello.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>GoodByeTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.goodbye.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloGoodByeTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hellogoodbye.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hello.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>GoodByeQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.goodbye.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>ResponderQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.responder.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidConnectionFactoryProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>QpidConnectionFactory</message-destination-name>
+ <config-property-setting name="connectionURL">@broker.url@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ </resourceadapter>
+</connector>
+
diff --git a/qpid/java/systests/etc/config-systests-aclv2.xml b/qpid/java/jca/example/conf/jboss-web.xml
index e8b971a2a0..edacf8d418 100644
--- a/qpid/java/systests/etc/config-systests-aclv2.xml
+++ b/qpid/java/jca/example/conf/jboss-web.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,16 @@
- under the License.
-
-->
-<configuration>
- <system/>
- <override>
- <xml fileName="${QPID_HOME}/${test.config}" optional="true"/>
- <xml fileName="${QPID_HOME}/etc/config-systests-aclv2-settings.xml"/>
- <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
- <xml fileName="${QPID_HOME}/etc/config.xml"/>
- </override>
-</configuration>
+<jboss-web>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ <ejb-local-ref>
+ <ejb-ref-name>QpidTestBean</ejb-ref-name>
+ <jndi-name>qpid-jcaex/QpidTestBean/local</jndi-name>
+ </ejb-local-ref>
+ <context-root>qpid-jca-web</context-root>
+</jboss-web>
+
diff --git a/qpid/java/jca/example/conf/jboss.xml b/qpid/java/jca/example/conf/jboss.xml
new file mode 100644
index 0000000000..8b62ca73b0
--- /dev/null
+++ b/qpid/java/jca/example/conf/jboss.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<jboss
+ xmlns="http://www.jboss.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
+ http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
+ version="3.0">
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeListenerBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeSubscriberBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </session>
+ </enterprise-beans>
+
+</jboss>
diff --git a/qpid/java/jca/example/conf/log4j.properties b/qpid/java/jca/example/conf/log4j.properties
new file mode 100644
index 0000000000..f1847f4418
--- /dev/null
+++ b/qpid/java/jca/example/conf/log4j.properties
@@ -0,0 +1,18 @@
+log4j.rootLogger=DEBUG, CONSOLE, FILE
+
+#Console Appender
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+#File Appender
+log4j.appender.FILE=org.apache.log4j.FileAppender
+log4j.appender.FILE.File=./build/log/qpid-jca-example.log
+log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
+log4j.appender.FILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+log4j.logger.org.jboss=WARN
+log4j.logger.org.jnp.interfaces=WARN
+log4j.logger.org.apache.qpid=ERROR
+log4j.logger.org.apache.qpid.jca.example=DEBUG
+
diff --git a/qpid/java/jca/example/conf/qpid-jca-ds.xml b/qpid/java/jca/example/conf/qpid-jca-ds.xml
new file mode 100644
index 0000000000..9e589169e3
--- /dev/null
+++ b/qpid/java/jca/example/conf/qpid-jca-ds.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<connection-factories>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloTopic">
+ <attribute name="JNDIName">HelloTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.hello.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=GoodByeTopic">
+ <attribute name="JNDIName">GoodByeTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.goodbye.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloGoodByeTopic">
+ <attribute name="JNDIName">HelloGoodByeTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.hellogoodbye.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloQueue">
+ <attribute name="JNDIName">HelloQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.hello.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=GoodByeQueue">
+ <attribute name="JNDIName">GoodByeQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.goodbye.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidResponderQueue">
+ <attribute name="JNDIName">QpidResponderQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.responder.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidConnectionFactory">
+ <attribute name="JNDIName">QpidConnectionFactory</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.ConnectionFactory</attribute>
+ <attribute name="Properties">
+ connectionURL=@broker.url@
+ </attribute>
+ </mbean>
+
+ <!-- Non XA connection factory. Can be used when running adapter against clustered Brokers -->
+ <tx-connection-factory>
+ <jndi-name>QpidJMS</jndi-name>
+ <rar-name>@rar.name@</rar-name>
+ <local-transaction/>
+ <config-property name="useLocalTx" type="java.lang.Boolean">true</config-property>
+ <config-property name="connectionURL">@broker.url@</config-property>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+ <!--XA ConnectionFactory-->
+ <tx-connection-factory>
+ <jndi-name>QpidJMSXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>@rar.name@</rar-name>
+ <config-property name="connectionURL">@broker.url@</config-property>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+</connection-factories>
diff --git a/qpid/java/jca/example/conf/web.xml b/qpid/java/jca/example/conf/web.xml
new file mode 100644
index 0000000000..509612dc90
--- /dev/null
+++ b/qpid/java/jca/example/conf/web.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+
+ <ejb-local-ref>
+ <ejb-ref-name>QpidTestBean</ejb-ref-name>
+ <ejb-ref-type>Session</ejb-ref-type>
+ <local>org.apache.qpid.jca.example.ejb.QpidTestLocal</local>
+ </ejb-local-ref>
+
+ <servlet>
+ <display-name>QpidTestServlet</display-name>
+ <servlet-name>QpidTestServlet</servlet-name>
+ <servlet-class>org.apache.qpid.jca.example.web.QpidTestServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>QpidTestServlet</servlet-name>
+ <url-pattern>/qpid</url-pattern>
+ </servlet-mapping>
+
+
+</web-app>
+
diff --git a/qpid/java/jca/example/qpid-jca-example-properties.xml b/qpid/java/jca/example/qpid-jca-example-properties.xml
new file mode 100644
index 0000000000..ee0478a6e5
--- /dev/null
+++ b/qpid/java/jca/example/qpid-jca-example-properties.xml
@@ -0,0 +1,79 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="qpid-jca-example-properties" basedir="." default="">
+
+ <property name="src.dir" location="${basedir}/src/main/java"/>
+ <property name="lib.dir" location="${basedir}/lib"/>
+ <property name="conf.dir" location="${basedir}/conf"/>
+ <property name="build.dir" location="${basedir}/build"/>
+ <property name="build.classes.dir" location="${build.dir}/classes"/>
+ <property name="gen.dir" location="${build.dir}/gen"/>
+ <property name="log.dir" location="${build.dir}/log"/>
+ <property name="qpid.jca.dir" location="${env.QPID_JCA_HOME}"/>
+
+ <property name="ejb.name" value="qpid-jcaex-ejb.jar"/>
+ <property name="war.name" value="qpid-jcaex-web.war"/>
+ <property name="ear.name" value="qpid-jcaex.ear"/>
+
+ <property name="rar.ver" value="${qpid.ver}"/>
+ <property name="rar.name" value="qpid-ra-${rar.ver}.rar"/>
+
+ <property name="broker.url" value="amqp://anonymous:passwd@client/test?brokerlist='tcp://${broker.address}?sasl_mechs='ANONYMOUS''"/>
+
+ <property name="qpid.hello.topic.dest.address.ADDR" value="amq.topic/hello.Topic"/>
+ <property name="qpid.goodbye.topic.dest.address.ADDR" value="amq.topic/goodbye.Topic"/>
+ <property name="qpid.hellogoodbye.topic.dest.address.ADDR" value="amq.topic/goodbye.Topic"/>
+ <property name="qpid.hello.queue.dest.address.ADDR"
+ value="hello.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+ <property name="qpid.goodbye.queue.dest.address.ADDR"
+ value="goodbye.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+ <property name="qpid.responder.queue.dest.address.ADDR"
+ value="responder.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+
+ <property name="qpid.hello.topic.dest.address.BURL"
+ value="topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/>
+ <property name="qpid.goodbye.topic.dest.address.BURL"
+ value="topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/>
+ <property name="qpid.hellogoodbye.topic.dest.address.BURL"
+ value="topic://amq.topic//#.jcaTopic"/>
+ <property name="qpid.hello.queue.dest.address.BURL"
+ value="direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/>
+ <property name="qpid.goodbye.queue.dest.address.BURL"
+ value="direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/>
+ <property name="qpid.responder.queue.dest.address.BURL"
+ value="direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/>
+
+ <!-- This macro allows us to construct a property name which contains a property expansion -->
+ <macrodef name="set-address-property">
+ <attribute name="name"/>
+ <attribute name="syntax"/>
+ <sequential>
+ <property name="@{name}" value="${@{name}.@{syntax}}"/>
+ </sequential>
+ </macrodef>
+
+ <set-address-property name="qpid.hello.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.goodbye.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.hellogoodbye.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.hello.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.goodbye.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.responder.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+</project>
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java
new file mode 100644
index 0000000000..734df1c0f3
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.jca.example.client;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidRequestResponseClient implements MessageListener, Runnable
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidRequestResponseClient.class);
+
+ private static final String DEFAULT_CF_JNDI = "QpidConnectionFactory";
+ private static final String DEFAULT_DESTINATION_JNDI = "QpidResponderQueue";
+ private static final String DEFAULT_MESSAGE = "Hello, World!";
+ private static final int DEFAULT_MESSAGE_COUNT = 1;
+ private static final int DEFAULT_THREAD_COUNT = 1;
+ private static CountDownLatch THREAD_LATCH;
+ private static InitialContext CONTEXT;
+
+ private ConnectionFactory _connectionFactory;
+ private Connection _connection;
+ private Session _session;
+ private CountDownLatch _latch = null;
+ private int _count = DEFAULT_MESSAGE_COUNT;
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception
+ {
+ int threadCount = (System.getProperty("thread.count") == null)
+ ? DEFAULT_THREAD_COUNT : Integer.valueOf(System.getProperty("thread.count"));
+
+ _log.debug("Creating " + threadCount + " threads for execution.");
+
+ THREAD_LATCH = new CountDownLatch(threadCount);
+
+ CONTEXT = new InitialContext();
+
+ for(int i = 0; i < threadCount; i++)
+ {
+ new Thread(new QpidRequestResponseClient()).start();
+ }
+
+ _log.debug("Waiting for " + threadCount + " to finish.");
+ THREAD_LATCH.await(10, TimeUnit.SECONDS);
+
+ QpidUtil.closeResources(CONTEXT);
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ _latch.countDown();
+
+ if(message instanceof TextMessage)
+ {
+ try
+ {
+ _log.debug("Thread " + Thread.currentThread().getId() + " received response message with content " + ((TextMessage)message).getText());
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ }
+
+ if(_latch.getCount() == _count)
+ {
+ QpidUtil.closeResources(_session, _connection);
+ }
+
+ THREAD_LATCH.countDown();
+
+ }
+
+ public void run()
+ {
+ MessageProducer producer = null;
+ Destination requestQueue = null;
+ Destination responseQueue = null;
+
+ String cfName = (System.getProperty("qpid.cf.name") == null) ? DEFAULT_CF_JNDI : System.getProperty("qpid.cf.name");
+ String destName = (System.getProperty("qpid.dest.name") == null) ? DEFAULT_DESTINATION_JNDI : System.getProperty("qpid.dest.name");
+
+ try
+ {
+ _count = (System.getProperty("message.count") == null) ? DEFAULT_MESSAGE_COUNT : Integer.valueOf(System.getProperty("message.count"));
+ _latch = new CountDownLatch(_count);
+
+ _connectionFactory = (ConnectionFactory)QpidTestUtil.getFromJNDI(CONTEXT, cfName);
+ requestQueue = (Destination)QpidTestUtil.getFromJNDI(CONTEXT, destName);
+ _connection = _connectionFactory.createConnection();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ producer = _session.createProducer(requestQueue);
+ responseQueue = _session.createTemporaryQueue();
+ _session.createConsumer(responseQueue).setMessageListener(this);
+
+
+ _connection.start();
+
+ String content = (System.getProperty("qpid.message") == null) ? DEFAULT_MESSAGE : System.getProperty("qpid.message");
+
+ for(int i = 0; i < _count; i++)
+ {
+ TextMessage message = _session.createTextMessage();
+ message.setText(content);
+ message.setJMSReplyTo(responseQueue);
+ producer.send(message);
+
+ }
+
+ _latch.await();
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(producer);
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java
new file mode 100644
index 0000000000..a5a33e36ec
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java
@@ -0,0 +1,135 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jca.example.client;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.jca.example.ejb.QpidTest;
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidTestClient
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestClient.class);
+
+ private static final String DEFAULT_EJB_JNDI = "QpidTestBean/remote";
+ private static final String DEFAULT_CF_JNDI = "QpidConnectionFactory";
+ private static final String DEFAULT_MESSAGE = "Hello,World!";
+ private static final int DEFAULT_MESSAGE_COUNT = 1;
+ private static final boolean DEFAULT_USE_TOPIC = false;
+ private static final boolean DEFAULT_USE_EJB = true;
+ private static final String DEFAULT_DESTINATION_JNDI = "HelloQueue";
+ private static final boolean DEFAULT_SAY_GOODBYE = false;
+
+ public static void main(String[] args) throws Exception
+ {
+ String content = (System.getProperty("qpid.message") == null) ? DEFAULT_MESSAGE : System.getProperty("qpid.message");
+ boolean useEJB = (System.getProperty("use.ejb") == null) ? DEFAULT_USE_EJB : Boolean.valueOf(System.getProperty("use.ejb"));
+ int total = (System.getProperty("message.count") == null) ? DEFAULT_MESSAGE_COUNT : Integer.valueOf(System.getProperty("message.count"));
+ boolean useTopic = (System.getProperty("use.topic") == null) ? DEFAULT_USE_TOPIC : Boolean.valueOf(System.getProperty("use.topic"));
+ String destType = (useTopic) ? "Topic" : "Queue";
+ boolean goodbye = (System.getProperty("say.goodbye") == null) ? DEFAULT_SAY_GOODBYE : Boolean.valueOf(System.getProperty("say.goodbye"));
+
+ _log.debug("Environment: ");
+ _log.debug("JNDI IntialContectFactory: " + System.getProperty("java.naming.factory.initial"));
+ _log.debug("JNDI Provider: " + System.getProperty("java.naming.provider.url"));
+ _log.debug("Message content: " + content);
+ _log.debug("Message count:" + total);
+ _log.debug("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ _log.debug("Destination Type: " + destType);
+ _log.debug("Say GoodBye : " + goodbye);
+
+ Context context = new InitialContext();
+
+ if(useEJB)
+ {
+
+ String ejbName = (System.getProperty("qpid.ejb.name") == null) ? DEFAULT_EJB_JNDI : System.getProperty("qpid.ejb.name");
+
+ QpidTest ejb = (QpidTest)QpidTestUtil.getFromJNDI(context, ejbName);
+
+ _log.debug("Found SLSB " + ejbName + "in JNDI");
+ ejb.testQpidAdapter(content, total, useTopic, false, goodbye);
+
+ }
+ else
+ {
+ ConnectionFactory connectionFactory = null;
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ Destination destination = null;
+ int count = 0;
+
+ String cfName = (System.getProperty("qpid.cf.name") == null) ? DEFAULT_CF_JNDI : System.getProperty("qpid.cf.name");
+ String destName = (System.getProperty("qpid.dest.name") == null) ? DEFAULT_DESTINATION_JNDI : System.getProperty("qpid.dest.name");
+
+ _log.debug("Using JMS with CF name " + cfName + " and Destination name " + destName + " to send " + total + " message(s) with content " + content);
+
+ try
+ {
+ _log.debug("Using JNDI at " + System.getProperty("java.naming.provider.url"));
+
+ connectionFactory = (ConnectionFactory)QpidTestUtil.getFromJNDI(context, cfName);
+ destination = (Destination)QpidTestUtil.getFromJNDI(context, destName);
+
+ _log.debug("Using CF: " + connectionFactory);
+ _log.debug("Destination " + destination);
+
+ connection = connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(destination);
+
+ _log.debug("Sending " + total + " message(s) with content: " + content + " to destination " + destName);
+
+ for(int i = 0; i < total; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", goodbye);
+ messageProducer.send(message);
+ count++;
+ }
+
+
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ _log.error(e.getMessage());
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection, context);
+ }
+
+ _log.debug(count + " message(s) sent successfully");
+ }
+
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java
new file mode 100644
index 0000000000..7a53335d79
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.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.jca.example.client;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.spi.NamingManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidTestUtil {
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestUtil.class);
+
+ /*
+ * Encapsulate looking up in JNDI and working around a seeming bug in OpenEJB which returns a
+ * Reference when it should just return an object constructed from it
+ */
+ static Object getFromJNDI(Context context, String name) throws NamingException, Exception
+ {
+ Object o = context.lookup(name);
+ if (o instanceof Reference)
+ {
+ _log.debug("Got a Reference back from JNDI for " + name + " - working around");
+ return NamingManager.getObjectInstance(o, null, null, null);
+ }
+ else
+ {
+ return o;
+ }
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java
new file mode 100644
index 0000000000..9cf220de2a
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.goodbye.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "useLocalTx", propertyValue = "false"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidGoodByeListenerBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidGoodByeListenerBean.class);
+
+ @Override
+ public void onMessage(Message message)
+ {
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java
new file mode 100644
index 0000000000..8ad8aaa482
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java
@@ -0,0 +1,27 @@
+package org.apache.qpid.jca.example.ejb;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.goodbye.topic.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NotDurable"),
+ @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "hello.Topic"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+
+public class QpidGoodByeSubscriberBean implements MessageListener
+{
+
+ @Override
+ public void onMessage(Message message)
+ {
+ System.out.println(message);
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java
new file mode 100644
index 0000000000..d6d08d1557
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.hello.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidHelloListenerBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidHelloListenerBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.goodbye.queue.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidHelloListenerBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.propertyExists("say.goodbye") && message.getBooleanProperty("say.goodbye"))
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(_queue);
+ response = session.createTextMessage(temp.toString());
+ messageProducer.send(response);
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java
new file mode 100644
index 0000000000..43ccf9defd
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.hello.topic.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NotDurable"),
+ @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "hello.Topic"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidHelloSubscriberBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidHelloSubscriberBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _topic;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _topic = (Destination)context.lookup("@qpid.goodbye.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidHelloSubscriberBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.propertyExists("say.goodbye") && message.getBooleanProperty("say.goodbye"))
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(_topic);
+ response = session.createTextMessage(temp.toString());
+ messageProducer.send(response);
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java
new file mode 100644
index 0000000000..74d6fb6d89
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java
@@ -0,0 +1,100 @@
+package org.apache.qpid.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.responder.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidJMSResponderBean implements MessageListener
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidJMSResponderBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidJMSResponderBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.getJMSReplyTo() != null)
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(message.getJMSReplyTo());
+ response = session.createTextMessage();
+ response.setText(temp.toString());
+ messageProducer.send(response);
+ }
+ else
+ {
+ _log.warn("Response was requested with no JMSReplyToDestination set. Will not respond to message.");
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java
new file mode 100644
index 0000000000..14488fda53
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.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.jca.example.ejb;
+
+public interface QpidTest
+{
+ public void testQpidAdapter(String content) throws Exception;
+ public void testQpidAdapter(String content, int count) throws Exception;
+ public void testQpidAdapter(String content, int count, boolean useTopic) throws Exception;
+ public void testQpidAdapter(String content, int count, boolean useTopic, boolean respond, boolean sayGoodbye) throws Exception;
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java
new file mode 100644
index 0000000000..17e37b9475
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.jca.example.ejb;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.Stateless;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Stateless
+public class QpidTestBean implements QpidTestRemote, QpidTestLocal
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ private Destination _topic;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.hello.queue.jndi.name@");
+ _topic = (Destination)context.lookup("@qpid.hello.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+ @Override
+ public void testQpidAdapter(String content) throws Exception
+ {
+ testQpidAdapter(content, 1);
+ }
+
+ @Override
+ public void testQpidAdapter(String content, int count) throws Exception
+ {
+ testQpidAdapter(content, count, false);
+ }
+
+ public void testQpidAdapter(final String content, int count, boolean useTopic) throws Exception
+ {
+ testQpidAdapter(content, count, useTopic, false, false);
+ }
+
+ @Override
+ public void testQpidAdapter(String content, int count, boolean useTopic,
+ boolean respond, boolean sayGoodbye) throws Exception
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+
+ _log.info("Sending " + count + " message(s) to MDB with content " + content);
+
+ try
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = (useTopic) ? session.createProducer(_topic) : session.createProducer(_queue);
+
+ for(int i = 0; i < count; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", sayGoodbye);
+ messageProducer.send(message);
+ }
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw e;
+ }
+ finally
+ {
+ QpidUtil.closeResources(messageProducer, session, connection);
+ }
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java
new file mode 100644
index 0000000000..73a0de08c2
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.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.jca.example.ejb;
+
+import javax.ejb.Local;
+
+@Local
+public interface QpidTestLocal extends QpidTest
+{
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java
new file mode 100644
index 0000000000..2abb4d71f5
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.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.jca.example.ejb;
+
+import javax.ejb.Remote;
+
+@Remote
+public interface QpidTestRemote extends QpidTest
+{
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java
new file mode 100644
index 0000000000..d96a4e8163
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jca.example.ejb;
+
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+
+import javax.jms.Message;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidUtil
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestBean.class);
+
+ public static void handleMessage(String beanName, final Message message) throws Exception
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+ _log.debug(beanName + ": Received text message with contents " + content);
+
+ if(content.contains("PrintEnv"))
+ {
+ printJMSHeaders(message);
+ printProperties(message);
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static void printProperties(final Message message) throws Exception
+ {
+ _log.debug("Priting Message Properties:");
+
+ Enumeration e = message.getPropertyNames();
+
+ while(e.hasMoreElements())
+ {
+ _log.debug(e + ":" + message.getObjectProperty(e.toString()));
+ }
+ }
+
+ public static void printJMSHeaders(final Message message) throws Exception
+ {
+ _log.debug("JMSCorrelationID:" + message.getJMSCorrelationID());
+ _log.debug("JMSDeliveryMode:" + message.getJMSDeliveryMode());
+ _log.debug("JMSExpires:" + message.getJMSExpiration());
+ _log.debug("JMSMessageID:" + message.getJMSMessageID());
+ _log.debug("JMSPriority:" + message.getJMSPriority());
+ _log.debug("JMSTimestamp:" + message.getJMSTimestamp());
+ _log.debug("JMSType:" + message.getJMSType());
+ _log.debug("JMSReplyTo:" + message.getJMSReplyTo());
+ }
+
+ public static void closeResources(Object...objects)
+ {
+ try
+ {
+ for(Object object: objects)
+ {
+ Method close = object.getClass().getMethod("close", new Class[]{});
+ close.invoke(object, new Object[]{});
+ }
+ }
+ catch(Exception ignore)
+ {
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java
new file mode 100644
index 0000000000..71289b22c3
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java
@@ -0,0 +1,209 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.jca.example.web;
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.transaction.UserTransaction;
+
+import org.apache.qpid.jca.example.ejb.QpidTest;
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("serial")
+public class QpidTestServlet extends HttpServlet
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestServlet.class);
+
+ private static final String DEFAULT_MESSAGE = "Hello, World!";
+ private static final int DEFAULT_COUNT = 1;
+ private static final boolean DEFAULT_TOPIC = false;
+ private static final boolean DEFAULT_XA = false;
+ private static final boolean DEFAULT_SAY_GOODBYE = true;
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ private Destination _topic;
+
+ public void init(ServletConfig config) throws ServletException
+ {
+
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.hello.queue.jndi.name@");
+ _topic = (Destination)context.lookup("@qpid.hello.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ doPost(req, resp);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ InitialContext ctx = null;
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ UserTransaction ut = null;
+ boolean useXA = false;
+ boolean rollback = false;
+
+ try
+ {
+ String content = (req.getParameter("message") == null) ? DEFAULT_MESSAGE : req.getParameter("message");
+ boolean useEJB = (req.getParameter("useEJB") == null) ? false : Boolean.valueOf(req.getParameter("useEJB"));
+ int count = (req.getParameter("count") == null) ? DEFAULT_COUNT : Integer.valueOf(req.getParameter("count"));
+ boolean useTopic = (req.getParameter("useTopic") == null) ? DEFAULT_TOPIC : Boolean.valueOf(req.getParameter("useTopic"));
+ useXA = (req.getParameter("useXA") == null) ? DEFAULT_XA : Boolean.valueOf(req.getParameter("useXA"));
+ ctx = new InitialContext();
+ boolean sayGoodBye = (req.getParameter("sayGoodBye") == null) ? DEFAULT_SAY_GOODBYE : Boolean.valueOf(req.getParameter("sayGoodBye"));
+
+ _log.debug("Environment: ");
+ _log.debug("Message content: " + content);
+ _log.debug("Message count:" + count);
+ _log.debug("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ _log.debug("Destination Type: " + ((useTopic) ? "Topic" : "Queue"));
+ _log.debug("Using XA: " + useXA);
+ _log.debug("Say GoodBye: ", sayGoodBye);
+
+ resp.getOutputStream().println("Environment: ");
+ resp.getOutputStream().println("Message content: " + content);
+ resp.getOutputStream().println("Message count:" + count);
+ resp.getOutputStream().println("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ resp.getOutputStream().println("Destination Type: " + ((useTopic) ? "Topic" : "Queue"));
+ resp.getOutputStream().println("Using XA: " + useXA);
+ resp.getOutputStream().println("Say GoodBye: " + sayGoodBye);
+
+ if(useEJB)
+ {
+ QpidTest ejb = (QpidTest)ctx.lookup("java:comp/env/QpidTestBean");
+ ejb.testQpidAdapter(content, count, useTopic, false, sayGoodBye);
+ }
+ else
+ {
+ if(useXA)
+ {
+ ut = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
+ ut.begin();
+ }
+
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = (useTopic) ? session.createProducer(_topic) : session.createProducer(_queue);
+
+ for(int i = 0; i < count; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", sayGoodBye);
+ messageProducer.send(message);
+ }
+
+ }
+
+ resp.getOutputStream().println("Sent " + count + " messages with content '" + content + "'");
+ resp.getOutputStream().flush();
+
+ }
+ catch(Exception e)
+ {
+
+ if(useXA && ut != null)
+ {
+ try
+ {
+ rollback = true;
+ ut.setRollbackOnly();
+ }
+ catch(Exception ex)
+ {
+ _log.error(ex.getMessage(), ex);
+ throw new ServletException(ex.getMessage(), ex);
+ }
+ }
+
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+ }
+ finally
+ {
+ if(useXA && ut != null)
+ {
+ try
+ {
+ if(rollback)
+ {
+ ut.rollback();
+ }
+ else
+ {
+ ut.commit();
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+
+ }
+ }
+
+ QpidUtil.closeResources(session, connection, ctx);
+ }
+ }
+
+
+
+}
+
+
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java
new file mode 100644
index 0000000000..2dc94ed194
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.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.ra;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ *
+ * A ConnectionFactoryObjectFactory.
+ *
+ * Given a reference - reconstructs a QpidRAConnectionFactory
+ *
+ */
+public class ConnectionFactoryObjectFactory implements ObjectFactory
+{
+ static final String QPID_CF = "QPID-CF";
+
+ public Object getObjectInstance(final Object ref, final Name name, final Context ctx, final Hashtable<?,?> props) throws Exception
+ {
+ if (!(ref instanceof Reference))
+ {
+ throw new IllegalArgumentException();
+ }
+
+ RefAddr ra = ((Reference)ref).get(QPID_CF);
+ if (ra == null)
+ {
+ throw new NameNotFoundException();
+ }
+
+ byte[] bytes = (byte[])ra.getContent();
+
+ return Util.deserialize(bytes);
+
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java
new file mode 100644
index 0000000000..be129a67cc
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java
@@ -0,0 +1,215 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class ConnectionFactoryProperties
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(ConnectionFactoryProperties.class);
+
+ private boolean _hasBeenUpdated = false;
+
+ private String _clientID;
+
+ private String _connectionURL;
+
+ private String _userName;
+
+ private String _password;
+
+ private String _host;
+
+ private Integer _port;
+
+ private String _path;
+
+ private Boolean _localTx = Boolean.FALSE;
+
+ public String getClientId()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+ return _clientID;
+ }
+
+ public void setClientId(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+ _hasBeenUpdated = true;
+ this._clientID = clientID;
+ }
+
+ public boolean isHasBeenUpdated()
+ {
+ return _hasBeenUpdated;
+ }
+
+ public String getConnectionURL()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnectionURL()");
+ }
+ return _connectionURL;
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setConnectionURL(" + connectionURL + ")");
+ }
+ _hasBeenUpdated = true;
+ this._connectionURL = connectionURL;
+ }
+
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultPassword()");
+ }
+ return _password;
+ }
+
+ public void setPassword(final String defaultPassword)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultPassword(" + defaultPassword + ")");
+ }
+ _hasBeenUpdated = true;
+ this._password = defaultPassword;
+ }
+
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultUsername()");
+ }
+ return _userName;
+ }
+
+ public void setUserName(final String defaultUsername)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultUsername(" + defaultUsername + ")");
+ }
+ _hasBeenUpdated = true;
+ this._userName = defaultUsername;
+ }
+
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+ return _host;
+ }
+
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+ _hasBeenUpdated = true;
+ this._host = host;
+ }
+
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+ return _port;
+ }
+
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+ _hasBeenUpdated = true;
+ this._port = port;
+ }
+
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+ return _path;
+ }
+
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+ _hasBeenUpdated = true;
+ this._path = path;
+ }
+
+ public Boolean isUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isUseLocalTx()");
+ }
+ return _localTx;
+ }
+
+ public void setUseLocalTx(Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ if(localTx != null)
+ {
+ _hasBeenUpdated = true;
+ this._localTx = localTx;
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java
new file mode 100644
index 0000000000..d30a45c739
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java
@@ -0,0 +1,462 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRABytesMessage extends QpidRAMessage implements BytesMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRABytesMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRABytesMessage(final BytesMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get body length
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getBodyLength() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBodyLength()");
+ }
+
+ return ((BytesMessage)_message).getBodyLength();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean readBoolean() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBoolean()");
+ }
+
+ return ((BytesMessage)_message).readBoolean();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte readByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readByte()");
+ }
+
+ return ((BytesMessage)_message).readByte();
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @param length The length
+ * @return The result
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ", " + length + ")");
+ }
+
+ return ((BytesMessage)_message).readBytes(value, length);
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @return The result
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ")");
+ }
+
+ return ((BytesMessage)_message).readBytes(value);
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char readChar() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readChar()");
+ }
+
+ return ((BytesMessage)_message).readChar();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double readDouble() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readDouble()");
+ }
+
+ return ((BytesMessage)_message).readDouble();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float readFloat() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readFloat()");
+ }
+
+ return ((BytesMessage)_message).readFloat();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readInt() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readInt()");
+ }
+
+ return ((BytesMessage)_message).readInt();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long readLong() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readLong()");
+ }
+
+ return ((BytesMessage)_message).readLong();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short readShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readShort()");
+ }
+
+ return ((BytesMessage)_message).readShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readUnsignedByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUnsignedByte()");
+ }
+
+ return ((BytesMessage)_message).readUnsignedByte();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readUnsignedShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUnsignedShort()");
+ }
+
+ return ((BytesMessage)_message).readUnsignedShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String readUTF() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUTF()");
+ }
+
+ return ((BytesMessage)_message).readUTF();
+ }
+
+ /**
+ * Reset
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void reset() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("reset()");
+ }
+
+ ((BytesMessage)_message).reset();
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBoolean(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBoolean(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeBoolean(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeByte(final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeByte(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeByte(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((BytesMessage)_message).writeBytes(value, offset, length);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeBytes(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeChar(final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeChar(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeChar(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeDouble(final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeDouble(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeDouble(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeFloat(final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeFloat(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeFloat(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeInt(final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeInt(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeInt(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeLong(final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeLong(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeLong(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeObject(final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeObject(" + Util.asString(value) + ")");
+ }
+
+ ((BytesMessage)_message).writeObject(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeShort(final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeShort(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeShort(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeUTF(final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeUTF(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeUTF(value);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java
new file mode 100644
index 0000000000..1e8fb13c79
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.Serializable;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XAQueueConnectionFactory;
+import javax.jms.XATopicConnectionFactory;
+import javax.resource.Referenceable;
+
+/**
+ * An aggregate interface for the JMS connection factories
+ *
+ */
+public interface QpidRAConnectionFactory extends ConnectionFactory, TopicConnectionFactory, QueueConnectionFactory,
+ XAConnectionFactory, XAQueueConnectionFactory, XATopicConnectionFactory, Serializable, Referenceable
+{
+ /** Connection factory capable of handling connections */
+ public static final int CONNECTION = 0;
+
+ /** Connection factory capable of handling queues */
+ public static final int QUEUE_CONNECTION = 1;
+
+ /** Connection factory capable of handling topics */
+ public static final int TOPIC_CONNECTION = 2;
+
+ /** Connection factory capable of handling XA connections */
+ public static final int XA_CONNECTION = 3;
+
+ /** Connection factory capable of handling XA queues */
+ public static final int XA_QUEUE_CONNECTION = 4;
+
+ /** Connection factory capable of handling XA topics */
+ public static final int XA_TOPIC_CONNECTION = 5;
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java
new file mode 100644
index 0000000000..77a38d5b34
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java
@@ -0,0 +1,442 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.TopicConnection;
+import javax.jms.XAConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XATopicConnection;
+import javax.naming.BinaryRefAddr;
+import javax.naming.Reference;
+import javax.resource.spi.ConnectionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The connection factory
+ *
+ */
+public class QpidRAConnectionFactoryImpl implements QpidRAConnectionFactory
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = -5306006173783505760L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionFactoryImpl.class);
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection manager */
+ private ConnectionManager _cm;
+
+ /** Naming reference */
+ private Reference _reference;
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cm The connection manager
+ */
+ public QpidRAConnectionFactoryImpl(final QpidRAManagedConnectionFactory mcf, final ConnectionManager cm)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cm + ")");
+ }
+
+ this._mcf = mcf;
+
+ if (cm == null)
+ {
+ // This is standalone usage, no appserver
+ this._cm = new QpidRAConnectionManager();
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created new ConnectionManager=" + this._cm);
+ }
+ }
+ else
+ {
+ this._cm = cm;
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Using ManagedConnectionFactory=" + mcf + ", ConnectionManager=" + this._cm);
+ }
+ }
+
+ /**
+ * Set the reference
+ * @param reference The reference
+ */
+ public void setReference(final Reference reference)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setReference(" + reference + ")");
+ }
+
+ this._reference = reference;
+ }
+
+ /**
+ * Get the reference
+ * @return The reference
+ */
+ public Reference getReference()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getReference()");
+ }
+ if (_reference == null)
+ {
+ try
+ {
+ _reference = new Reference(this.getClass().getCanonicalName(),
+ new BinaryRefAddr(ConnectionFactoryObjectFactory.QPID_CF,
+ Util.serialize(this)),
+ ConnectionFactoryObjectFactory.class.getCanonicalName(),
+ null);
+ }
+ catch (final IOException ioe)
+ {
+ _log.error("Error while giving object Reference.", ioe);
+ }
+ }
+
+ return _reference;
+
+ }
+
+ /**
+ * Create a queue connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public QueueConnection createQueueConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.QUEUE_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a queue connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public QueueConnection createQueueConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.QUEUE_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a topic connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public TopicConnection createTopicConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.TOPIC_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a topic connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public TopicConnection createTopicConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.TOPIC_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA queue connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAQueueConnection createXAQueueConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_QUEUE_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA queue connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAQueueConnection createXAQueueConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_QUEUE_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA topic connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XATopicConnection createXATopicConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_TOPIC_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA topic connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XATopicConnection createXATopicConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_TOPIC_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAConnection createXAConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.XA_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAConnection createXAConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.XA_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA connection: " + s);
+ }
+
+ return s;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java
new file mode 100644
index 0000000000..7ba5dd5374
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The connection manager used in non-managed environments.
+ *
+ */
+public class QpidRAConnectionManager implements ConnectionManager
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = 688529567919039006L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionManager.class);
+
+ /**
+ * Constructor
+ */
+ public QpidRAConnectionManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Allocates a connection
+ * @param mcf The managed connection factory
+ * @param cxRequestInfo The connection request information
+ * @return The connection
+ * @exception ResourceException Thrown if there is a problem obtaining the connection
+ */
+ public Object allocateConnection(final ManagedConnectionFactory mcf, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + mcf + ", " + cxRequestInfo + ")");
+ }
+
+ ManagedConnection mc = mcf.createManagedConnection(null, cxRequestInfo);
+ Object c = mc.getConnection(null, cxRequestInfo);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated connection: " + c + ", with managed connection: " + mc);
+ }
+
+ return c;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
new file mode 100644
index 0000000000..ec14c2a492
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.jms.ConnectionMetaData;
+
+import org.apache.qpid.client.CustomJMSXProperty;
+import org.apache.qpid.common.QpidProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements javax.jms.ConnectionMetaData
+ *
+ */
+public class QpidRAConnectionMetaData implements ConnectionMetaData
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionMetaData.class);
+
+ private static final String PROVIDER_VERSION ;
+ private static final int PROVIDER_MAJOR ;
+ private static final int PROVIDER_MINOR ;
+ private static final String[] JMSX_PROPERTY_NAMES ;
+
+ /**
+ * Constructor
+ */
+ public QpidRAConnectionMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the JMS version
+ * @return The version
+ */
+ public String getJMSVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSVersion()");
+ }
+
+ return "1.1";
+ }
+
+ /**
+ * Get the JMS major version
+ * @return The major version
+ */
+ public int getJMSMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMajorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS minor version
+ * @return The minor version
+ */
+ public int getJMSMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMinorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS provider name
+ * @return The name
+ */
+ public String getJMSProviderName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSProviderName()");
+ }
+
+ return QpidProperties.getProductName() + " Resource Adapter" ;
+ }
+
+ /**
+ * Get the provider version
+ * @return The version
+ */
+ public String getProviderVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderVersion()");
+ }
+
+ return PROVIDER_VERSION ;
+ }
+
+ /**
+ * Get the provider major version
+ * @return The version
+ */
+ public int getProviderMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMajorVersion()");
+ }
+
+ return PROVIDER_MAJOR ;
+ }
+
+ /**
+ * Get the provider minor version
+ * @return The version
+ */
+ public int getProviderMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMinorVersion()");
+ }
+
+ return PROVIDER_MINOR ;
+ }
+
+ /**
+ * Get the JMS XPropertyNames
+ * @return The names
+ */
+ public Enumeration<String> getJMSXPropertyNames()
+ {
+ // Bug in CustomJMSXProperty.asEnumeration() so we handle this here
+ return Collections.enumeration(Arrays.asList(JMSX_PROPERTY_NAMES)) ;
+ }
+
+ static
+ {
+ final String version = QpidProperties.getReleaseVersion() ;
+ int major = -1 ;
+ int minor = -1 ;
+ if (version != null)
+ {
+ final int separator = version.indexOf('.') ;
+ if (separator != -1)
+ {
+ major = parseInt(version.substring(0, separator), "major") ;
+ minor = parseInt(version.substring(separator+1, version.length()), "minor") ;
+ }
+ }
+ PROVIDER_VERSION = version ;
+ PROVIDER_MAJOR = major ;
+ PROVIDER_MINOR = minor ;
+
+ final CustomJMSXProperty[] properties = CustomJMSXProperty.values();
+ final String[] names = new String[properties.length] ;
+ int count = 0 ;
+ for(CustomJMSXProperty property : properties)
+ {
+ names[count++] = property.toString() ;
+ }
+ JMSX_PROPERTY_NAMES = names ;
+ }
+
+ private static int parseInt(final String value, final String name)
+ {
+ try
+ {
+ return Integer.parseInt(value) ;
+ }
+ catch (final NumberFormatException nfe)
+ {
+ _log.warn("Failed to parse " + name + ": " + value) ;
+ return -1 ;
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java
new file mode 100644
index 0000000000..c37a264ebc
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java
@@ -0,0 +1,361 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import javax.jms.Session;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+
+import org.apache.qpid.jms.ConnectionURL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Connection request information
+ *
+ */
+public class QpidRAConnectionRequestInfo implements ConnectionRequestInfo
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionRequestInfo.class);
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /** The client id */
+ private String _clientID;
+
+ /** The type */
+ private final int _type;
+
+ /** Use transactions */
+ private final boolean _transacted;
+
+ /** The acknowledge mode */
+ private final int _acknowledgeMode;
+
+ /**
+ * Constructor
+ * @param ra The resource adapter.
+ * @param type The connection type
+ * @throws ResourceException
+ */
+ public QpidRAConnectionRequestInfo(final QpidResourceAdapter ra, final int type)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + ra + ")");
+ }
+
+ final QpidRAProperties properties = ra.getProperties() ;
+ if (properties.getConnectionURL() != null)
+ {
+ final ConnectionURL connectionURL = ra.getDefaultAMQConnectionFactory().getConnectionURL() ;
+ _userName = connectionURL.getUsername();
+ _password = connectionURL.getPassword();
+ _clientID = connectionURL.getClientName();
+ }
+ else
+ {
+ _userName = ra.getDefaultUserName();
+ _password = ra.getDefaultPassword();
+ _clientID = ra.getClientId();
+ }
+ this._type = type;
+ _transacted = true;
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+
+ /**
+ * Constructor
+ * @param type The connection type
+ */
+ public QpidRAConnectionRequestInfo(final int type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + type + ")");
+ }
+
+ this._type = type;
+ _transacted = true;
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+
+ /**
+ * Constructor
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @param type The connection type
+ */
+ public QpidRAConnectionRequestInfo(final boolean transacted, final int acknowledgeMode, final int type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + transacted +
+ ", " +
+ acknowledgeMode +
+ ", " +
+ type +
+ ")");
+ }
+
+ this._transacted = transacted;
+ this._acknowledgeMode = acknowledgeMode;
+ this._type = type;
+ }
+
+ /**
+ * Fill in default values if they are missing
+ * @param connectionURL The connection URL
+ */
+ public void setDefaults(final ConnectionURL connectionURL)
+ {
+ if (_userName == null)
+ {
+ _userName = connectionURL.getUsername();
+ }
+ if (_password == null)
+ {
+ _password = connectionURL.getPassword();
+ }
+ if (_clientID == null)
+ {
+ _clientID = connectionURL.getClientName();
+ }
+ }
+
+ /**
+ * Fill in default values if they are missing
+ * @param ra The resource adapter
+ * @throws ResourceException
+ */
+ public void setDefaults(final QpidResourceAdapter ra)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaults(" + ra + ")");
+ }
+
+ final QpidRAProperties properties = ra.getProperties() ;
+ if (properties.getConnectionURL() != null)
+ {
+ setDefaults(ra.getDefaultAMQConnectionFactory().getConnectionURL()) ;
+ }
+ else
+ {
+ if (_userName == null)
+ {
+ _userName = ra.getDefaultUserName();
+ }
+ if (_password == null)
+ {
+ _password = ra.getDefaultPassword();
+ }
+ if (_clientID == null)
+ {
+ _clientID = ra.getClientId();
+ }
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The value
+ */
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Set the user name
+ * @param userName The value
+ */
+ public void setUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ this._userName = userName;
+ }
+
+ /**
+ * Get the password
+ * @return The value
+ */
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _password;
+ }
+
+ /**
+ * Set the password
+ * @param password The value
+ */
+ public void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get the client id
+ * @return The value
+ */
+ public String getClientID()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ return _clientID;
+ }
+
+ /**
+ * Set the client id
+ * @param clientID The value
+ */
+ public void setClientID(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+
+ this._clientID = clientID;
+ }
+
+ /**
+ * Get the connection type
+ * @return The type
+ */
+ public int getType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getType()");
+ }
+
+ return _type;
+ }
+
+ /**
+ * Use transactions
+ * @return True if transacted; otherwise false
+ */
+ public boolean isTransacted()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isTransacted() " + _transacted);
+ }
+
+ return _transacted;
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The mode
+ */
+ public int getAcknowledgeMode()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ return _acknowledgeMode;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof QpidRAConnectionRequestInfo)
+ {
+ QpidRAConnectionRequestInfo you = (QpidRAConnectionRequestInfo)obj;
+ return Util.compare(_userName, you.getUserName()) && Util.compare(_password, you.getPassword()) &&
+ Util.compare(_clientID, you.getClientID()) &&
+ _type == you.getType() &&
+ _transacted == you.isTransacted() &&
+ _acknowledgeMode == you.getAcknowledgeMode();
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ int hash = 7;
+
+ hash += 31 * hash + (_userName != null ? _userName.hashCode() : 0);
+ hash += 31 * hash + (_password != null ? _password.hashCode() : 0);
+ hash += 31 * hash + (_clientID != null ? _clientID.hashCode() : 0);
+ hash += 31 * hash + _type;
+ hash += 31 * hash + (_transacted ? 1 : 0);
+ hash += 31 * hash + _acknowledgeMode;
+
+ return hash;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "QpidRAConnectionRequestInfo[type=" + _type +
+ ", transacted=" + _transacted + ", acknowledgeMode=" + _acknowledgeMode +
+ ", clientID=" + _clientID + ", userName=" + _userName + ((_password != null) ? ", password=********]" :"]");
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
new file mode 100644
index 0000000000..2b42f9dc3d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Set;
+
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.SecurityException;
+import javax.resource.spi.security.PasswordCredential;
+import javax.security.auth.Subject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Credential information
+ *
+ */
+public class QpidRACredential implements Serializable
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = 7040664839205409352L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRACredential.class);
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /**
+ * Private constructor
+ */
+ private QpidRACredential()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The value
+ */
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Set the user name
+ * @param userName The value
+ */
+ private void setUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ this._userName = userName;
+ }
+
+ /**
+ * Get the password
+ * @return The value
+ */
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _password;
+ }
+
+ /**
+ * Set the password
+ * @param password The value
+ */
+ private void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get credentials
+ * @param mcf The managed connection factory
+ * @param subject The subject
+ * @param info The connection request info
+ * @return The credentials
+ * @exception SecurityException Thrown if the credentials cant be retrieved
+ */
+ public static QpidRACredential getCredential(final ManagedConnectionFactory mcf,
+ final Subject subject,
+ final ConnectionRequestInfo info) throws SecurityException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + mcf + ", " + subject + ", " + info + ")");
+ }
+
+ QpidRACredential jc = new QpidRACredential();
+ if (subject == null && info != null)
+ {
+ jc.setUserName(((QpidRAConnectionRequestInfo)info).getUserName());
+ jc.setPassword(((QpidRAConnectionRequestInfo)info).getPassword());
+ }
+ else if (subject != null)
+ {
+ PasswordCredential pwdc = GetCredentialAction.getCredential(subject, mcf);
+
+ if (pwdc == null)
+ {
+ throw new SecurityException("No password credentials found");
+ }
+
+ jc.setUserName(pwdc.getUserName());
+ jc.setPassword(new String(pwdc.getPassword()));
+ }
+ else
+ {
+ throw new SecurityException("No Subject or ConnectionRequestInfo set, could not get credentials");
+ }
+
+ return jc;
+ }
+
+ /**
+ * String representation
+ * @return The representation
+ */
+ @Override
+ public String toString()
+ {
+ return super.toString() + "{ username=" + _userName + ", password=**** }";
+ }
+
+ /**
+ * Privileged class to get credentials
+ */
+ private static class GetCredentialAction implements PrivilegedAction<PasswordCredential>
+ {
+ /** The subject */
+ private final Subject subject;
+
+ /** The managed connection factory */
+ private final ManagedConnectionFactory mcf;
+
+ /**
+ * Constructor
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ */
+ GetCredentialAction(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + subject + ", " + mcf + ")");
+ }
+
+ this.subject = subject;
+ this.mcf = mcf;
+ }
+
+ /**
+ * Run
+ * @return The credential
+ */
+ public PasswordCredential run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ Set<PasswordCredential> creds = subject.getPrivateCredentials(PasswordCredential.class);
+ PasswordCredential pwdc = null;
+
+ for (PasswordCredential curCred : creds)
+ {
+ if (curCred.getManagedConnectionFactory().equals(mcf))
+ {
+ pwdc = curCred;
+ break;
+ }
+ }
+ return pwdc;
+ }
+
+ /**
+ * Get credentials
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ * @return The credential
+ */
+ static PasswordCredential getCredential(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + subject + ", " + mcf + ")");
+ }
+
+ GetCredentialAction action = new GetCredentialAction(subject, mcf);
+ return AccessController.doPrivileged(action);
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java
new file mode 100644
index 0000000000..9c070f6184
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java
@@ -0,0 +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.ra;
+
+
+/**
+ * Qpid Resource Adapter exception.
+ */
+public class QpidRAException extends Exception
+{
+ /**
+ * The serial version uid for this serializable class.
+ */
+ private static final long serialVersionUID = 2921345326731695238L;
+
+ /**
+ * Create a default Qpid ra exception.
+ */
+ public QpidRAException()
+ {
+ super();
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific message.
+ * @param message The message associated with this exception.
+ */
+ public QpidRAException(final String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific cause.
+ * @param cause The cause associated with this exception.
+ */
+ public QpidRAException(final Throwable cause)
+ {
+ super(cause);
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific message and cause.
+ * @param message The message associated with this exception.
+ * @param cause The cause associated with this exception.
+ */
+ public QpidRAException(final String message, final Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java
new file mode 100644
index 0000000000..eeb49b6b52
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.jms.JMSException;
+import javax.resource.ResourceException;
+import javax.resource.spi.LocalTransaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JMS Local transaction
+ *
+ */
+public class QpidRALocalTransaction implements LocalTransaction
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRALocalTransaction.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _mc;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ */
+ public QpidRALocalTransaction(final QpidRAManagedConnection mc)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ")");
+ }
+
+ this._mc = mc;
+ }
+
+ /**
+ * Begin
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void begin() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("begin()");
+ }
+ }
+
+ /**
+ * Commit
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void commit() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("commit()");
+ }
+
+ _mc.lock();
+
+ try
+ {
+ if (_mc.getSession() == null)
+ {
+ throw new ResourceException("Could not commit LocalTransaction: null Session.");
+ }
+
+ _mc.getSession().commit();
+ }
+ catch (JMSException e)
+ {
+ throw new ResourceException("Could not commit LocalTransaction", e);
+ }
+ finally
+ {
+ _mc.unlock();
+ }
+ }
+
+ /**
+ * Rollback
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void rollback() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("rollback()");
+ }
+
+ _mc.lock();
+ try
+ {
+ if (_mc.getSession() != null && _mc.getSession().getTransacted())
+ {
+ _mc.getSession().rollback();
+ }
+ }
+ catch (JMSException ex)
+ {
+ throw new ResourceException("Could not rollback LocalTransaction", ex);
+ }
+ finally
+ {
+ _mc.unlock();
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java
new file mode 100644
index 0000000000..dd60c175de
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java
@@ -0,0 +1,177 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The MCF default properties
+ *
+ */
+public class QpidRAMCFProperties extends ConnectionFactoryProperties implements Serializable
+{
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = -1675836810881223064L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMCFProperties.class);
+
+ /**
+ * The queue type
+ */
+ private static final String QUEUE_TYPE = Queue.class.getName();
+
+ /**
+ * The topic type
+ */
+ private static final String TOPIC_TYPE = Topic.class.getName();
+
+ /**
+ * The connection type
+ */
+ private int _type = QpidRAConnectionFactory.CONNECTION;
+
+ /**
+ * Use tryLock
+ */
+ private Integer _useTryLock;
+
+ /**
+ * Constructor
+ */
+ public QpidRAMCFProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _useTryLock = null;
+ }
+
+ /**
+ * Get the connection type
+ *
+ * @return The type
+ */
+ public int getType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getType()");
+ }
+
+ return _type;
+ }
+
+ /**
+ * Set the default session type.
+ *
+ * @param defaultType either javax.jms.Topic or javax.jms.Queue
+ */
+ public void setSessionDefaultType(final String defaultType)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSessionDefaultType(" + _type + ")");
+ }
+
+ if (defaultType.equals(QpidRAMCFProperties.QUEUE_TYPE))
+ {
+ _type = QpidRAConnectionFactory.QUEUE_CONNECTION;
+ }
+ else if (defaultType.equals(QpidRAMCFProperties.TOPIC_TYPE))
+ {
+ _type = QpidRAConnectionFactory.TOPIC_CONNECTION;
+ }
+ else
+ {
+ _type = QpidRAConnectionFactory.CONNECTION;
+ }
+ }
+
+ /**
+ * Get the default session type.
+ *
+ * @return The default session type
+ */
+ public String getSessionDefaultType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionDefaultType()");
+ }
+
+ if (_type == QpidRAConnectionFactory.CONNECTION)
+ {
+ return "BOTH";
+ }
+ else if (_type == QpidRAConnectionFactory.QUEUE_CONNECTION)
+ {
+ return QpidRAMCFProperties.TOPIC_TYPE;
+ }
+ else
+ {
+ return QpidRAMCFProperties.QUEUE_TYPE;
+ }
+ }
+
+ /**
+ * Get the useTryLock.
+ *
+ * @return the useTryLock.
+ */
+ public Integer getUseTryLock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseTryLock()");
+ }
+
+ return _useTryLock;
+ }
+
+ /**
+ * Set the useTryLock.
+ *
+ * @param useTryLock the useTryLock.
+ */
+ public void setUseTryLock(final Integer useTryLock)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseTryLock(" + useTryLock + ")");
+ }
+
+ this._useTryLock = useTryLock;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
new file mode 100644
index 0000000000..fb1b7f060c
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
@@ -0,0 +1,880 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.ResourceAllocationException;
+import javax.jms.Session;
+import javax.jms.QueueConnection;
+import javax.jms.TopicConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XASession;
+import javax.jms.XATopicConnection;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ConnectionEventListener;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.IllegalStateException;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionMetaData;
+import javax.resource.spi.SecurityException;
+import javax.security.auth.Subject;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The managed connection
+ *
+ */
+public class QpidRAManagedConnection implements ManagedConnection, ExceptionListener
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnection.class);
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection request information */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The user name */
+ private final String _userName;
+
+ /** The password */
+ private final String _password;
+
+ /** Has the connection been destroyed */
+ private final AtomicBoolean _isDestroyed = new AtomicBoolean(false);
+
+ /** Event listeners */
+ private final List<ConnectionEventListener> _eventListeners;
+
+ /** Handles */
+ private final Set<QpidRASessionImpl> _handles;
+
+ /** Lock */
+ private ReentrantLock _lock = new ReentrantLock();
+
+ // Physical JMS connection stuff
+ private Connection _connection;
+
+ private XASession _xaSession;
+
+ private XAResource _xaResource;
+
+ private Session _session;
+
+ private final TransactionManager _tm;
+
+ private boolean _inManagedTx;
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cri The connection request information
+ * @param userName The user name
+ * @param password The password
+ */
+ public QpidRAManagedConnection(final QpidRAManagedConnectionFactory mcf,
+ final QpidRAConnectionRequestInfo cri,
+ final TransactionManager tm,
+ final String userName,
+ final String password) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cri + ", " + userName + ", ****)");
+ }
+
+ this._mcf = mcf;
+ this._cri = cri;
+ this._tm = tm;
+ this._userName = userName;
+ this._password = password;
+ _eventListeners = Collections.synchronizedList(new ArrayList<ConnectionEventListener>());
+ _handles = Collections.synchronizedSet(new HashSet<QpidRASessionImpl>());
+
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ destroy();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ throw new ResourceException("Error during setup", t);
+ }
+ }
+
+ /**
+ * Get a connection
+ * @param subject The security subject
+ * @param cxRequestInfo The request info
+ * @return The connection
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public synchronized Object getConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ // Check user first
+ QpidRACredential credential = QpidRACredential.getCredential(_mcf, subject, cxRequestInfo);
+
+ // Null users are allowed!
+ if (_userName != null && !_userName.equals(credential.getUserName()))
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_userName == null && credential.getUserName() != null)
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ QpidRASessionImpl session = new QpidRASessionImpl(this, (QpidRAConnectionRequestInfo)cxRequestInfo);
+ _handles.add(session);
+ return session;
+ }
+
+ /**
+ * Destroy all handles.
+ * @exception ResourceException Failed to close one or more handles.
+ */
+ private void destroyHandles() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroyHandles()");
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Ignored error stopping connection", t);
+ }
+
+ for (QpidRASessionImpl session : _handles)
+ {
+ session.destroy();
+ }
+
+ _handles.clear();
+ }
+
+ /**
+ * Destroy the physical connection.
+ * @exception ResourceException Could not property close the session and connection.
+ */
+ public void destroy() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ if (_isDestroyed.get() || _connection == null)
+ {
+ return;
+ }
+
+ _isDestroyed.set(true);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error unsetting the exception listener " + this, e);
+ }
+
+ destroyHandles();
+
+ try
+ {
+ try
+ {
+ if (_xaSession != null)
+ {
+ _xaSession.close();
+ }
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error closing session " + this, e);
+ }
+
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable e)
+ {
+ throw new ResourceException("Could not properly close the session and connection", e);
+ }
+ }
+
+ /**
+ * Cleanup
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public void cleanup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("cleanup()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("ManagedConnection already destroyed");
+ }
+
+ destroyHandles();
+
+ _inManagedTx = false;
+
+ // I'm recreating the lock object when we return to the pool
+ // because it looks too nasty to expect the connection handle
+ // to unlock properly in certain race conditions
+ // where the dissociation of the managed connection is "random".
+ _lock = new ReentrantLock();
+ }
+
+ /**
+ * Move a handler from one mc to this one.
+ * @param obj An object of type QpidRASession.
+ * @throws ResourceException Failed to associate connection.
+ * @throws IllegalStateException ManagedConnection in an illegal state.
+ */
+ public void associateConnection(final Object obj) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("associateConnection(" + obj + ")");
+ }
+
+ if (!_isDestroyed.get() && obj instanceof QpidRASessionImpl)
+ {
+ QpidRASessionImpl h = (QpidRASessionImpl)obj;
+ h.setManagedConnection(this);
+ _handles.add(h);
+ }
+ else
+ {
+ throw new IllegalStateException("ManagedConnection in an illegal state");
+ }
+ }
+
+ public void checkTransactionActive() throws JMSException
+ {
+ // don't bother looking at the transaction if there's an active XID
+ if (!_inManagedTx && _tm != null)
+ {
+ try
+ {
+ Transaction tx = _tm.getTransaction();
+ if (tx != null)
+ {
+ int status = tx.getStatus();
+ // Only allow states that will actually succeed
+ if (status != Status.STATUS_ACTIVE && status != Status.STATUS_PREPARING &&
+ status != Status.STATUS_PREPARED &&
+ status != Status.STATUS_COMMITTING)
+ {
+ throw new javax.jms.IllegalStateException("Transaction " + tx + " not active");
+ }
+ }
+ }
+ catch (SystemException e)
+ {
+ JMSException jmsE = new javax.jms.IllegalStateException("Unexpected exception on the Transaction ManagerTransaction");
+ jmsE.initCause(e);
+ throw jmsE;
+ }
+ }
+ }
+
+
+ /**
+ * Aqquire a lock on the managed connection
+ */
+ protected void lock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ _lock.lock();
+ }
+
+ /**
+ * Aqquire a lock on the managed connection within the specified period
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected void tryLock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("tryLock()");
+ }
+
+ Integer tryLock = _mcf.getUseTryLock();
+ if (tryLock == null || tryLock.intValue() <= 0)
+ {
+ lock();
+ return;
+ }
+ try
+ {
+ if (_lock.tryLock(tryLock.intValue(), TimeUnit.SECONDS) == false)
+ {
+ throw new ResourceAllocationException("Unable to obtain lock in " + tryLock + " seconds: " + this);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new ResourceAllocationException("Interrupted attempting lock: " + this);
+ }
+ }
+
+ /**
+ * Unlock the managed connection
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lock.isHeldByCurrentThread())
+ {
+ _lock.unlock();
+ }
+ }
+
+ /**
+ * Add a connection event listener.
+ * @param l The connection event listener to be added.
+ */
+ public void addConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.add(l);
+ }
+
+ /**
+ * Remove a connection event listener.
+ * @param l The connection event listener to be removed.
+ */
+ public void removeConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.remove(l);
+ }
+
+ /**
+ * Get the XAResource for the connection.
+ * @return The XAResource for the connection.
+ * @exception ResourceException XA transaction not supported
+ */
+ public XAResource getXAResource() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ //
+ // Spec says a mc must allways return the same XA resource,
+ // so we cache it.
+ //
+ if (_xaResource == null)
+ {
+ _xaResource = new QpidRAXAResource(this, _xaSession.getXAResource());
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("XAResource=" + _xaResource);
+ }
+
+ return _xaResource;
+ }
+
+ /**
+ * Get the location transaction for the connection.
+ * @return The local transaction for the connection.
+ * @exception ResourceException Thrown if operation fails.
+ */
+ public LocalTransaction getLocalTransaction() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLocalTransaction()");
+ }
+
+ LocalTransaction tx = new QpidRALocalTransaction(this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("LocalTransaction=" + tx);
+ }
+
+ return tx;
+ }
+
+ /**
+ * Get the meta data for the connection.
+ * @return The meta data for the connection.
+ * @exception ResourceException Thrown if the operation fails.
+ * @exception IllegalStateException Thrown if the managed connection already is destroyed.
+ */
+ public ManagedConnectionMetaData getMetaData() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ return new QpidRAMetaData(this);
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ * @param out The log writer
+ * @exception ResourceException If operation fails
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ * @return Always null
+ * @exception ResourceException If operation fails
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Notifies user of a JMS exception.
+ * @param exception The JMS exception
+ */
+ public void onException(final JMSException exception)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onException(" + exception + ")");
+ }
+
+ if (_isDestroyed.get())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Ignoring error on already destroyed connection " + this, exception);
+ }
+ return;
+ }
+
+ _log.warn("Handling JMS exception failure: " + this, exception);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Unable to unset exception listener", e);
+ }
+
+ ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, exception);
+ sendEvent(event);
+ }
+
+ /**
+ * Get the session for this connection.
+ * @return The session
+ * @throws JMSException
+ */
+ protected Session getSession() throws JMSException
+ {
+ if(_xaSession != null && !_mcf.getUseLocalTx())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> XA session " + Util.asString(_xaSession));
+ }
+
+ return _xaSession;
+ }
+ else
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> session " + Util.asString(_session));
+ }
+
+ return _session;
+ }
+ }
+
+ /**
+ * Send an event.
+ * @param event The event to send.
+ */
+ protected void sendEvent(final ConnectionEvent event)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sendEvent(" + event + ")");
+ }
+
+ int type = event.getId();
+
+ // convert to an array to avoid concurrent modification exceptions
+ ConnectionEventListener[] list = _eventListeners.toArray(new ConnectionEventListener[_eventListeners.size()]);
+
+ for (ConnectionEventListener l : list)
+ {
+ switch (type)
+ {
+ case ConnectionEvent.CONNECTION_CLOSED:
+ l.connectionClosed(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
+ l.localTransactionStarted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
+ l.localTransactionCommitted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
+ l.localTransactionRolledback(event);
+ break;
+
+ case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
+ l.connectionErrorOccurred(event);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Illegal eventType: " + type);
+ }
+ }
+ }
+
+ /**
+ * Remove a handle from the handle map.
+ * @param handle The handle to remove.
+ */
+ protected void removeHandle(final QpidRASessionImpl handle)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeHandle(" + handle + ")");
+ }
+
+ _handles.remove(handle);
+ }
+
+ /**
+ * Get the request info for this connection.
+ * @return The connection request info for this connection.
+ */
+ protected QpidRAConnectionRequestInfo getCRI()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI()");
+ }
+
+ return _cri;
+ }
+
+ /**
+ * Get the connection factory for this connection.
+ * @return The connection factory for this connection.
+ */
+ protected QpidRAManagedConnectionFactory getManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getManagedConnectionFactory()");
+ }
+
+ return _mcf;
+ }
+
+ /**
+ * Start the connection
+ * @exception JMSException Thrown if the connection cant be started
+ */
+ void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.start();
+ }
+ }
+
+ /**
+ * Stop the connection
+ * @exception JMSException Thrown if the connection cant be stopped
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The user name
+ */
+ protected String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Setup the connection.
+ * @exception ResourceException Thrown if a connection couldnt be created
+ */
+ private void setup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setup()");
+ }
+
+ try
+ {
+ boolean transacted = _cri.isTransacted();
+ int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ boolean localTx = _mcf.getUseLocalTx();
+
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXATopicConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXATopicConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createTopicConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XATopicConnection)_connection).createXATopicSession();
+
+ }
+ else
+ {
+ _session = ((TopicConnection)_connection).createTopicSession(localTx, acknowledgeMode);
+ }
+ }
+ else if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAQueueConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAQueueConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createQueueConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXAQueueSession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createQueueSession(localTx, acknowledgeMode);
+
+ }
+ }
+ else
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXASession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createSession(localTx, acknowledgeMode);
+
+ }
+ }
+
+ _connection.setExceptionListener(this);
+ }
+ catch (JMSException je)
+ {
+ throw new ResourceException(je.getMessage(), je);
+ }
+ }
+
+ protected void setInManagedTx(boolean inManagedTx)
+ {
+ this._inManagedTx = inManagedTx;
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
new file mode 100644
index 0000000000..377a0c6253
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
@@ -0,0 +1,623 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.jms.ConnectionMetaData;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterAssociation;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Qpid ManagedConectionFactory
+ *
+ */
+public class QpidRAManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation
+{
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = -8798804592247643959L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnectionFactory.class);
+
+ /**
+ * The resource adapter
+ */
+ private QpidResourceAdapter _ra;
+
+ /**
+ * Connection manager
+ */
+ private ConnectionManager _cm;
+
+ /**
+ * The managed connection factory properties
+ */
+ private final QpidRAMCFProperties _mcfProperties;
+
+ /**
+ * Connection Factory used if properties are set
+ */
+ private AMQConnectionFactory _connectionFactory;
+
+ /**
+ * Constructor
+ */
+ public QpidRAManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _ra = null;
+ _cm = null;
+ _mcfProperties = new QpidRAMCFProperties();
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory()");
+ }
+
+ return createConnectionFactory(new QpidRAConnectionManager());
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @param cxManager The connection manager
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory(final ConnectionManager cxManager) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory(" + cxManager + ")");
+ }
+
+ _cm = cxManager;
+
+ QpidRAConnectionFactory cf = new QpidRAConnectionFactoryImpl(this, _cm);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection factory: " + cf +
+ ", using connection manager: " +
+ _cm);
+ }
+
+ return cf;
+ }
+
+ /**
+ * Creates a new physical connection to the underlying EIS resource manager.
+ *
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if a managed connection cant be created
+ */
+ public ManagedConnection createManagedConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createManagedConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("jms credential: " + credential);
+ }
+
+ QpidRAManagedConnection mc = new QpidRAManagedConnection(this,
+ cri,
+ _ra.getTM(),
+ credential.getUserName(),
+ credential.getPassword());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("created new managed connection: " + mc);
+ }
+
+ return mc;
+ }
+
+ /**
+ * Returns a matched connection from the candidate set of connections.
+ *
+ * @param connectionSet The candidate connection set
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if no managed connection can be found
+ */
+ @SuppressWarnings("rawtypes")
+ public ManagedConnection matchManagedConnections(final Set connectionSet,
+ final Subject subject,
+ final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("matchManagedConnections(" + connectionSet +
+ ", " +
+ subject +
+ ", " +
+ cxRequestInfo +
+ ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Looking for connection matching credentials: " + credential);
+ }
+
+ for (final Object obj : connectionSet)
+ {
+ if (obj instanceof QpidRAManagedConnection)
+ {
+ QpidRAManagedConnection mc = (QpidRAManagedConnection)obj;
+ ManagedConnectionFactory mcf = mc.getManagedConnectionFactory();
+
+ if ((mc.getUserName() == null || mc.getUserName() != null && mc.getUserName()
+ .equals(credential.getUserName())) && mcf.equals(this))
+ {
+ if (cri.equals(mc.getCRI()))
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Found matching connection: " + mc);
+ }
+
+ return mc;
+ }
+ }
+ }
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("No matching connection was found");
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ *
+ * @param out The writer
+ * @throws ResourceException Thrown if the writer cant be set
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ *
+ * @return The writer
+ * @throws ResourceException Thrown if the writer cant be retrieved
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the resource adapter
+ *
+ * @return The resource adapter
+ */
+ public ResourceAdapter getResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getResourceAdapter()");
+ }
+
+ return _ra;
+ }
+
+ /**
+ * Set the resource adapter
+ *
+ * @param ra The resource adapter
+ * @throws ResourceException Thrown if incorrect resource adapter
+ */
+ public void setResourceAdapter(final ResourceAdapter ra) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setResourceAdapter(" + ra + ")");
+ }
+
+ if (!(ra instanceof QpidResourceAdapter))
+ {
+ throw new ResourceException("Resource adapter is " + ra);
+ }
+
+ this._ra = (QpidResourceAdapter)ra;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof QpidRAManagedConnectionFactory)
+ {
+ QpidRAManagedConnectionFactory other = (QpidRAManagedConnectionFactory)obj;
+
+ return _mcfProperties.equals(other.getProperties()) && _ra.equals(other.getResourceAdapter());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ int hash = _mcfProperties.hashCode();
+ hash += 31 * _ra.hashCode();
+
+ return hash;
+ }
+
+ /**
+ * Get the default session type
+ *
+ * @return The value
+ */
+ public String getSessionDefaultType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionDefaultType()");
+ }
+
+ return _mcfProperties.getSessionDefaultType();
+ }
+
+ /**
+ * Set the default session type
+ *
+ * @param type either javax.jms.Topic or javax.jms.Queue
+ */
+ public void setSessionDefaultType(final String type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSessionDefaultType(" + type + ")");
+ }
+
+ _mcfProperties.setSessionDefaultType(type);
+ }
+
+ public String getClientID()
+ {
+ return _mcfProperties.getClientId();
+ }
+
+ public void setClientID(final String clientID)
+ {
+ _mcfProperties.setClientId(clientID);
+ }
+
+ public String getConnectionURL()
+ {
+ return _mcfProperties.getConnectionURL() ;
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ _mcfProperties.setConnectionURL(connectionURL);
+ }
+
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultPassword()");
+ }
+ return _mcfProperties.getPassword();
+ }
+
+ public void setPassword(final String defaultPassword)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultPassword(" + defaultPassword + ")");
+ }
+ _mcfProperties.setPassword(defaultPassword);
+ }
+
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultUsername()");
+ }
+ return _mcfProperties.getUserName();
+ }
+
+ public void setUserName(final String defaultUsername)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultUsername(" + defaultUsername + ")");
+ }
+ _mcfProperties.setUserName(defaultUsername);
+ }
+
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+ return _mcfProperties.getHost();
+ }
+
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+ _mcfProperties.setHost(host);
+ }
+
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+ return _mcfProperties.getPort();
+ }
+
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+ _mcfProperties.setPort(port);
+ }
+
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+ return _mcfProperties.getPath();
+ }
+
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+ _mcfProperties.setPath(path);
+ }
+
+ /**
+ * Get the useTryLock.
+ *
+ * @return the useTryLock.
+ */
+ public Integer getUseTryLock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseTryLock()");
+ }
+
+ return _mcfProperties.getUseTryLock();
+ }
+
+ /**
+ * Set the useTryLock.
+ *
+ * @param useTryLock the useTryLock.
+ */
+ public void setUseTryLock(final Integer useTryLock)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseTryLock(" + useTryLock + ")");
+ }
+
+ _mcfProperties.setUseTryLock(useTryLock);
+ }
+
+ /**
+ * Get the connection metadata
+ *
+ * @return The metadata
+ */
+ public ConnectionMetaData getMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetadata()");
+ }
+
+ return new QpidRAConnectionMetaData();
+ }
+
+ /**
+ * Get the default connection factory
+ *
+ * @return The factory
+ */
+ protected synchronized AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (_connectionFactory == null)
+ {
+ try
+ {
+ _connectionFactory = _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+ return _connectionFactory;
+ }
+
+ /**
+ * Get a clean connection factory
+ *
+ * @return The factory
+ */
+ protected AMQConnectionFactory getCleanAMQConnectionFactory() throws ResourceException
+ {
+ try
+ {
+ return _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+
+ /**
+ * Get the managed connection factory properties
+ *
+ * @return The properties
+ */
+ protected QpidRAMCFProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _mcfProperties;
+ }
+
+ /**
+ * Get a connection request info instance
+ *
+ * @param info The instance that should be updated; may be <code>null</code>
+ * @return The instance
+ * @throws ResourceException
+ */
+ private QpidRAConnectionRequestInfo getCRI(final QpidRAConnectionRequestInfo info)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI(" + info + ")");
+ }
+
+ if (info == null)
+ {
+ // Create a default one
+ return new QpidRAConnectionRequestInfo(_ra, _mcfProperties.getType());
+ }
+ else
+ {
+ // Fill the one with any defaults
+ info.setDefaults(_ra);
+ return info;
+ }
+ }
+
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _mcfProperties.isUseLocalTx();
+ }
+
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _mcfProperties.setUseLocalTx(localTx);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java
new file mode 100644
index 0000000000..797a28a09a
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java
@@ -0,0 +1,457 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAMapMessage extends QpidRAMessage implements MapMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMapMessage.class);
+
+ /**
+ * Create a new wrapper
+ *
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAMapMessage(final MapMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + message + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getBoolean(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBoolean(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getBoolean(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte getByte(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getByte(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getByte(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte[] getBytes(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBytes(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getBytes(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char getChar(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getChar(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getChar(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double getDouble(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDouble(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getDouble(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float getFloat(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getFloat(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getFloat(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getInt(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getInt(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getInt(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getLong(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLong(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getLong(name);
+ }
+
+ /**
+ * Get the map names
+ * @return The values
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Enumeration<?> getMapNames() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMapNames()");
+ }
+
+ return ((MapMessage)_message).getMapNames();
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object getObject(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObject(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getObject(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short getShort(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getShort(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getShort(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getString(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getString(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getString(name);
+ }
+
+ /**
+ * Does the item exist
+ * @param name The name
+ * @return True / false
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean itemExists(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("itemExists(" + name + ")");
+ }
+
+ return ((MapMessage)_message).itemExists(name);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBoolean(final String name, final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBoolean(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setBoolean(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setByte(final String name, final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setByte(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setByte(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBytes(final String name, final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBytes(" + name + ", " + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((MapMessage)_message).setBytes(name, value, offset, length);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBytes(final String name, final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBytes(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setBytes(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setChar(final String name, final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setChar(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setChar(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDouble(final String name, final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDouble(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setDouble(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setFloat(final String name, final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setFloat(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setFloat(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setInt(final String name, final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setInt(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setInt(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setLong(final String name, final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLong(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setLong(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObject(final String name, final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObject(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setObject(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setShort(final String name, final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setShort(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setShort(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setString(final String name, final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setString(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setString(name, value);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
new file mode 100644
index 0000000000..691fe8c40a
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
@@ -0,0 +1,782 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.util.Enumeration;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ */
+public class QpidRAMessage implements Message
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessage.class);
+
+ /** The message */
+ protected Message _message;
+
+ /** The session */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAMessage(final Message message, final QpidRASessionImpl session)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+
+ this._message = message;
+ this._session = session;
+ }
+
+ /**
+ * Acknowledge
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void acknowledge() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("acknowledge()");
+ }
+
+ _session.getSession(); // Check for closed
+ _message.acknowledge();
+ }
+
+ /**
+ * Clear body
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void clearBody() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("clearBody()");
+ }
+
+ _message.clearBody();
+ }
+
+ /**
+ * Clear properties
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void clearProperties() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("clearProperties()");
+ }
+
+ _message.clearProperties();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getBooleanProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBooleanProperty(" + name + ")");
+ }
+
+ return _message.getBooleanProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte getByteProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getByteProperty(" + name + ")");
+ }
+
+ return _message.getByteProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double getDoubleProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDoubleProperty(" + name + ")");
+ }
+
+ return _message.getDoubleProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float getFloatProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getFloatProperty(" + name + ")");
+ }
+
+ return _message.getFloatProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getIntProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getIntProperty(" + name + ")");
+ }
+
+ return _message.getIntProperty(name);
+ }
+
+ /**
+ * Get correlation id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSCorrelationID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSCorrelationID()");
+ }
+
+ return _message.getJMSCorrelationID();
+ }
+
+ /**
+ * Get correlation id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSCorrelationIDAsBytes()");
+ }
+
+ return _message.getJMSCorrelationIDAsBytes();
+ }
+
+ /**
+ * Get delivery mode
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getJMSDeliveryMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSDeliveryMode()");
+ }
+
+ return _message.getJMSDeliveryMode();
+ }
+
+ /**
+ * Get destination
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getJMSDestination() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSDestination()");
+ }
+
+ return _message.getJMSDestination();
+ }
+
+ /**
+ * Get expiration
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getJMSExpiration() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSExpiration()");
+ }
+
+ return _message.getJMSExpiration();
+ }
+
+ /**
+ * Get message id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSMessageID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMessageID()");
+ }
+
+ return _message.getJMSMessageID();
+ }
+
+ /**
+ * Get priority
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getJMSPriority() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSPriority()");
+ }
+
+ return _message.getJMSPriority();
+ }
+
+ /**
+ * Get redelivered status
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getJMSRedelivered() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSRedelivered()");
+ }
+
+ return _message.getJMSRedelivered();
+ }
+
+ /**
+ * Get reply to destination
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getJMSReplyTo() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSReplyTo()");
+ }
+
+ return _message.getJMSReplyTo();
+ }
+
+ /**
+ * Get timestamp
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getJMSTimestamp() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSTimestamp()");
+ }
+
+ return _message.getJMSTimestamp();
+ }
+
+ /**
+ * Get type
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSType() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSType()");
+ }
+
+ return _message.getJMSType();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getLongProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLongProperty(" + name + ")");
+ }
+
+ return _message.getLongProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object getObjectProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObjectProperty(" + name + ")");
+ }
+
+ return _message.getObjectProperty(name);
+ }
+
+ /**
+ * Get property names
+ * @return The values
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Enumeration<?> getPropertyNames() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPropertyNames()");
+ }
+
+ return _message.getPropertyNames();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short getShortProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getShortProperty(" + name + ")");
+ }
+
+ return _message.getShortProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getStringProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getStringProperty(" + name + ")");
+ }
+
+ return _message.getStringProperty(name);
+ }
+
+ /**
+ * Do property exist
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean propertyExists(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("propertyExists(" + name + ")");
+ }
+
+ return _message.propertyExists(name);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBooleanProperty(final String name, final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBooleanProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setBooleanProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setByteProperty(final String name, final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setByteProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setByteProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDoubleProperty(final String name, final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDoubleProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setDoubleProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setFloatProperty(final String name, final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setFloatProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setFloatProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setIntProperty(final String name, final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setIntProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setIntProperty(name, value);
+ }
+
+ /**
+ * Set correlation id
+ * @param correlationID The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSCorrelationID(final String correlationID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSCorrelationID(" + correlationID + ")");
+ }
+
+ _message.setJMSCorrelationID(correlationID);
+ }
+
+ /**
+ * Set correlation id
+ * @param correlationID The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSCorrelationIDAsBytes(final byte[] correlationID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSCorrelationIDAsBytes(" + correlationID + ")");
+ }
+
+ _message.setJMSCorrelationIDAsBytes(correlationID);
+ }
+
+ /**
+ * Set delivery mode
+ * @param deliveryMode The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSDeliveryMode(final int deliveryMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSDeliveryMode(" + deliveryMode + ")");
+ }
+
+ _message.setJMSDeliveryMode(deliveryMode);
+ }
+
+ /**
+ * Set destination
+ * @param destination The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSDestination(final Destination destination) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSDestination(" + destination + ")");
+ }
+
+ _message.setJMSDestination(destination);
+ }
+
+ /**
+ * Set expiration
+ * @param expiration The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSExpiration(final long expiration) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSExpiration(" + expiration + ")");
+ }
+
+ _message.setJMSExpiration(expiration);
+ }
+
+ /**
+ * Set message id
+ * @param id The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSMessageID(final String id) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSMessageID(" + id + ")");
+ }
+
+ _message.setJMSMessageID(id);
+ }
+
+ /**
+ * Set priority
+ * @param priority The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSPriority(final int priority) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSPriority(" + priority + ")");
+ }
+
+ _message.setJMSPriority(priority);
+ }
+
+ /**
+ * Set redelivered status
+ * @param redelivered The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSRedelivered(final boolean redelivered) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSRedelivered(" + redelivered + ")");
+ }
+
+ _message.setJMSRedelivered(redelivered);
+ }
+
+ /**
+ * Set reply to
+ * @param replyTo The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSReplyTo(final Destination replyTo) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSReplyTo(" + replyTo + ")");
+ }
+
+ _message.setJMSReplyTo(replyTo);
+ }
+
+ /**
+ * Set timestamp
+ * @param timestamp The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSTimestamp(final long timestamp) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSTimestamp(" + timestamp + ")");
+ }
+
+ _message.setJMSTimestamp(timestamp);
+ }
+
+ /**
+ * Set type
+ * @param type The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSType(final String type) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSType(" + type + ")");
+ }
+
+ _message.setJMSType(type);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setLongProperty(final String name, final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLongProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setLongProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObjectProperty(final String name, final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObjectProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setObjectProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setShortProperty(final String name, final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setShortProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setShortProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setStringProperty(final String name, final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setStringProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setStringProperty(name, value);
+ }
+
+ /**
+ * Return the hash code
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ return _message.hashCode();
+ }
+
+ /**
+ * Check for equality
+ * @param object The other object
+ * @return True / false
+ */
+ @Override
+ public boolean equals(final Object object)
+ {
+ if (object != null && object instanceof QpidRAMessage)
+ {
+ return _message.equals(((QpidRAMessage)object)._message);
+ }
+ else
+ {
+ return _message.equals(object);
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java
new file mode 100644
index 0000000000..aa0e6adb0e
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java
@@ -0,0 +1,353 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message consumer
+ *
+ */
+public class QpidRAMessageConsumer implements MessageConsumer
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageConsumer.class);
+
+ /** The wrapped message consumer */
+ protected MessageConsumer _consumer;
+ /** The closed flag */
+ private AtomicBoolean _closed = new AtomicBoolean();
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param consumer the consumer
+ * @param session the session
+ */
+ public QpidRAMessageConsumer(final MessageConsumer consumer, final QpidRASessionImpl session)
+ {
+ this._consumer = consumer;
+ this._session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAMessageConsumer " + this +
+ " consumer=" +
+ Util.asString(consumer) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+ try
+ {
+ closeConsumer();
+ }
+ finally
+ {
+ _session.removeConsumer(this);
+ }
+ }
+
+ /**
+ * Check state
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkState() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("checkState()");
+ }
+ _session.checkState();
+ }
+
+ /**
+ * Get message listener
+ * @return The listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageListener getMessageListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageListener()");
+ }
+
+ checkState();
+ _session.checkStrict();
+ return _consumer.getMessageListener();
+ }
+
+ /**
+ * Set message listener
+ * @param listener The listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setMessageListener(final MessageListener listener) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ checkState();
+ _session.checkStrict();
+ if (listener == null)
+ {
+ _consumer.setMessageListener(null);
+ }
+ else
+ {
+ _consumer.setMessageListener(wrapMessageListener(listener));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Get message selector
+ * @return The selector
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getMessageSelector() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ checkState();
+ return _consumer.getMessageSelector();
+ }
+
+ /**
+ * Receive
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receive() throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receive " + this);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receive() : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Receive
+ * @param timeout The timeout value
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receive(final long timeout) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receive " + this + " timeout=" + timeout);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receive(timeout) : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Receive
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receiveNoWait() throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receiveNoWait " + this);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receiveNoWait() : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Close consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeConsumer() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("closeConsumer()");
+ }
+
+ if (!_closed.getAndSet(true))
+ {
+ _consumer.close();
+ }
+ }
+
+ /**
+ * Wrap message
+ * @param message The message to be wrapped
+ * @return The wrapped message
+ */
+ Message wrapMessage(final Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("wrapMessage(" + Util.asString(message) + ")");
+ }
+
+ if (message instanceof BytesMessage)
+ {
+ return new QpidRABytesMessage((BytesMessage)message, _session);
+ }
+ else if (message instanceof MapMessage)
+ {
+ return new QpidRAMapMessage((MapMessage)message, _session);
+ }
+ else if (message instanceof ObjectMessage)
+ {
+ return new QpidRAObjectMessage((ObjectMessage)message, _session);
+ }
+ else if (message instanceof StreamMessage)
+ {
+ return new QpidRAStreamMessage((StreamMessage)message, _session);
+ }
+ else if (message instanceof TextMessage)
+ {
+ return new QpidRATextMessage((TextMessage)message, _session);
+ }
+ return new QpidRAMessage(message, _session);
+ }
+
+ /**
+ * Wrap message listener
+ * @param listener The listener to be wrapped
+ * @return The wrapped listener
+ */
+ MessageListener wrapMessageListener(final MessageListener listener)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ return new QpidRAMessageListener(listener, this);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java
new file mode 100644
index 0000000000..e272df818f
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message listener
+ */
+public class QpidRAMessageListener implements MessageListener
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageListener.class);
+
+ /** The message listener */
+ private final MessageListener _listener;
+
+ /** The consumer */
+ private final QpidRAMessageConsumer _consumer;
+
+ /**
+ * Create a new wrapper
+ * @param listener the listener
+ * @param consumer the consumer
+ */
+ public QpidRAMessageListener(final MessageListener listener, final QpidRAMessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + listener + ", " + consumer + ")");
+ }
+
+ this._listener = listener;
+ this._consumer = consumer;
+ }
+
+ /**
+ * On message
+ * @param message The message
+ */
+ public void onMessage(Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onMessage(" + Util.asString(message) + ")");
+ }
+
+ message = _consumer.wrapMessage(message);
+ _listener.onMessage(message);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java
new file mode 100644
index 0000000000..ce0656e30d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java
@@ -0,0 +1,419 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAMessageProducer.
+ *
+ */
+public class QpidRAMessageProducer implements MessageProducer
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageProducer.class);
+
+ /** The wrapped message producer */
+ protected MessageProducer _producer;
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRAMessageProducer(final MessageProducer producer, final QpidRASessionImpl session)
+ {
+ this._producer = producer;
+ this._session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAMessageProducer " + this +
+ " producer=" +
+ Util.asString(producer) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+ try
+ {
+ closeProducer();
+ }
+ finally
+ {
+ _session.removeProducer(this);
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Destination destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ _producer.send(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Destination destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ _producer.send(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Message message, final int deliveryMode, final int priority, final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ _producer.send(message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ _producer.send(message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Get the delivery mode
+ * @return The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getDeliveryMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDeliveryMode()");
+ }
+
+ return _producer.getDeliveryMode();
+ }
+
+ /**
+ * Get the destination
+ * @return The destination
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getDestination() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestination()");
+ }
+
+ return _producer.getDestination();
+ }
+
+ /**
+ * Disable message id
+ * @return True if disable
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getDisableMessageID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDisableMessageID()");
+ }
+
+ return _producer.getDisableMessageID();
+ }
+
+ /**
+ * Disable message timestamp
+ * @return True if disable
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getDisableMessageTimestamp() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDisableMessageTimestamp()");
+ }
+
+ return _producer.getDisableMessageTimestamp();
+ }
+
+ /**
+ * Get the priority
+ * @return The priority
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getPriority() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPriority()");
+ }
+
+ return _producer.getPriority();
+ }
+
+ /**
+ * Get the time to live
+ * @return The ttl
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getTimeToLive() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTimeToLive()");
+ }
+
+ return _producer.getTimeToLive();
+ }
+
+ /**
+ * Set the delivery mode
+ * @param deliveryMode The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDeliveryMode(final int deliveryMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDeliveryMode(" + deliveryMode + ")");
+ }
+
+ _producer.setDeliveryMode(deliveryMode);
+ }
+
+ /**
+ * Set disable message id
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDisableMessageID(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDisableMessageID(" + value + ")");
+ }
+
+ _producer.setDisableMessageID(value);
+ }
+
+ /**
+ * Set disable message timestamp
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDisableMessageTimestamp(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDisableMessageTimestamp(" + value + ")");
+ }
+
+ _producer.setDisableMessageTimestamp(value);
+ }
+
+ /**
+ * Set the priority
+ * @param defaultPriority The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setPriority(final int defaultPriority) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPriority(" + defaultPriority + ")");
+ }
+
+ _producer.setPriority(defaultPriority);
+ }
+
+ /**
+ * Set the ttl
+ * @param timeToLive The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setTimeToLive(final long timeToLive) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTimeToLive(" + timeToLive + ")");
+ }
+
+ _producer.setTimeToLive(timeToLive);
+ }
+
+ /**
+ * Check state
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkState() throws JMSException
+ {
+ _session.checkState();
+ }
+
+ /**
+ * Close producer
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeProducer() throws JMSException
+ {
+ _producer.close();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java
new file mode 100644
index 0000000000..0ad7d089c3
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ManagedConnectionMetaData;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Managed connection meta data
+ *
+ */
+public class QpidRAMetaData implements ManagedConnectionMetaData
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMetaData.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _mc;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ */
+ public QpidRAMetaData(final QpidRAManagedConnection mc)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ")");
+ }
+
+ this._mc = mc;
+ }
+
+ /**
+ * Get the EIS product name
+ * @return The name
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getEISProductName() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEISProductName()");
+ }
+
+ return "Qpid";
+ }
+
+ /**
+ * Get the EIS product version
+ * @return The version
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getEISProductVersion() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEISProductVersion()");
+ }
+
+ return "2.0";
+ }
+
+ /**
+ * Get the user name
+ * @return The user name
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getUserName() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _mc.getUserName();
+ }
+
+ /**
+ * Get the maximum number of connections -- RETURNS 0
+ * @return The number
+ * @exception ResourceException Thrown if operation fails
+ */
+ public int getMaxConnections() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMaxConnections()");
+ }
+
+ return 0;
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java
new file mode 100644
index 0000000000..926319bb85
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAObjectMessage extends QpidRAMessage implements ObjectMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAObjectMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAObjectMessage(final ObjectMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the object
+ * @return The object
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Serializable getObject() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObject()");
+ }
+
+ return ((ObjectMessage)_message).getObject();
+ }
+
+ /**
+ * Set the object
+ * @param object The object
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObject(final Serializable object) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObject(" + object + ")");
+ }
+
+ ((ObjectMessage)_message).setObject(object);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java
new file mode 100644
index 0000000000..21f7d2574f
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java
@@ -0,0 +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.ra;
+
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The RA default properties - these are set in the ra.xml file
+ *
+ */
+public class QpidRAProperties extends ConnectionFactoryProperties implements Serializable
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = -4823893873707374791L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAProperties.class);
+
+ private static final int DEFAULT_SETUP_ATTEMPTS = 10;
+
+ private static final long DEFAULT_SETUP_INTERVAL = 2 * 1000;
+
+ private int _setupAttempts = DEFAULT_SETUP_ATTEMPTS;
+
+ private long _setupInterval = DEFAULT_SETUP_INTERVAL;
+
+ /** Use Local TX instead of XA */
+ private Boolean _localTx = false;
+
+ /** Class used to locate the Transaction Manager. */
+ private String _transactionManagerLocatorClass ;
+
+ /** Method used to locate the TM */
+ private String _transactionManagerLocatorMethod ;
+
+
+ /**
+ * Constructor
+ */
+ public QpidRAProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the use XA flag
+ * @return The value
+ */
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _localTx;
+ }
+
+ /**
+ * Set the use XA flag
+ * @param localTx The value
+ */
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ this._localTx = localTx;
+ }
+
+ public void setTransactionManagerLocatorClass(final String transactionManagerLocatorClass)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorClass(" + transactionManagerLocatorClass + ")");
+ }
+
+ this._transactionManagerLocatorClass = transactionManagerLocatorClass;
+ }
+
+ public String getTransactionManagerLocatorClass()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorClass()");
+ }
+
+ return _transactionManagerLocatorClass;
+ }
+
+ public String getTransactionManagerLocatorMethod()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorMethod()");
+ }
+
+ return _transactionManagerLocatorMethod;
+ }
+
+ public void setTransactionManagerLocatorMethod(final String transactionManagerLocatorMethod)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorMethod(" + transactionManagerLocatorMethod + ")");
+ }
+
+ this._transactionManagerLocatorMethod = transactionManagerLocatorMethod;
+ }
+
+ public int getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+
+ return _setupAttempts;
+ }
+
+ public void setSetupAttempts(int setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+
+ this._setupAttempts = setupAttempts;
+ }
+
+ public long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+
+ return _setupInterval;
+ }
+
+ public void setSetupInterval(long setupInterval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + setupInterval + ")");
+ }
+
+ this._setupInterval = setupInterval;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "QpidRAProperties[localTx=" + _localTx +
+ ", transactionManagerLocatorClass=" + _transactionManagerLocatorClass +
+ ", transactionManagerLocatorMethod=" + _transactionManagerLocatorMethod +
+ ", setupAttempts=" + _setupAttempts +
+ ", setupInterval=" + _setupInterval + "]";
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java
new file mode 100644
index 0000000000..bcd2d3b63c
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java
@@ -0,0 +1,139 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAQueueBrowser.
+ *
+ */
+public class QpidRAQueueBrowser implements QueueBrowser
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueBrowser.class);
+
+ /** The wrapped queue browser */
+ protected QueueBrowser _browser;
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /** The closed flag */
+ private AtomicBoolean _isClosed = new AtomicBoolean();
+
+ /**
+ * Create a new wrapper
+ * @param browser the browser
+ * @param session the session
+ */
+ public QpidRAQueueBrowser(final QueueBrowser browser, final QpidRASessionImpl session)
+ {
+ _browser = browser;
+ _session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAQueueBrowser " + this +
+ " browser=" +
+ Util.asString(browser) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+
+ if (!_isClosed.getAndSet(true))
+ {
+ try
+ {
+ _browser.close();
+ }
+ finally
+ {
+ _session.removeQueueBrowser(this);
+ }
+ }
+ }
+
+ /**
+ * Get the queue associated with this browser.
+ * @return the associated queue.
+ */
+ public Queue getQueue()
+ throws JMSException
+ {
+ return _browser.getQueue();
+ }
+
+ /**
+ * Get the message selector associated with this browser.
+ * @return the associated message selector.
+ */
+ public String getMessageSelector()
+ throws JMSException
+ {
+ return _browser.getMessageSelector();
+ }
+
+ /**
+ * Get an enumeration for the current browser.
+ * @return The enumeration.
+ */
+ public Enumeration getEnumeration()
+ throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEnumeration " + this + " browser=" + Util.asString(_browser));
+ }
+
+ _session.lock();
+ try
+ {
+ _session.checkState();
+ return _browser.getEnumeration();
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java
new file mode 100644
index 0000000000..ad1f7fc43b
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java
@@ -0,0 +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.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a queue receiver
+ *
+ */
+public class QpidRAQueueReceiver extends QpidRAMessageConsumer implements QueueReceiver
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueReceiver.class);
+
+ /**
+ * Create a new wrapper
+ * @param consumer the queue receiver
+ * @param session the session
+ */
+ public QpidRAQueueReceiver(final QueueReceiver consumer, final QpidRASessionImpl session)
+ {
+ super(consumer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(consumer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get queue
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue getQueue() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueue()");
+ }
+
+ checkState();
+ return ((QueueReceiver)_consumer).getQueue();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java
new file mode 100644
index 0000000000..7a123618be
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAQueueSender.
+ *
+ */
+public class QpidRAQueueSender extends QpidRAMessageProducer implements QueueSender
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueSender.class);
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRAQueueSender(final QueueSender producer, final QpidRASessionImpl session)
+ {
+ super(producer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(producer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get queue
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue getQueue() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueue()");
+ }
+
+ return ((QueueSender)_producer).getQueue();
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Queue destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+ _producer.send(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Queue destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+ _producer.send(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java
index 834b17430b..081677ca4b 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java
@@ -18,23 +18,16 @@
* under the License.
*
*/
-package org.apache.qpid.test.unit.ack;
-import org.apache.qpid.jms.Session;
+package org.apache.qpid.ra;
-import javax.jms.Message;
-import javax.jms.Queue;
+import javax.jms.JMSException;
-public class FailoverBeforeConsumingRecoverTest extends RecoverTest
+public interface QpidRASession
{
+ public void setQpidSessionFactory(QpidRASessionFactory sf);
- @Override
- protected void initTest() throws Exception
- {
- super.initTest();
- failBroker(getFailingPort());
+ public void start() throws JMSException;
- Queue queue = _consumerSession.createQueue(getTestQueueName());
- sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT);
- }
+ public void close() throws JMSException;
}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java
new file mode 100644
index 0000000000..cf28d5bba1
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.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.ra;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TopicConnection;
+import javax.jms.XAConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XATopicConnection;
+
+/**
+ * A joint interface for all connection types
+ *
+ */
+public interface QpidRASessionFactory extends Connection, TopicConnection, QueueConnection, XAConnection,
+ XATopicConnection, XAQueueConnection
+{
+ /** Error message for strict behaviour */
+ String ISE = "This method is not applicable inside the application server. See the J2EE spec, e.g. J2EE1.4 Section 6.6";
+
+ /**
+ * Add a temporary queue
+ * @param temp The temporary queue
+ */
+ void addTemporaryQueue(TemporaryQueue temp);
+
+ /**
+ * Add a temporary topic
+ * @param temp The temporary topic
+ */
+ void addTemporaryTopic(TemporaryTopic temp);
+
+ /**
+ * Notification that a session is closed
+ * @param session The session
+ * @throws JMSException for any error
+ */
+ void closeSession(QpidRASessionImpl session) throws JMSException;
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
new file mode 100644
index 0000000000..e2bc2d2008
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
@@ -0,0 +1,911 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jms.ConnectionConsumer;
+import javax.jms.ConnectionMetaData;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueSession;
+import javax.jms.ServerSessionPool;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.Topic;
+import javax.jms.TopicSession;
+import javax.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.naming.Reference;
+import javax.resource.Referenceable;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements the JMS Connection API and produces {@link QpidRASessionImpl} objects.
+ *
+ */
+public class QpidRASessionFactoryImpl implements QpidRASessionFactory, Referenceable
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionFactoryImpl.class);
+
+ /** Are we closed? */
+ private boolean _closed = false;
+
+ /** The naming reference */
+ private Reference _reference;
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /** The client ID */
+ private String _clientID;
+
+ /** The connection type */
+ private final int _type;
+
+ /** Whether we are started */
+ private boolean _started = false;
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection manager */
+ private ConnectionManager _cm;
+
+ /** The sessions */
+ private final Set<QpidRASession> _sessions = new HashSet<QpidRASession>();
+
+ /** The temporary queues */
+ private final Set<TemporaryQueue> _tempQueues = new HashSet<TemporaryQueue>();
+
+ /** The temporary topics */
+ private final Set<TemporaryTopic> _tempTopics = new HashSet<TemporaryTopic>();
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cm The connection manager
+ * @param type The connection type
+ */
+ public QpidRASessionFactoryImpl(final QpidRAManagedConnectionFactory mcf,
+ final ConnectionManager cm,
+ final int type)
+ {
+ this._mcf = mcf;
+
+ if (cm == null)
+ {
+ this._cm = new QpidRAConnectionManager();
+ }
+ else
+ {
+ this._cm = cm;
+ }
+
+ this._type = type;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cm + ", " + type);
+ }
+ }
+
+ /**
+ * Set the naming reference
+ * @param reference The reference
+ */
+ public void setReference(final Reference reference)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setReference(" + reference + ")");
+ }
+
+ this._reference = reference;
+ }
+
+ /**
+ * Get the naming reference
+ * @return The reference
+ */
+ public Reference getReference()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getReference()");
+ }
+
+ return _reference;
+ }
+
+ /**
+ * Set the user name
+ * @param name The user name
+ */
+ public void setUserName(final String name)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + name + ")");
+ }
+
+ _userName = name;
+ }
+
+ /**
+ * Set the password
+ * @param password The password
+ */
+ public void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get the client ID
+ * @return The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getClientID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ checkClosed();
+
+ if (_clientID == null)
+ {
+ try
+ {
+ return _mcf.getDefaultAMQConnectionFactory().getConnectionURL().getClientName() ;
+ }
+ catch (final ResourceException re)
+ {
+ final JMSException jmse = new JMSException("Unexpected exception obtaining resource") ;
+ jmse.initCause(re) ;
+ throw jmse ;
+ }
+ }
+
+ return _clientID;
+ }
+
+ /**
+ * Set the client ID -- throws IllegalStateException
+ * @param cID The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setClientID(final String cID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + cID + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a queue session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession createQueueSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.TOPIC_CONNECTION || _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a queue session from a topic connection");
+ }
+
+ return (QueueSession)allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA queue session
+ * @return The XA queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XAQueueSession createXAQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.TOPIC_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XAQueueSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Queue queue,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + queue +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a topic session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession createTopicSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.QUEUE_CONNECTION || _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (TopicSession) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA topic session
+ * @return The XA topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XATopicSession createXATopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XATopicSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Topic topic,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a durable connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param subscriptionName The subscription name
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createDurableConnectionConsumer(final Topic topic,
+ final String subscriptionName,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ subscriptionName +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param name The name
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final String name,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ name +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+ return (Session) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA session
+ * @return The XA session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XASession createXASession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXASession()");
+ }
+
+ checkClosed();
+ return (XASession) allocateConnection(_type);
+ }
+
+ /**
+ * Get the connection metadata
+ * @return The connection metadata
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionMetaData getMetaData() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ checkClosed();
+ return _mcf.getMetaData();
+ }
+
+ /**
+ * Get the exception listener -- throws IllegalStateException
+ * @return The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ExceptionListener getExceptionListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getExceptionListener()");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Set the exception listener -- throws IllegalStateException
+ * @param listener The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setExceptionListener(final ExceptionListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setExceptionListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ checkClosed();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start() " + this);
+ }
+
+ synchronized (_sessions)
+ {
+ if (_started)
+ {
+ return;
+ }
+ _started = true;
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ session.start();
+ }
+ }
+ }
+
+ /**
+ * Stop -- throws IllegalStateException
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop() " + this);
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close() " + this);
+ }
+
+ if (_closed)
+ {
+ return;
+ }
+
+ _closed = true;
+
+ synchronized (_sessions)
+ {
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ try
+ {
+ session.closeSession();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing session", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_tempQueues)
+ {
+ for (Iterator<TemporaryQueue> i = _tempQueues.iterator(); i.hasNext();)
+ {
+ TemporaryQueue temp = (TemporaryQueue)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Closing temporary queue " + temp + " for " + this);
+ }
+ temp.delete();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error deleting temporary queue", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_tempTopics)
+ {
+ for (Iterator<TemporaryTopic> i = _tempTopics.iterator(); i.hasNext();)
+ {
+ TemporaryTopic temp = (TemporaryTopic)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Closing temporary topic " + temp + " for " + this);
+ }
+ temp.delete();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error deleting temporary queue", t);
+ }
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Close session
+ * @param session The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void closeSession(final QpidRASessionImpl session) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("closeSession(" + session + ")");
+ }
+
+ synchronized (_sessions)
+ {
+ _sessions.remove(session);
+ }
+ }
+
+ /**
+ * Add temporary queue
+ * @param temp The temporary queue
+ */
+ public void addTemporaryQueue(final TemporaryQueue temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryQueue(" + temp + ")");
+ }
+
+ synchronized (_tempQueues)
+ {
+ _tempQueues.add(temp);
+ }
+ }
+
+ /**
+ * Add temporary topic
+ * @param temp The temporary topic
+ */
+ public void addTemporaryTopic(final TemporaryTopic temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryTopic(" + temp + ")");
+ }
+
+ synchronized (_tempTopics)
+ {
+ _tempTopics.add(temp);
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + sessionType + ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_sessions.isEmpty() == false)
+ {
+ throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(this);
+
+ if (_started)
+ {
+ session.start();
+ }
+
+ _sessions.add(session);
+
+ return session;
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ session.close();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ if (t instanceof Exception)
+ {
+ throw (Exception)t;
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected error: ", t);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _log.error("Could not create session", e);
+
+ JMSException je = new JMSException("Could not create a session: " + e.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final boolean transacted, int acknowledgeMode, final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + transacted +
+ ", " +
+ acknowledgeMode +
+ ", " +
+ sessionType +
+ ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_sessions.isEmpty() == false)
+ {
+ throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
+ }
+
+ if (transacted)
+ {
+ acknowledgeMode = Session.SESSION_TRANSACTED;
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(transacted,
+ acknowledgeMode,
+ sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(this);
+
+ if (_started)
+ {
+ session.start();
+ }
+
+ _sessions.add(session);
+
+ return session;
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ session.close();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ if (t instanceof Exception)
+ {
+ throw (Exception)t;
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected error: ", t);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _log.error("Could not create session", e);
+
+ JMSException je = new JMSException("Could not create a session: " + e.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Check if we are closed
+ * @exception IllegalStateException Thrown if closed
+ */
+ protected void checkClosed() throws IllegalStateException
+ {
+ if (_closed)
+ {
+ throw new IllegalStateException("The connection is closed");
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
new file mode 100644
index 0000000000..a270253c13
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
@@ -0,0 +1,1732 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import javax.jms.TransactionInProgressException;
+import javax.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ManagedConnection;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A joint interface for JMS sessions
+ *
+ */
+public class QpidRASessionImpl implements Session, QueueSession, TopicSession, XASession, XAQueueSession, XATopicSession, QpidRASession
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionImpl.class);
+
+ /** The managed connection */
+ private volatile QpidRAManagedConnection _mc;
+ /** The locked managed connection */
+ private QpidRAManagedConnection _lockedMC;
+
+ /** The connection request info */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The session factory */
+ private QpidRASessionFactory _sf;
+
+ /** The message consumers */
+ private final Set<MessageConsumer> _consumers;
+
+ /** The message producers */
+ private final Set<MessageProducer> _producers;
+
+ /** The queue browsers */
+ private final Set<QueueBrowser> _browsers;
+
+ /** Are we started */
+ private AtomicBoolean _started = new AtomicBoolean(false) ;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ * @param cri The connection request info
+ */
+ public QpidRASessionImpl(final QpidRAManagedConnection mc, final QpidRAConnectionRequestInfo cri)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ", " + cri + ")");
+ }
+
+ this._mc = mc;
+ this._cri = cri;
+ _sf = null;
+ _consumers = new HashSet<MessageConsumer>();
+ _producers = new HashSet<MessageProducer>();
+ _browsers = new HashSet<QueueBrowser>();
+ }
+
+ /**
+ * Set the session factory
+ * @param sf The session factory
+ */
+ public void setQpidSessionFactory(final QpidRASessionFactory sf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setQpidSessionFactory(" + sf + ")");
+ }
+
+ _started.set(false) ;
+ this._sf = sf;
+ }
+
+ /**
+ * Lock
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ protected void lock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.tryLock();
+ _lockedMC = mc ;
+ }
+ else
+ {
+ throw new IllegalStateException("Connection is not associated with a managed connection. " + this);
+ }
+ }
+
+ /**
+ * Unlock
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lockedMC != null)
+ {
+ try
+ {
+ _lockedMC.unlock();
+ }
+ finally
+ {
+ _lockedMC = null ;
+ }
+ }
+
+ // We recreate the lock when returned to the pool
+ // so missing the unlock after disassociation is not important
+ }
+
+ /**
+ * Create a bytes message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public BytesMessage createBytesMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBytesMessage" + Util.asString(session));
+ }
+
+ return session.createBytesMessage();
+ }
+
+ /**
+ * Create a map message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MapMessage createMapMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMapMessage" + Util.asString(session));
+ }
+
+ return session.createMapMessage();
+ }
+
+ /**
+ * Create a message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message createMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMessage" + Util.asString(session));
+ }
+
+ return session.createMessage();
+ }
+
+ /**
+ * Create an object message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage" + Util.asString(session));
+ }
+
+ return session.createObjectMessage();
+ }
+
+ /**
+ * Create an object message
+ * @param object The object
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage(final Serializable object) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage(" + object + ")" + Util.asString(session));
+ }
+
+ return session.createObjectMessage(object);
+ }
+
+ /**
+ * Create a stream message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public StreamMessage createStreamMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createStreamMessage" + Util.asString(session));
+ }
+
+ return session.createStreamMessage();
+ }
+
+ /**
+ * Create a text message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage" + Util.asString(session));
+ }
+
+ return session.createTextMessage();
+ }
+
+ /**
+ * Create a text message
+ * @param string The text
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage(final String string) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage(" + string + ")" + Util.asString(session));
+ }
+
+ return session.createTextMessage(string);
+ }
+
+ /**
+ * Get transacted
+ * @return True if transacted; otherwise false
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getTransacted() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransacted()");
+ }
+
+ getSessionInternal();
+ return _cri.isTransacted();
+ }
+
+ /**
+ * Get the message listener -- throws IllegalStateException
+ * @return The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageListener getMessageListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageListener()");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Set the message listener -- Throws IllegalStateException
+ * @param listener The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setMessageListener(final MessageListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMessageListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Always throws an Error.
+ * @exception Error Method not allowed.
+ */
+ public void run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ throw new Error("Method not allowed");
+ }
+
+ /**
+ * Closes the session. Sends a ConnectionEvent.CONNECTION_CLOSED to the
+ * managed connection.
+ * @exception JMSException Failed to close session.
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close()");
+ }
+
+ _sf.closeSession(this);
+ closeSession();
+ }
+
+ /**
+ * Commit
+ * @exception JMSException Failed to close session.
+ */
+ public void commit() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Commit session " + this);
+ }
+
+ session.commit();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Rollback
+ * @exception JMSException Failed to close session.
+ */
+ public void rollback() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Rollback session " + this);
+ }
+
+ session.rollback();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Recover
+ * @exception JMSException Failed to close session.
+ */
+ public void recover() throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted())
+ {
+ throw new IllegalStateException("Session is transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Recover session " + this);
+ }
+
+ session.recover();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic
+ * @param topicName The topic name
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic createTopic(final String topicName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create topic for javax.jms.QueueSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopic " + Util.asString(session) + " topicName=" + topicName);
+ }
+
+ Topic result = session.createTopic(topicName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTopic " + Util.asString(session) + " topic=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic, final String messageSelector, final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a durable topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic, final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) + " topic=" + topic + " name=" + name);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic,
+ final String name,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " name=" +
+ name +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic publisher
+ * @param topic The topic
+ * @return The publisher
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicPublisher createPublisher(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createPublisher " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicPublisher result = session.createPublisher(topic);
+ result = new QpidRATopicPublisher(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdPublisher " + Util.asString(session) + " publisher=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary topic
+ * @return The temporary topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryTopic createTemporaryTopic() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary topic for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryTopic " + Util.asString(session));
+ }
+
+ TemporaryTopic temp = session.createTemporaryTopic();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryTopic " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryTopic(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Unsubscribe
+ * @param name The name
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void unsubscribe(final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot unsubscribe for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unsubscribe " + Util.asString(session) + " name=" + name);
+ }
+
+ session.unsubscribe(name);
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueBrowser result = session.createBrowser(queue);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue, final String messageSelector) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueBrowser result = session.createBrowser(queue, messageSelector);
+ result = new QpidRAQueueBrowser(result, this);
+ addQueueBrowser(result) ;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue
+ * @param queueName The queue name
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue createQueue(final String queueName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser or javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueue " + Util.asString(session) + " queueName=" + queueName);
+ }
+
+ Queue result = session.createQueue(queueName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdQueue " + Util.asString(session) + " queue=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueReceiver result = session.createReceiver(queue);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @param messageSelector
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueReceiver result = session.createReceiver(queue, messageSelector);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue sender
+ * @param queue The queue
+ * @return The queue sender
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSender createSender(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSender " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueSender result = session.createSender(queue);
+ result = new QpidRAQueueSender(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSender " + Util.asString(session) + " sender=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary queue
+ * @return The temporary queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary queue for javax.jms.TopicSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryQueue " + Util.asString(session));
+ }
+
+ TemporaryQueue temp = session.createTemporaryQueue();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryQueue " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryQueue(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageConsumer result = session.createConsumer(destination);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector, noLocal);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message producer
+ * @param destination The destination
+ * @return The message producer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageProducer createProducer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createProducer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageProducer result = session.createProducer(destination);
+ result = new QpidRAMessageProducer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdProducer " + Util.asString(session) + " producer=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getAcknowledgeMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ getSessionInternal();
+ return _cri.getAcknowledgeMode();
+ }
+
+ /**
+ * Get the XA resource
+ * @return The XA resource
+ * @exception IllegalStateException If non XA connection
+ */
+ public XAResource getXAResource()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ return null;
+ }
+
+ try
+ {
+ lock();
+
+ return getXAResourceInternal();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the session
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session getSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession getQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueueSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession getTopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopicSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Set the managed connection
+ * @param managedConnection The managed connection
+ */
+ void setManagedConnection(final QpidRAManagedConnection managedConnection)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setManagedConnection(" + managedConnection + ")");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.removeHandle(this);
+ }
+
+ this._mc = managedConnection;
+ }
+
+ /** for tests only */
+ public ManagedConnection getManagedConnection()
+ {
+ return _mc;
+ }
+
+ /**
+ * Destroy
+ */
+ void destroy()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ _mc = null;
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _started.set(true) ;
+ mc.start();
+ }
+ }
+
+ /**
+ * Stop
+ * @exception JMSException Thrown if an error occurs
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.stop();
+ _started.set(false) ;
+ }
+ }
+
+ /**
+ * Check strict
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkStrict() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("checkStrict()");
+ }
+
+ if (_mc != null)
+ {
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+ }
+
+ /**
+ * Close session
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeSession() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _log.trace("Closing session");
+
+ try
+ {
+ mc.stop();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error stopping managed connection", t);
+ }
+
+ synchronized (_consumers)
+ {
+ for (Iterator<MessageConsumer> i = _consumers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageConsumer consumer = (QpidRAMessageConsumer)i.next();
+ try
+ {
+ consumer.closeConsumer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing consumer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_producers)
+ {
+ for (Iterator<MessageProducer> i = _producers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageProducer producer = (QpidRAMessageProducer)i.next();
+ try
+ {
+ producer.closeProducer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing producer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_browsers)
+ {
+ for (Iterator<QueueBrowser> i = _browsers.iterator(); i.hasNext();)
+ {
+ QpidRAQueueBrowser browser = (QpidRAQueueBrowser)i.next();
+ try
+ {
+ browser.close();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing browser", t);
+ }
+ i.remove();
+ }
+ }
+
+ mc.removeHandle(this);
+ ConnectionEvent ev = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_CLOSED);
+ ev.setConnectionHandle(this);
+ mc.sendEvent(ev);
+ this._mc = null;
+ }
+ }
+
+ /**
+ * Add consumer
+ * @param consumer The consumer
+ */
+ void addConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.add(consumer);
+ }
+ }
+
+ /**
+ * Remove consumer
+ * @param consumer The consumer
+ */
+ void removeConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.remove(consumer);
+ }
+ }
+
+ /**
+ * Add producer
+ * @param producer The producer
+ */
+ void addProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.add(producer);
+ }
+ }
+
+ /**
+ * Remove producer
+ * @param producer The producer
+ */
+ void removeProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.remove(producer);
+ }
+ }
+
+ /**
+ * Add queue browser
+ * @param browser The queue browser
+ */
+ void addQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.add(browser);
+ }
+ }
+
+ /**
+ * Remove queue browser
+ * @param browser The queue browser
+ */
+ void removeQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.remove(browser);
+ }
+ }
+
+ /**
+ * Get the session and ensure that it is open
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ Session getSessionInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ Session session = mc.getSession();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionInternal " + Util.asString(session) + " for " + this);
+ }
+
+ return session;
+ }
+
+ /**
+ * Get the XA resource and ensure that it is open
+ * @return The XA Resource
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ XAResource getXAResourceInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ try
+ {
+ XAResource xares = mc.getXAResource();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResourceInternal " + xares + " for " + this);
+ }
+
+ return xares;
+ }
+ catch (ResourceException e)
+ {
+ JMSException jmse = new JMSException("Unable to get XA Resource");
+ jmse.initCause(e);
+ throw jmse;
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ QueueSession getQueueSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof QueueSession))
+ {
+ throw new InvalidDestinationException("Attempting to use QueueSession methods on: " + this);
+ }
+ return (QueueSession)s;
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ TopicSession getTopicSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof TopicSession))
+ {
+ throw new InvalidDestinationException("Attempting to use TopicSession methods on: " + this);
+ }
+ return (TopicSession)s;
+ }
+
+ /**
+ * @throws SystemException
+ * @throws RollbackException
+ *
+ */
+ public void checkState() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.checkTransactionActive();
+ }
+ }
+
+ /**
+ * Has this session been started?
+ * @return true if started, false if stopped.
+ */
+ public boolean isStarted()
+ {
+ return _started.get();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java
new file mode 100644
index 0000000000..3c2bee33f2
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java
@@ -0,0 +1,415 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.jms.JMSException;
+import javax.jms.StreamMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAStreamMessage extends QpidRAMessage implements StreamMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAStreamMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAStreamMessage(final StreamMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean readBoolean() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBoolean()");
+ }
+
+ return ((StreamMessage)_message).readBoolean();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte readByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readByte()");
+ }
+
+ return ((StreamMessage)_message).readByte();
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ")");
+ }
+
+ return ((StreamMessage)_message).readBytes(value);
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char readChar() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readChar()");
+ }
+
+ return ((StreamMessage)_message).readChar();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double readDouble() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readDouble()");
+ }
+
+ return ((StreamMessage)_message).readDouble();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float readFloat() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readFloat()");
+ }
+
+ return ((StreamMessage)_message).readFloat();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readInt() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readInt()");
+ }
+
+ return ((StreamMessage)_message).readInt();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long readLong() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readLong()");
+ }
+
+ return ((StreamMessage)_message).readLong();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object readObject() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readObject()");
+ }
+
+ return ((StreamMessage)_message).readObject();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short readShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readShort()");
+ }
+
+ return ((StreamMessage)_message).readShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String readString() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readString()");
+ }
+
+ return ((StreamMessage)_message).readString();
+ }
+
+ /**
+ * Reset
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void reset() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("reset()");
+ }
+
+ ((StreamMessage)_message).reset();
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBoolean(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBoolean(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeBoolean(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeByte(final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeByte(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeByte(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((StreamMessage)_message).writeBytes(value, offset, length);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeBytes(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeChar(final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeChar(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeChar(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeDouble(final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeDouble(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeDouble(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeFloat(final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeFloat(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeFloat(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeInt(final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeInt(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeInt(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeLong(final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeLong(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeLong(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeObject(final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeObject(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeObject(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeShort(final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeShort(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeShort(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeString(final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeString(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeString(value);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java
new file mode 100644
index 0000000000..d74d006a7f
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRATextMessage extends QpidRAMessage implements TextMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATextMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRATextMessage(final TextMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get text
+ * @return The text
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getText() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getText()");
+ }
+
+ return ((TextMessage)_message).getText();
+ }
+
+ /**
+ * Set text
+ * @param string The text
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setText(final String string) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setText(" + string + ")");
+ }
+
+ ((TextMessage)_message).setText(string);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java
new file mode 100644
index 0000000000..b753690142
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRATopicPublisher.
+ *
+ */
+public class QpidRATopicPublisher extends QpidRAMessageProducer implements TopicPublisher
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATopicPublisher.class);
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRATopicPublisher(final TopicPublisher producer, final QpidRASessionImpl session)
+ {
+ super(producer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(producer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the topic
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic getTopic() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopic()");
+ }
+
+ return ((TopicPublisher)_producer).getTopic();
+ }
+
+ /**
+ * Publish message
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Message message, final int deliveryMode, final int priority, final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Topic destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Topic destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java
new file mode 100644
index 0000000000..e423f468e0
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java
@@ -0,0 +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.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a topic subscriber
+ *
+ */
+public class QpidRATopicSubscriber extends QpidRAMessageConsumer implements TopicSubscriber
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATopicSubscriber.class);
+
+ /**
+ * Create a new wrapper
+ * @param consumer the topic subscriber
+ * @param session the session
+ */
+ public QpidRATopicSubscriber(final TopicSubscriber consumer, final QpidRASessionImpl session)
+ {
+ super(consumer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(consumer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the no local value
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getNoLocal() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getNoLocal()");
+ }
+
+ checkState();
+ return ((TopicSubscriber)_consumer).getNoLocal();
+ }
+
+ /**
+ * Get the topic
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic getTopic() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopic()");
+ }
+
+ checkState();
+ return ((TopicSubscriber)_consumer).getTopic();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java
new file mode 100644
index 0000000000..22b39792b1
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAXAResource.
+ *
+ */
+public class QpidRAXAResource implements XAResource
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAXAResource.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _managedConnection;
+
+ /** The resource */
+ private final XAResource _xaResource;
+
+ /**
+ * Create a new QpidRAXAResource.
+ * @param managedConnection the managed connection
+ * @param xaResource the xa resource
+ */
+ public QpidRAXAResource(final QpidRAManagedConnection managedConnection, final XAResource xaResource)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + managedConnection + ", " + Util.asString(xaResource) + ")");
+ }
+
+ this._managedConnection = managedConnection;
+ this._xaResource = xaResource;
+ }
+
+ /**
+ * Start
+ * @param xid A global transaction identifier
+ * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
+ * @exception XAException An error has occurred
+ */
+ public void start(final Xid xid, final int flags) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start(" + xid + ", " + flags + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.start(xid, flags);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(true);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * End
+ * @param xid A global transaction identifier
+ * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND.
+ * @exception XAException An error has occurred
+ */
+ public void end(final Xid xid, final int flags) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("end(" + xid + ", " + flags + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.end(xid, flags);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(false);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * Prepare
+ * @param xid A global transaction identifier
+ * @return XA_RDONLY or XA_OK
+ * @exception XAException An error has occurred
+ */
+ public int prepare(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("prepare(" + xid + ")");
+ }
+
+ return _xaResource.prepare(xid);
+ }
+
+ /**
+ * Commit
+ * @param xid A global transaction identifier
+ * @param onePhase If true, the resource manager should use a one-phase commit protocol to commit the work done on behalf of xid.
+ * @exception XAException An error has occurred
+ */
+ public void commit(final Xid xid, final boolean onePhase) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("commit(" + xid + ", " + onePhase + ")");
+ }
+
+ _xaResource.commit(xid, onePhase);
+ }
+
+ /**
+ * Rollback
+ * @param xid A global transaction identifier
+ * @exception XAException An error has occurred
+ */
+ public void rollback(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("rollback(" + xid + ")");
+ }
+
+ _xaResource.rollback(xid);
+ }
+
+ /**
+ * Forget
+ * @param xid A global transaction identifier
+ * @exception XAException An error has occurred
+ */
+ public void forget(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("forget(" + xid + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.forget(xid);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(false);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * IsSameRM
+ * @param xaRes An XAResource object whose resource manager instance is to be compared with the resource manager instance of the target object.
+ * @return True if its the same RM instance; otherwise false.
+ * @exception XAException An error has occurred
+ */
+ public boolean isSameRM(final XAResource xaRes) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isSameRM(" + xaRes + ")");
+ }
+
+ return _xaResource.isSameRM(xaRes);
+ }
+
+ /**
+ * Recover
+ * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS
+ * @return Zero or more XIDs
+ * @exception XAException An error has occurred
+ */
+ public Xid[] recover(final int flag) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("recover(" + flag + ")");
+ }
+
+ return _xaResource.recover(flag);
+ }
+
+ /**
+ * Get the transaction timeout in seconds
+ * @return The transaction timeout
+ * @exception XAException An error has occurred
+ */
+ public int getTransactionTimeout() throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionTimeout()");
+ }
+
+ return _xaResource.getTransactionTimeout();
+ }
+
+ /**
+ * Set the transaction timeout
+ * @param seconds The number of seconds
+ * @return True if the transaction timeout value is set successfully; otherwise false.
+ * @exception XAException An error has occurred
+ */
+ public boolean setTransactionTimeout(final int seconds) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionTimeout(" + seconds + ")");
+ }
+
+ return _xaResource.setTransactionTimeout(seconds);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
new file mode 100644
index 0000000000..d56f520db4
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
@@ -0,0 +1,820 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Session;
+import javax.jms.XASession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.BootstrapContext;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterInternalException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.WorkManager;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.ra.inflow.QpidActivation;
+import org.apache.qpid.ra.inflow.QpidActivationSpec;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * The resource adapter for Qpid
+ *
+ */
+public class QpidResourceAdapter implements ResourceAdapter, Serializable
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2446231446818098726L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidResourceAdapter.class);
+
+ /**
+ * The bootstrap context
+ */
+ private BootstrapContext _ctx;
+
+ /**
+ * The resource adapter properties
+ */
+ private final QpidRAProperties _raProperties;
+
+ /**
+ * Have the factory been configured
+ */
+ private final AtomicBoolean _configured;
+
+ /**
+ * The activations by activation spec
+ */
+ private final Map<ActivationSpec, QpidActivation> _activations;
+
+ private AMQConnectionFactory _defaultAMQConnectionFactory;
+
+ private TransactionManager _tm;
+
+ /**
+ * Constructor
+ */
+ public QpidResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _raProperties = new QpidRAProperties();
+ _configured = new AtomicBoolean(false);
+ _activations = new ConcurrentHashMap<ActivationSpec, QpidActivation>();
+ }
+
+ public TransactionManager getTM()
+ {
+ return _tm;
+ }
+
+ /**
+ * Endpoint activation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void endpointActivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec) throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointActivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = new QpidActivation(this, endpointFactory, (QpidActivationSpec)spec);
+ _activations.put(spec, activation);
+ activation.start();
+ }
+
+ /**
+ * Endpoint deactivation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ */
+ public void endpointDeactivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointDeactivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = _activations.remove(spec);
+ if (activation != null)
+ {
+ activation.stop();
+ }
+ }
+
+ /**
+ * Get XA resources
+ *
+ * @param specs The activation specs
+ * @return The XA resources
+ * @throws ResourceException Thrown if an error occurs or unsupported
+ */
+ public XAResource[] getXAResources(final ActivationSpec[] specs) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResources(" + specs + ")");
+ }
+
+ return null;
+ }
+
+ /**
+ * Start
+ *
+ * @param ctx The bootstrap context
+ * @throws ResourceAdapterInternalException
+ * Thrown if an error occurs
+ */
+ public void start(final BootstrapContext ctx) throws ResourceAdapterInternalException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start(" + ctx + ")");
+ }
+
+ locateTM();
+
+ this._ctx = ctx;
+
+ _log.info("Qpid resource adapter started");
+ }
+
+ /**
+ * Stop
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ for (Map.Entry<ActivationSpec, QpidActivation> entry : _activations.entrySet())
+ {
+ try
+ {
+ entry.getValue().stop();
+ }
+ catch (Exception ignored)
+ {
+ _log.debug("Ignored", ignored);
+ }
+ }
+
+ _activations.clear();
+
+ _log.info("Qpid resource adapter stopped");
+ }
+
+ /**
+ * Get the user name
+ *
+ * @return The value
+ */
+ public String getDefaultUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _raProperties.getUserName();
+ }
+
+ /**
+ * Set the user name
+ *
+ * @param userName The value
+ */
+ public void setDefaultUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ _raProperties.setUserName(userName);
+ }
+
+ /**
+ * Get the password
+ *
+ * @return The value
+ */
+ public String getDefaultPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _raProperties.getPassword();
+ }
+
+ /**
+ * Set the password
+ *
+ * @param password The value
+ */
+ public void setDefaultPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ _raProperties.setPassword(password);
+ }
+
+ /**
+ * Get the client ID
+ *
+ * @return The value
+ */
+ public String getClientId()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ return _raProperties.getClientId();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param clientID The client id
+ */
+ public void setClientId(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+
+ _raProperties.setClientId(clientID);
+ }
+
+ /**
+ * Get the host
+ *
+ * @return The value
+ */
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+
+ return _raProperties.getHost();
+ }
+
+ /**
+ * Set the host
+ *
+ * @param host The host
+ */
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+
+ _raProperties.setHost(host);
+ }
+
+ /**
+ * Get the port
+ *
+ * @return The value
+ */
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+
+ return _raProperties.getPort();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param port The port
+ */
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+
+ _raProperties.setPort(port);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+
+ return _raProperties.getPath();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param path The path
+ */
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+
+ _raProperties.setPath(path);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getConnectionURL()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnectionURL()");
+ }
+
+ return _raProperties.getConnectionURL();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param connectionURL The connection url
+ */
+ public void setConnectionURL(final String connectionURL)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setConnectionURL(" + connectionURL + ")");
+ }
+
+ _raProperties.setConnectionURL(connectionURL);
+ }
+
+ /**
+ * Get the transaction manager locator class
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorClass()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorClass()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorClass();
+ }
+
+ /**
+ * Set the transaction manager locator class
+ *
+ * @param locator The transaction manager locator class
+ */
+ public void setTransactionManagerLocatorClass(final String locator)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorClass(" + locator + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorClass(locator);
+ }
+
+ /**
+ * Get the transaction manager locator method
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorMethod()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorMethod()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorMethod();
+ }
+
+ /**
+ * Set the transaction manager locator method
+ *
+ * @param method The transaction manager locator method
+ */
+ public void setTransactionManagerLocatorMethod(final String method)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorMethod(" + method + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorMethod(method);
+ }
+
+ /**
+ * Get the use XA flag
+ *
+ * @return The value
+ */
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _raProperties.getUseLocalTx();
+ }
+
+ /**
+ * Set the use XA flag
+ *
+ * @param localTx The value
+ */
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _raProperties.setUseLocalTx(localTx);
+ }
+
+ public Integer getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+ return _raProperties.getSetupAttempts();
+ }
+
+ public void setSetupAttempts(Integer setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+ _raProperties.setSetupAttempts(setupAttempts);
+ }
+
+ public Long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+ return _raProperties.getSetupInterval();
+ }
+
+ public void setSetupInterval(Long interval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + interval + ")");
+ }
+ _raProperties.setSetupInterval(interval);
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ public boolean equals(final Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (obj instanceof QpidResourceAdapter)
+ {
+ return _raProperties.equals(((QpidResourceAdapter)obj).getProperties());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ public int hashCode()
+ {
+ return _raProperties.hashCode();
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The manager
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ if (_ctx == null)
+ {
+ return null;
+ }
+
+ return _ctx.getWorkManager();
+ }
+
+ public XASession createXASession(final XAConnectionImpl connection)
+ throws Exception
+ {
+ final XASession result = connection.createXASession() ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+ return result ;
+ }
+
+ public Session createSession(final AMQConnection connection,
+ final int ackMode,
+ final boolean useLocalTx,
+ final Integer prefetchLow,
+ final Integer prefetchHigh) throws Exception
+ {
+ Session result;
+
+ if (prefetchLow == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode) ;
+ }
+ else if (prefetchHigh == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchLow) ;
+ }
+ else
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchHigh, prefetchLow) ;
+ }
+
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Get the resource adapter properties
+ *
+ * @return The properties
+ */
+ protected QpidRAProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _raProperties;
+ }
+
+ /**
+ * Setup the factory
+ */
+ protected void setup() throws QpidRAException
+ {
+ _defaultAMQConnectionFactory = createAMQConnectionFactory(_raProperties);
+ }
+
+
+ public AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ return _defaultAMQConnectionFactory;
+ }
+
+ public AMQConnectionFactory createAMQConnectionFactory(final ConnectionFactoryProperties overrideProperties)
+ throws QpidRAException
+ {
+ try
+ {
+ return createFactory(overrideProperties);
+ }
+ catch (final URLSyntaxException urlse)
+ {
+ throw new QpidRAException("Unexpected exception creating connection factory", urlse) ;
+ }
+ }
+
+ public Map<String, Object> overrideConnectionParameters(final Map<String, Object> connectionParams,
+ final Map<String, Object> overrideConnectionParams)
+ {
+ Map<String, Object> map = new HashMap<String, Object>();
+
+ if(connectionParams != null)
+ {
+ map.putAll(connectionParams);
+ }
+ if(overrideConnectionParams != null)
+ {
+ for (Map.Entry<String, Object> stringObjectEntry : overrideConnectionParams.entrySet())
+ {
+ map.put(stringObjectEntry.getKey(), stringObjectEntry.getValue());
+ }
+ }
+ return map;
+ }
+
+ private void locateTM()
+ {
+ if(_raProperties.getTransactionManagerLocatorClass() != null && _raProperties.getTransactionManagerLocatorMethod() != null)
+ {
+
+ String locatorClasses[] = _raProperties.getTransactionManagerLocatorClass().split(";");
+ String locatorMethods[] = _raProperties.getTransactionManagerLocatorMethod().split(";");
+
+ for (int i = 0 ; i < locatorClasses.length; i++)
+ {
+ _tm = Util.locateTM(locatorClasses[i], locatorMethods[i]);
+ if (_tm != null)
+ {
+ break;
+ }
+ }
+
+
+ }
+
+ if (_tm == null)
+ {
+ _log.warn("It wasn't possible to lookup a Transaction Manager through the configured properties TransactionManagerLocatorClass and TransactionManagerLocatorMethod");
+ _log.warn("Qpid Resource Adapter won't be able to set and verify transaction timeouts in certain cases.");
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("TM located = " + _tm);
+ }
+ }
+ }
+
+
+ private AMQConnectionFactory createFactory(final ConnectionFactoryProperties overrideProperties)
+ throws URLSyntaxException, QpidRAException
+ {
+ final String overrideURL = overrideProperties.getConnectionURL() ;
+ final String url = overrideURL != null ? overrideURL : _raProperties.getConnectionURL() ;
+
+ final String overrideClientID = overrideProperties.getClientId() ;
+ final String clientID = (overrideClientID != null ? overrideClientID : _raProperties.getClientId()) ;
+
+ final String overrideDefaultPassword = overrideProperties.getPassword() ;
+ final String defaultPassword = (overrideDefaultPassword != null ? overrideDefaultPassword : _raProperties.getPassword()) ;
+
+ final String overrideDefaultUsername = overrideProperties.getUserName() ;
+ final String defaultUsername = (overrideDefaultUsername != null ? overrideDefaultUsername : _raProperties.getUserName()) ;
+
+ final String overrideHost = overrideProperties.getHost() ;
+ final String host = (overrideHost != null ? overrideHost : _raProperties.getHost()) ;
+
+ final Integer overridePort = overrideProperties.getPort() ;
+ final Integer port = (overridePort != null ? overridePort : _raProperties.getPort()) ;
+
+ final String overridePath = overrideProperties.getPath() ;
+ final String path = (overridePath != null ? overridePath : _raProperties.getPath()) ;
+
+ final AMQConnectionFactory cf ;
+
+ if (url != null)
+ {
+ cf = new AMQConnectionFactory(url) ;
+
+ if (clientID != null)
+ {
+ cf.getConnectionURL().setClientName(clientID) ;
+ }
+ }
+ else
+ {
+ // create a URL to force the connection details
+ if ((host == null) || (port == null) || (path == null))
+ {
+ throw new QpidRAException("Configuration requires host/port/path if connectionURL is not specified") ;
+ }
+ final String username = (defaultUsername != null ? defaultUsername : "") ;
+ final String password = (defaultPassword != null ? defaultPassword : "") ;
+ final String client = (clientID != null ? clientID : "") ;
+
+ final String newurl = AMQConnectionURL.AMQ_PROTOCOL + "://" + username +":" + password + "@" + client + "/" + path + '?' + AMQConnectionURL.OPTIONS_BROKERLIST + "='tcp://" + host + ':' + port + '\'' ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Initialising connectionURL to " + newurl) ;
+ }
+
+ cf = new AMQConnectionFactory(newurl) ;
+ }
+
+ return cf ;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java
new file mode 100644
index 0000000000..b927aaa0be
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.transaction.TransactionManager;
+
+import org.apache.qpid.ra.admin.QpidQueue;
+import org.apache.qpid.ra.admin.QpidTopic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Various utility functions
+ *
+ */
+public class Util
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(Util.class);
+
+ /**
+ * Compare two strings.
+ * @param me First value
+ * @param you Second value
+ * @return True if object equals else false.
+ */
+ public static boolean compare(final String me, final String you)
+ {
+ // If both null or intern equals
+ if (me == you)
+ {
+ return true;
+ }
+
+ // if me null and you are not
+ if (me == null && you != null)
+ {
+ return false;
+ }
+
+ // me will not be null, test for equality
+ return me.equals(you);
+ }
+
+ /**
+ * Lookup an object in the default initial context
+ * @param context The context to use
+ * @param name the name to lookup
+ * @param clazz the expected type
+ * @return the object
+ * @throws Exception for any error
+ */
+ public static <T> T lookup(final Context context, final String name, final Class<T> clazz) throws Exception
+ {
+ Object object = context.lookup(name);
+
+ if (object instanceof Reference)
+ {
+
+ Reference ref = (Reference) object;
+ String addressContent = null;
+
+ if (ref.getClassName().equals(QpidQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidQueue.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidQueue(addressContent);
+ }
+ }
+
+ if (ref.getClassName().equals(QpidTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidTopic.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidTopic(addressContent);
+ }
+ }
+ }
+
+ return clazz.cast(object);
+
+ }
+
+ /** The Resource adapter can't depend on any provider's specific library. Because of that we use reflection to locate the
+ * transaction manager during startup.
+ *
+ *
+ * TODO: We should use a proper SPI instead of reflection
+ * We would need to define a proper SPI package for this.
+ **/
+ public static TransactionManager locateTM(final String locatorClass, final String locatorMethod)
+ {
+ try
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ Class<?> aClass = loader.loadClass(locatorClass);
+ Object o = aClass.newInstance();
+ Method m = aClass.getMethod(locatorMethod);
+ return (TransactionManager)m.invoke(o);
+ }
+ catch (Throwable e)
+ {
+ _log.debug(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * Serialize the object into a byte array.
+ * @param serializable The serializable object
+ * @return The generated byte array
+ * @throws IOException For errors during serialization.
+ */
+ public static byte[] serialize(final Serializable serializable)
+ throws IOException
+ {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
+ final ObjectOutputStream oos = new ObjectOutputStream(baos) ;
+ oos.writeObject(serializable) ;
+ oos.close() ;
+ return baos.toByteArray() ;
+ }
+
+ /**
+ * Deserialize the byte array into an object.
+ * @param data The serialized object as a byte array
+ * @return The serializable object.
+ * @throws IOException For errors during deserialization
+ * @throws ClassNotFoundException If the deserialized class cannot be found.
+ */
+ public static Object deserialize(final byte[] data)
+ throws IOException, ClassNotFoundException
+ {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(data) ;
+ final ObjectInputStream ois = new ObjectInputStream(bais) ;
+ return ois.readObject() ;
+ }
+
+ /**
+ * Return a string identification for the specified object.
+ * @param object The object value.
+ * @return The string identification.
+ */
+ public static String asString(final Object object)
+ {
+ return (object == null ? "null" : object.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(object))) ;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java
new file mode 100644
index 0000000000..11f2903c72
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.ra.admin;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AdminObjectFactory implements ObjectFactory
+{
+ private static final Logger _log = LoggerFactory.getLogger(AdminObjectFactory.class);
+
+ @Override
+ public Object getObjectInstance(Object object, Name name, Context context, Hashtable<?, ?> env) throws Exception
+ {
+
+ Object instance = null;
+
+ if (object instanceof Reference)
+ {
+ Reference ref = (Reference) object;
+ String bindingURLString;
+
+ if (ref.getClassName().equals(QpidQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidQueue.class.getName());
+ bindingURLString = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return new QpidQueue(bindingURLString);
+ }
+
+ }
+
+ if (ref.getClassName().equals(QpidTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidTopic.class.getName());
+ bindingURLString = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return new QpidTopic(bindingURLString);
+ }
+ }
+ }
+ return instance;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java
new file mode 100644
index 0000000000..503f59eecc
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.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.ra.admin;
+
+import java.net.URISyntaxException;
+
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+
+public class QpidBindingURL extends AMQBindingURL {
+
+ private String _url;
+
+ public QpidBindingURL(String url) throws URISyntaxException {
+ super(url);
+
+ if (!url.contains(BindingURL.OPTION_ROUTING_KEY) || getRoutingKey() == null) {
+ setOption(BindingURL.OPTION_ROUTING_KEY, null);
+ }
+
+ this._url = url;
+ }
+
+ @Override
+ public String getURL() {
+ return _url;
+ }
+
+ @Override
+ public String toString() {
+ return _url;
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java
new file mode 100644
index 0000000000..41242fefae
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra.admin;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ *
+ */
+public class QpidConnectionFactoryProxy implements Externalizable, Referenceable, ConnectionFactory, Serializable
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidDestinationProxy.class);
+
+ private String _connectionURL;
+
+ private ConnectionFactory _delegate;
+
+ /**
+ * This constructor should not only be used be de-serialisation code. Create
+ * original object with the other constructor.
+ */
+ public QpidConnectionFactoryProxy()
+ {
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ Reference ref = (Reference) in.readObject();
+
+ try
+ {
+ _delegate = (ConnectionFactory) dereference(ref);
+
+ } catch (Exception e)
+ {
+ _log.error("Failed to dereference ConnectionFactory " + e.getMessage(), e);
+ throw new IOException("Failed to dereference ConnectionFactory: " + e.getMessage());
+ }
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ if (_delegate == null)
+ {
+ _log.error("Null Destination ");
+ throw new IOException("Null ConnectionFactory!");
+ }
+
+ try
+ {
+ out.writeObject(((Referenceable) _delegate).getReference());
+ }
+ catch (NamingException e)
+ {
+ _log.error("Failed to dereference ConnectionFactory " + e.getMessage(), e);
+ throw new IOException("Failed to dereference ConnectionFactory: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ try
+ {
+ _delegate = new AMQConnectionFactory(getConnectionURL());
+ /*
+ QpidResourceAdapter ra = new QpidResourceAdapter();
+ QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory();
+ mcf.setResourceAdapter(ra);
+ mcf.setConnectionURL(getConnectionURL());
+ delegate = new QpidRAConnectionFactoryImpl(mcf, null);
+ */
+ return ((Referenceable) _delegate).getReference();
+ }
+ catch(Exception e)
+ {
+ throw new NamingException(e.getMessage());
+ }
+ }
+ private Object dereference(Reference ref) throws Exception
+ {
+ ObjectFactory objFactory = (ObjectFactory) Class.forName(
+ ref.getFactoryClassName()).newInstance();
+ return objFactory.getObjectInstance(ref, null, null, null);
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ this._connectionURL = connectionURL;
+ }
+ public String getConnectionURL()
+ {
+ return this._connectionURL;
+ }
+
+ /**
+ * Create a connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection() throws JMSException
+ {
+ return _delegate.createConnection();
+ }
+
+ /**
+ * Create a connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection(final String userName, final String password) throws JMSException
+ {
+ return _delegate.createConnection(userName, password);
+ }
+
+}
+
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java
new file mode 100644
index 0000000000..738ce4be0d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java
@@ -0,0 +1,162 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra.admin;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+import javax.jms.Destination;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.spi.ObjectFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The QpidDestinationProxy provides for allowing an administrator/developer to
+ * create and bind QPID destinations into a JNDI tree. AdminObjects are used as
+ * an generic integration point rather than relying on the EE server specific
+ * API's to create destinations (queues, topics). AdminObjects and associated
+ * properties are defined in the ra.xml file for a particular JCA adapter.
+ * Please see the ra.xml file for the QPID JCA resource adapter as well as the
+ * README.txt for the adapter for more details.
+ *
+ */
+public class QpidDestinationProxy implements Externalizable, Referenceable, Destination, Serializable
+{
+ private static final long serialVersionUID = -1137413782643796461L;
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidDestinationProxy.class);
+
+ private static final String DEFAULT_QUEUE_TYPE = "QUEUE";
+
+ private static final String DEFAULT_TOPIC_TYPE = "TOPIC";
+
+ private String _destinationAddress;
+
+ private String _destinationType;
+
+ private Destination _delegate;
+
+ /**
+ * This constructor should not only be used be de-serialisation code. Create
+ * original object with the other constructor.
+ */
+ public QpidDestinationProxy()
+ {
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ Reference ref = (Reference) in.readObject();
+
+ try
+ {
+ _delegate = (Destination) dereference(ref);
+
+ } catch (Exception e)
+ {
+ _log.error("Failed to dereference Destination " + e.getMessage(), e);
+ throw new IOException("Failed to dereference Destination: " + e.getMessage());
+ }
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ if (_delegate == null)
+ {
+ _log.error("Null Destination ");
+ throw new IOException("Null destination!");
+ }
+
+ try
+ {
+ out.writeObject(((Referenceable) _delegate).getReference());
+ }
+ catch (NamingException e)
+ {
+ _log.error("Failed to dereference Destination " + e.getMessage(), e);
+ throw new IOException("Failed to dereference Destination: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ try
+ {
+ if(getDestinationType().equalsIgnoreCase(DEFAULT_QUEUE_TYPE))
+ {
+ _delegate = new QpidQueue(getDestinationAddress());
+ }
+ else if(getDestinationType().equalsIgnoreCase(DEFAULT_TOPIC_TYPE))
+ {
+ _delegate = new QpidTopic(getDestinationAddress());
+ }
+ else
+ {
+ throw new IllegalStateException("Unknown destination type " + getDestinationType());
+ }
+
+ return ((Referenceable) _delegate).getReference();
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(),e);
+ throw new NamingException("Failed to create destination " + e.getMessage());
+ }
+
+ }
+
+ private Object dereference(Reference ref) throws Exception
+ {
+ ObjectFactory objFactory = (ObjectFactory) Class.forName(
+ ref.getFactoryClassName()).newInstance();
+ return objFactory.getObjectInstance(ref, null, null, null);
+ }
+
+ public void setDestinationAddress(String destinationAddress) throws Exception
+ {
+ this._destinationAddress = destinationAddress;
+ }
+
+ public String getDestinationAddress()
+ {
+ return this._destinationAddress;
+ }
+
+ public void setDestinationType(String destinationType)
+ {
+ this._destinationType = destinationType;
+ }
+
+ public String getDestinationType()
+ {
+ return this._destinationType;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java
new file mode 100644
index 0000000000..caef0c8ffd
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.ra.admin;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.qpid.client.AMQQueue;
+
+public class QpidQueue extends AMQQueue
+{
+ private String _url;
+
+ public QpidQueue(final String address) throws Exception
+ {
+ super(address);
+ this._url = address;
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(this.getClass().getName(), new StringRefAddr(this.getClass().getName(), toURL()),
+ AdminObjectFactory.class.getName(), null);
+ }
+
+ @Override
+ public String toURL()
+ {
+ return _url;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java
new file mode 100644
index 0000000000..3f181b93eb
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.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.ra.admin;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.qpid.client.AMQTopic;
+
+public class QpidTopic extends AMQTopic
+{
+ private String _url;
+
+ public QpidTopic(final String address) throws Exception
+ {
+ super(address);
+ this._url = address;
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(this.getClass().getName(), new StringRefAddr(this.getClass().getName(), toURL()),
+ AdminObjectFactory.class.getName(), null);
+ }
+
+ @Override
+ public String toURL()
+ {
+ return _url;
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
new file mode 100644
index 0000000000..98427d7f9d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
@@ -0,0 +1,593 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra.inflow;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.resource.ResourceException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.Work;
+import javax.resource.spi.work.WorkManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.ra.QpidResourceAdapter;
+import org.apache.qpid.ra.Util;
+
+/**
+ * The activation.
+ *
+ */
+public class QpidActivation implements ExceptionListener
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidActivation.class);
+
+ /**
+ * The onMessage method
+ */
+ public static final Method ONMESSAGE;
+
+ /**
+ * The resource adapter
+ */
+ private final QpidResourceAdapter _ra;
+
+ /**
+ * The activation spec
+ */
+ private final QpidActivationSpec _spec;
+
+ /**
+ * The message endpoint factory
+ */
+ private final MessageEndpointFactory _endpointFactory;
+
+ /**
+ * Whether delivery is active
+ */
+ private final AtomicBoolean _deliveryActive = new AtomicBoolean(false);
+
+ /**
+ * The destination type
+ */
+ private boolean _isTopic = false;
+
+ /**
+ * Is the delivery transacted
+ */
+ private boolean _isDeliveryTransacted;
+
+ private Destination _destination;
+
+ /**
+ * The connection
+ */
+ private Connection _connection;
+
+ private final List<QpidMessageHandler> _handlers = new ArrayList<QpidMessageHandler>();
+
+ private AMQConnectionFactory _factory;
+
+ // Whether we are in the failure recovery loop
+ private AtomicBoolean _inFailure = new AtomicBoolean(false);
+
+ static
+ {
+ try
+ {
+ ONMESSAGE = MessageListener.class.getMethod("onMessage", new Class[] { Message.class });
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param ra The resource adapter
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public QpidActivation(final QpidResourceAdapter ra,
+ final MessageEndpointFactory endpointFactory,
+ final QpidActivationSpec spec) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + ra + ", " + endpointFactory + ", " + spec + ")");
+ }
+
+ this._ra = ra;
+ this._endpointFactory = endpointFactory;
+ this._spec = spec;
+ try
+ {
+ _isDeliveryTransacted = endpointFactory.isDeliveryTransacted(QpidActivation.ONMESSAGE);
+ }
+ catch (Exception e)
+ {
+ throw new ResourceException(e);
+ }
+ }
+
+ /**
+ * Get the activation spec
+ *
+ * @return The value
+ */
+ public QpidActivationSpec getActivationSpec()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getActivationSpec()");
+ }
+
+ return _spec;
+ }
+
+ /**
+ * Get the message endpoint factory
+ *
+ * @return The value
+ */
+ public MessageEndpointFactory getMessageEndpointFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageEndpointFactory()");
+ }
+
+ return _endpointFactory;
+ }
+
+ /**
+ * Get whether delivery is transacted
+ *
+ * @return The value
+ */
+ public boolean isDeliveryTransacted()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isDeliveryTransacted()");
+ }
+
+ return _isDeliveryTransacted;
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The value
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ return _ra.getWorkManager();
+ }
+
+ /**
+ * Is the destination a topic
+ *
+ * @return The value
+ */
+ public boolean isTopic()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isTopic()");
+ }
+
+ return _isTopic;
+ }
+
+ /**
+ * Start the activation
+ *
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void start() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+ _deliveryActive.set(true);
+ _ra.getWorkManager().scheduleWork(new SetupActivation());
+ }
+
+ /**
+ * Stop the activation
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ _deliveryActive.set(false);
+ teardown();
+ }
+
+ /**
+ * Setup the activation
+ *
+ * @throws Exception Thrown if an error occurs
+ */
+ protected synchronized void setup() throws Exception
+ {
+ _log.debug("Setting up " + _spec);
+ setupCF();
+
+ setupDestination();
+ final AMQConnection amqConnection ;
+ final boolean useLocalTx = _spec.isUseLocalTx() ;
+ final boolean isXA = _isDeliveryTransacted && !useLocalTx ;
+
+ if (isXA)
+ {
+ amqConnection = (XAConnectionImpl)_factory.createXAConnection() ;
+ }
+ else
+ {
+ amqConnection = (AMQConnection)_factory.createConnection() ;
+ }
+
+ amqConnection.setExceptionListener(this) ;
+
+ for (int i = 0; i < _spec.getMaxSession(); i++)
+ {
+ Session session = null;
+
+ try
+ {
+ if (isXA)
+ {
+ session = _ra.createXASession((XAConnectionImpl)amqConnection) ;
+ }
+ else
+ {
+ session = _ra.createSession((AMQConnection)amqConnection,
+ _spec.getAcknowledgeModeInt(),
+ useLocalTx,
+ _spec.getPrefetchLow(),
+ _spec.getPrefetchHigh());
+ }
+
+ _log.debug("Using session " + Util.asString(session));
+ QpidMessageHandler handler = new QpidMessageHandler(this, _ra.getTM(), session);
+ handler.setup();
+ _handlers.add(handler);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ amqConnection.close() ;
+ }
+ catch (Exception e2)
+ {
+ _log.trace("Ignored error closing connection", e2);
+ }
+
+ throw e;
+ }
+ }
+ amqConnection.start() ;
+ this._connection = amqConnection ;
+
+ _log.debug("Setup complete " + this);
+ }
+
+ /**
+ * Teardown the activation
+ */
+ protected synchronized void teardown()
+ {
+ _log.debug("Tearing down " + _spec);
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error stopping connection " + Util.asString(_connection), t);
+ }
+
+ for (QpidMessageHandler handler : _handlers)
+ {
+ handler.teardown();
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error closing connection " + Util.asString(_connection), t);
+ }
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = null;
+ }
+ _log.debug("Tearing down complete " + this);
+ }
+
+ protected void setupCF() throws Exception
+ {
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = _ra.createAMQConnectionFactory(_spec);
+ }
+ else
+ {
+ _factory = _ra.getDefaultAMQConnectionFactory();
+ }
+ }
+
+ public Destination getDestination()
+ {
+ return _destination;
+ }
+
+ protected void setupDestination() throws Exception
+ {
+
+ String destinationName = _spec.getDestination();
+ String destinationTypeString = _spec.getDestinationType();
+
+ if (_spec.isUseJNDI())
+ {
+ Context ctx = new InitialContext();
+ _log.debug("Using context " + ctx.getEnvironment() + " for " + _spec);
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setupDestination(" + ctx + ")");
+ }
+
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+
+ Class<? extends Destination> destinationType;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ destinationType = Topic.class;
+ _isTopic = true;
+ }
+ else
+ {
+ destinationType = Queue.class;
+ }
+
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ destinationType.getName());
+ _destination = Util.lookup(ctx, destinationName, destinationType);
+ //_destination = (Destination)ctx.lookup(destinationName);
+
+ }
+ else
+ {
+ _log.debug("Destination type not defined");
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ Destination.class.getName());
+
+ _destination = Util.lookup(ctx, destinationName, AMQDestination.class);
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+ else
+ {
+ _destination = (AMQDestination)AMQDestination.createDestination(_spec.getDestination());
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+ final boolean match ;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ match = (_destination instanceof Topic) ;
+ _isTopic = true;
+ }
+ else
+ {
+ match = (_destination instanceof Queue) ;
+ }
+ if (!match)
+ {
+ throw new ClassCastException("Expected destination of type " + destinationTypeString + " but created destination " + _destination) ;
+ }
+ }
+ else
+ {
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+
+ _log.debug("Got destination " + _destination + " from " + destinationName);
+ }
+
+ /**
+ * Get a string representation
+ *
+ * @return The value
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(QpidActivation.class.getName()).append('(');
+ buffer.append("spec=").append(_spec.getClass().getName());
+ buffer.append(" mepf=").append(_endpointFactory.getClass().getName());
+ buffer.append(" active=").append(_deliveryActive.get());
+ if (_spec.getDestination() != null)
+ {
+ buffer.append(" destination=").append(_spec.getDestination());
+ }
+ buffer.append(" transacted=").append(_isDeliveryTransacted);
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+ public void onException(final JMSException jmse)
+ {
+ handleFailure(jmse) ;
+ }
+
+ /**
+ * Handles any failure by trying to reconnect
+ *
+ * @param failure the reason for the failure
+ */
+ public void handleFailure(Throwable failure)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.warn("Failure in Qpid activation " + _spec, failure);
+ }
+ int reconnectCount = 0;
+ int setupAttempts = _spec.getSetupAttempts();
+ long setupInterval = _spec.getSetupInterval();
+
+ // Only enter the failure loop once
+ if (_inFailure.getAndSet(true))
+ return;
+ try
+ {
+ while (_deliveryActive.get() && (setupAttempts == -1 || reconnectCount < setupAttempts))
+ {
+ teardown();
+
+ try
+ {
+ Thread.sleep(setupInterval);
+ }
+ catch (InterruptedException e)
+ {
+ _log.debug("Interrupted trying to reconnect " + _spec, e);
+ break;
+ }
+
+ _log.info("Attempting to reconnect " + _spec);
+ try
+ {
+ setup();
+ _log.info("Reconnected with Qpid");
+ break;
+ }
+ catch (Throwable t)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.error("Unable to reconnect " + _spec, t);
+ }
+ }
+ ++reconnectCount;
+ }
+ }
+ finally
+ {
+ // Leaving failure recovery loop
+ _inFailure.set(false);
+ }
+ }
+
+ /**
+ * Check to see if the failure represents a missing endpoint
+ * @param failure The failure.
+ * @return true if it represents a missing endpoint, false otherwise
+ */
+ private boolean doesNotExist(final Throwable failure)
+ {
+ return (failure instanceof AMQException) && (((AMQException)failure).getErrorCode() == AMQConstant.NOT_FOUND) ;
+ }
+
+ /**
+ * Handles the setup
+ */
+ private class SetupActivation implements Work
+ {
+ public void run()
+ {
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ handleFailure(t);
+ }
+ }
+
+ public void release()
+ {
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java
new file mode 100644
index 0000000000..5f4e2dcf6b
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java
@@ -0,0 +1,604 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra.inflow;
+
+import java.io.Serializable;
+
+import javax.jms.Session;
+import javax.resource.ResourceException;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.InvalidPropertyException;
+import javax.resource.spi.ResourceAdapter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.ra.ConnectionFactoryProperties;
+import org.apache.qpid.ra.QpidResourceAdapter;
+
+/**
+ * The activation spec
+ * These properties are set on the MDB ActivactionProperties
+ *
+ */
+public class QpidActivationSpec extends ConnectionFactoryProperties implements ActivationSpec, Serializable
+{
+ private static final long serialVersionUID = 7379131936083146158L;
+
+ private static final int DEFAULT_MAX_SESSION = 15;
+
+ /** The logger */
+ private static final transient Logger _log = LoggerFactory.getLogger(QpidActivationSpec.class);
+
+ /** The resource adapter */
+ private QpidResourceAdapter _ra;
+
+ /** The destination */
+ private String _destination;
+
+ /** The destination type */
+ private String _destinationType;
+
+ /** The message selector */
+ private String _messageSelector;
+
+ /** The acknowledgement mode */
+ private int _acknowledgeMode;
+
+ /** The subscription durability */
+ private boolean _subscriptionDurability;
+
+ /** The subscription name */
+ private String _subscriptionName;
+
+ /** The maximum number of sessions */
+ private Integer _maxSession;
+
+ /** Transaction timeout */
+ private Integer _transactionTimeout;
+
+ /** prefetch low */
+ private Integer _prefetchLow;
+
+ /** prefetch high */
+ private Integer _prefetchHigh;
+
+ private boolean _useJNDI = true;
+
+ // undefined by default, default is specified at the RA level in QpidRAProperties
+ private Integer _setupAttempts;
+
+ // undefined by default, default is specified at the RA level in QpidRAProperties
+ private Long _setupInterval;
+
+ /**
+ * Constructor
+ */
+ public QpidActivationSpec()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ _maxSession = DEFAULT_MAX_SESSION;
+ _transactionTimeout = 0;
+ }
+
+ /**
+ * Get the resource adapter
+ * @return The resource adapter
+ */
+ public ResourceAdapter getResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getResourceAdapter()");
+ }
+
+ return _ra;
+ }
+
+ /**
+ * @return the useJNDI
+ */
+ public boolean isUseJNDI()
+ {
+ return _useJNDI;
+ }
+
+ /**
+ * @param value the useJNDI to set
+ */
+ public void setUseJNDI(final boolean value)
+ {
+ _useJNDI = value;
+ }
+
+ /**
+ * Set the resource adapter
+ * @param ra The resource adapter
+ * @exception ResourceException Thrown if incorrect resource adapter
+ */
+ public void setResourceAdapter(final ResourceAdapter ra) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setResourceAdapter(" + ra + ")");
+ }
+
+ if (ra == null || !(ra instanceof QpidResourceAdapter))
+ {
+ throw new ResourceException("Resource adapter is " + ra);
+ }
+
+ this._ra = (QpidResourceAdapter)ra;
+ }
+
+ /**
+ * Get the destination
+ * @return The value
+ */
+ public String getDestination()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestination()");
+ }
+
+ return _destination;
+ }
+
+ /**
+ * Set the destination
+ * @param value The value
+ */
+ public void setDestination(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDestination(" + value + ")");
+ }
+
+ _destination = value;
+ }
+
+ /**
+ * Get the destination type
+ * @return The value
+ */
+ public String getDestinationType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestinationType()");
+ }
+
+ return _destinationType;
+ }
+
+ /**
+ * Set the destination type
+ * @param value The value
+ */
+ public void setDestinationType(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDestinationType(" + value + ")");
+ }
+
+ _destinationType = value;
+ }
+
+ /**
+ * Get the message selector
+ * @return The value
+ */
+ public String getMessageSelector()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ return _messageSelector;
+ }
+
+ /**
+ * Set the message selector
+ * @param value The value
+ */
+ public void setMessageSelector(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMessageSelector(" + value + ")");
+ }
+
+ _messageSelector = value;
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The value
+ */
+ public String getAcknowledgeMode()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ if (Session.DUPS_OK_ACKNOWLEDGE == _acknowledgeMode)
+ {
+ return "Dups-ok-acknowledge";
+ }
+ else
+ {
+ return "Auto-acknowledge";
+ }
+ }
+
+ /**
+ * Set the acknowledge mode
+ * @param value The value
+ */
+ public void setAcknowledgeMode(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setAcknowledgeMode(" + value + ")");
+ }
+
+ if ("DUPS_OK_ACKNOWLEDGE".equalsIgnoreCase(value) || "Dups-ok-acknowledge".equalsIgnoreCase(value))
+ {
+ _acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
+ }
+ else if ("AUTO_ACKNOWLEDGE".equalsIgnoreCase(value) || "Auto-acknowledge".equalsIgnoreCase(value))
+ {
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unsupported acknowledgement mode " + value);
+ }
+ }
+
+ /**
+ * @return the acknowledgement mode
+ */
+ public int getAcknowledgeModeInt()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ return _acknowledgeMode;
+ }
+
+ /**
+ * Get the subscription durability
+ * @return The value
+ */
+ public String getSubscriptionDurability()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSubscriptionDurability()");
+ }
+
+ if (_subscriptionDurability)
+ {
+ return "Durable";
+ }
+ else
+ {
+ return "NonDurable";
+ }
+ }
+
+ /**
+ * Set the subscription durability
+ * @param value The value
+ */
+ public void setSubscriptionDurability(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSubscriptionDurability(" + value + ")");
+ }
+
+ _subscriptionDurability = "Durable".equals(value);
+ }
+
+ /**
+ * Get the status of subscription durability
+ * @return The value
+ */
+ public boolean isSubscriptionDurable()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isSubscriptionDurable()");
+ }
+
+ return _subscriptionDurability;
+ }
+
+ /**
+ * Get the subscription name
+ * @return The value
+ */
+ public String getSubscriptionName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSubscriptionName()");
+ }
+
+ return _subscriptionName;
+ }
+
+ /**
+ * Set the subscription name
+ * @param value The value
+ */
+ public void setSubscriptionName(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSubscriptionName(" + value + ")");
+ }
+
+ _subscriptionName = value;
+ }
+
+ /**
+ * Get the number of max session
+ * @return The value
+ */
+ public Integer getMaxSession()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMaxSession()");
+ }
+
+ if (_maxSession == null)
+ {
+ return DEFAULT_MAX_SESSION;
+ }
+
+ return _maxSession;
+ }
+
+ /**
+ * Set the number of max session
+ * @param value The value
+ */
+ public void setMaxSession(final Integer value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMaxSession(" + value + ")");
+ }
+
+ _maxSession = value;
+ }
+
+ /**
+ * Get the transaction timeout
+ * @return The value
+ */
+ public Integer getTransactionTimeout()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionTimeout()");
+ }
+
+ return _transactionTimeout;
+ }
+
+ /**
+ * Set the transaction timeout
+ * @param value The value
+ */
+ public void setTransactionTimeout(final Integer value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionTimeout(" + value + ")");
+ }
+
+ _transactionTimeout = value;
+ }
+
+ /**
+ * Get the prefetch low
+ * @return The value
+ */
+ public Integer getPrefetchLow()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPrefetchLow()");
+ }
+
+ return _prefetchLow;
+ }
+
+ /**
+ * Set the prefetch low
+ * @param value The value
+ */
+ public void setPrefetchLow(final Integer prefetchLow)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPrefetchLow(" + prefetchLow + ")");
+ }
+
+ this._prefetchLow = prefetchLow;
+ }
+
+ /**
+ * Get the prefetch high
+ * @return The value
+ */
+ public Integer getPrefetchHigh()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPrefetchHigh()");
+ }
+
+ return _prefetchHigh;
+ }
+
+ /**
+ * Set the prefetch high
+ * @param value The value
+ */
+ public void setPrefetchHigh(final Integer prefetchHigh)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPrefetchHigh(" + prefetchHigh + ")");
+ }
+
+ this._prefetchHigh = prefetchHigh;
+ }
+
+ public int getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+
+ if (_setupAttempts == null)
+ {
+ return _ra.getSetupAttempts();
+ }
+ else
+ {
+ return _setupAttempts;
+ }
+ }
+
+ public void setSetupAttempts(int setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+
+ this._setupAttempts = setupAttempts;
+ }
+
+ public long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+
+ if (_setupInterval == null)
+ {
+ return _ra.getSetupInterval();
+ }
+ else
+ {
+ return _setupInterval;
+ }
+ }
+
+ public void setSetupInterval(long setupInterval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + setupInterval + ")");
+ }
+
+ this._setupInterval = setupInterval;
+ }
+
+ /**
+ * Validate
+ * @exception InvalidPropertyException Thrown if a validation exception occurs
+ */
+ public void validate() throws InvalidPropertyException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("validate()");
+ }
+
+ if (_destination == null || _destination.trim().equals(""))
+ {
+ throw new InvalidPropertyException("Destination is mandatory");
+ }
+ }
+
+ /**
+ * Get a string representation
+ * @return The value
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(QpidActivationSpec.class.getName()).append('(');
+ buffer.append("ra=").append(_ra);
+ buffer.append(" destination=").append(_destination);
+ buffer.append(" destinationType=").append(_destinationType);
+ if (_messageSelector != null)
+ {
+ buffer.append(" selector=").append(_messageSelector);
+ }
+ buffer.append(" ack=").append(getAcknowledgeMode());
+ buffer.append(" durable=").append(_subscriptionDurability);
+ buffer.append(" clientID=").append(getClientId());
+ if (_subscriptionName != null)
+ {
+ buffer.append(" subscription=").append(_subscriptionName);
+ }
+ buffer.append(" user=").append(getUserName());
+ if (getPassword() != null)
+ {
+ buffer.append(" password=").append("****");
+ }
+ buffer.append(" maxSession=").append(_maxSession);
+ if (_prefetchLow != null)
+ {
+ buffer.append(" prefetchLow=").append(_prefetchLow);
+ }
+ if (_prefetchHigh != null)
+ {
+ buffer.append(" prefetchHigh=").append(_prefetchHigh);
+ }
+ buffer.append(')');
+ return buffer.toString();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java
new file mode 100644
index 0000000000..473efab31f
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ra.inflow;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.XASession;
+import javax.resource.ResourceException;
+import javax.resource.spi.endpoint.MessageEndpoint;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.apache.qpid.ra.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The message handler
+ *
+ */
+public class QpidMessageHandler implements MessageListener
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidMessageHandler.class);
+
+ /**
+ * The session
+ */
+ private final Session _session;
+
+ private MessageConsumer _consumer;
+
+ /**
+ * The endpoint
+ */
+ private MessageEndpoint _endpoint;
+
+ private final QpidActivation _activation;
+
+ private boolean _useLocalTx;
+
+ private boolean _transacted;
+
+ private final TransactionManager _tm;
+
+ public QpidMessageHandler(final QpidActivation activation,
+ final TransactionManager tm,
+ final Session session)
+ {
+ this._activation = activation;
+ this._session = session;
+ this._tm = tm;
+ }
+
+ public void setup() throws Exception
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setup()");
+ }
+
+ QpidActivationSpec spec = _activation.getActivationSpec();
+ String selector = spec.getMessageSelector();
+
+ // Create the message consumer
+ if (_activation.isTopic())
+ {
+ final Topic topic = (Topic) _activation.getDestination();
+ final String subscriptionName = spec.getSubscriptionName();
+ if (spec.isSubscriptionDurable())
+ _consumer = _session.createDurableSubscriber(topic, subscriptionName, selector, false);
+ else
+ _consumer = _session.createConsumer(topic, selector) ;
+ }
+ else
+ {
+ final Queue queue = (Queue) _activation.getDestination();
+ _consumer = _session.createConsumer(queue, selector);
+ }
+
+ // Create the endpoint, if we are transacted pass the session so it is enlisted, unless using Local TX
+ MessageEndpointFactory endpointFactory = _activation.getMessageEndpointFactory();
+ _useLocalTx = _activation.getActivationSpec().isUseLocalTx();
+ _transacted = _activation.isDeliveryTransacted() || _useLocalTx ;
+ if (_activation.isDeliveryTransacted() && !_activation.getActivationSpec().isUseLocalTx())
+ {
+ final XAResource xaResource = ((XASession)_session).getXAResource() ;
+ _endpoint = endpointFactory.createEndpoint(xaResource);
+ }
+ else
+ {
+ _endpoint = endpointFactory.createEndpoint(null);
+ }
+ _consumer.setMessageListener(this);
+ }
+
+ /**
+ * Stop the handler
+ */
+ public void teardown()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("teardown()");
+ }
+
+ try
+ {
+ if (_endpoint != null)
+ {
+ _endpoint.release();
+ _endpoint = null;
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error releasing endpoint " + _endpoint, t);
+ }
+ }
+
+ public void onMessage(final Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onMessage(" + Util.asString(message) + ")");
+ }
+
+ boolean beforeDelivery = false;
+
+ try
+ {
+ if (_activation.getActivationSpec().getTransactionTimeout() > 0 && _tm != null)
+ {
+ _tm.setTransactionTimeout(_activation.getActivationSpec().getTransactionTimeout());
+ }
+
+ _endpoint.beforeDelivery(QpidActivation.ONMESSAGE);
+ beforeDelivery = true;
+
+ if(_transacted)
+ {
+ message.acknowledge();
+ }
+
+ ((MessageListener)_endpoint).onMessage(message);
+
+ if (_transacted && (_tm.getTransaction() != null))
+ {
+ final int status = _tm.getStatus() ;
+ final boolean rollback = status == Status.STATUS_MARKED_ROLLBACK
+ || status == Status.STATUS_ROLLING_BACK
+ || status == Status.STATUS_ROLLEDBACK;
+ if (rollback)
+ {
+ _session.recover() ;
+ }
+ }
+ else
+ {
+ message.acknowledge();
+ }
+
+ try
+ {
+ _endpoint.afterDelivery();
+ }
+ catch (ResourceException e)
+ {
+ _log.warn("Unable to call after delivery", e);
+ return;
+ }
+ if (_useLocalTx)
+ {
+ _session.commit();
+ }
+ }
+ catch (Throwable e)
+ {
+ _log.error("Failed to deliver message", e);
+ // we need to call before/afterDelivery as a pair
+ if (beforeDelivery)
+ {
+ try
+ {
+ _endpoint.afterDelivery();
+ }
+ catch (ResourceException e1)
+ {
+ _log.warn("Unable to call after delivery", e);
+ }
+ }
+ if (_useLocalTx || !_activation.isDeliveryTransacted())
+ {
+ try
+ {
+ _session.rollback();
+ }
+ catch (JMSException e1)
+ {
+ _log.warn("Unable to roll local transaction back", e1);
+ }
+ }
+ else
+ {
+ try
+ {
+ _session.recover() ;
+ }
+ catch (JMSException e1)
+ {
+ _log.warn("Unable to recover XA transaction", e1);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
new file mode 100644
index 0000000000..3a47824631
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.ra.tm;
+
+import java.util.Set;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.AbstractNameQuery;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.KernelRegistry;
+
+public class GeronimoTransactionManagerLocator
+{
+
+ public GeronimoTransactionManagerLocator()
+ {
+ }
+
+ public TransactionManager getTransactionManager()
+ {
+ try
+ {
+ Kernel kernel = KernelRegistry.getSingleKernel();
+ AbstractNameQuery query = new AbstractNameQuery(TransactionManager.class.getName ());
+ Set<AbstractName> names = kernel.listGBeans(query);
+
+ if (names.size() != 1)
+ {
+ throw new IllegalStateException("Expected one transaction manager, not " + names.size());
+ }
+
+ AbstractName name = names.iterator().next();
+ TransactionManager transMg = (TransactionManager) kernel.getGBean(name);
+ return (TransactionManager)transMg;
+
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java
new file mode 100644
index 0000000000..266c56bd63
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java
@@ -0,0 +1,33 @@
+package org.apache.qpid.ra.tm;
+
+import javax.naming.InitialContext;
+import javax.transaction.TransactionManager;
+
+public class JBoss7TransactionManagerLocator
+{
+ private static final String TM_JNDI_NAME = "java:jboss/TransactionManager";
+
+ public TransactionManager getTm() throws Exception
+ {
+ InitialContext ctx = null;
+
+ try
+ {
+ ctx = new InitialContext();
+ return (TransactionManager)ctx.lookup(TM_JNDI_NAME);
+ }
+ finally
+ {
+ try
+ {
+ if(ctx != null)
+ {
+ ctx.close();
+ }
+ }
+ catch(Exception ignore)
+ {
+ }
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java
new file mode 100644
index 0000000000..5a5b585984
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java
@@ -0,0 +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.ra.tm;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.transaction.TransactionManager;
+
+/**
+ */
+public class JBossTransactionManagerLocator
+{
+ private final String LOCATOR = "org.jboss.tm.TransactionManagerLocator" ;
+
+ public TransactionManager getTm()
+ throws SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
+ {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader() ;
+ final Class<?> locatorClass ;
+ try
+ {
+ locatorClass = classLoader.loadClass(LOCATOR) ;
+ }
+ catch (final ClassNotFoundException cnfe)
+ {
+ return null ;
+ }
+
+ Method instanceMethod = null ;
+ try
+ {
+ instanceMethod = locatorClass.getMethod("getInstance") ;
+ }
+ catch (final NoSuchMethodException nsme) {} // ignore
+
+ final Object instance ;
+ final String locatorMethodName ;
+ if (instanceMethod != null)
+ {
+ instance = instanceMethod.invoke(null) ;
+ locatorMethodName = "locate" ;
+ }
+ else
+ {
+ instance = null ;
+ locatorMethodName = "locateTransactionManager" ;
+ }
+ final Method locatorMethod = locatorClass.getMethod(locatorMethodName) ;
+ return (TransactionManager) locatorMethod.invoke(instance) ;
+ }
+}
diff --git a/qpid/java/systests/etc/virtualhosts-systests-aclv2-settings.xml b/qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml
index db1ad33a39..f459b1efc1 100644
--- a/qpid/java/systests/etc/virtualhosts-systests-aclv2-settings.xml
+++ b/qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -19,30 +19,15 @@
- under the License.
-
-->
-<virtualhosts>
- <virtualhost>
- <name>test</name>
- <test>
- <queues>
- <exchange>amq.direct</exchange>
- <!-- 4Mb -->
- <maximumQueueDepth>4235264</maximumQueueDepth>
- <!-- 2Mb -->
- <maximumMessageSize>2117632</maximumMessageSize>
- <!-- 10 mins -->
- <maximumMessageAge>600000</maximumMessageAge>
- </queues>
-
- <security>
- <aclv2>${QPID_HOME}/etc/test-default.txt</aclv2>
- </security>
- </test>
- </virtualhost>
-
- <virtualhost>
- <name>test2</name>
- <test2 />
- </virtualhost>
-</virtualhosts>
-
-
+<jboss-ra>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorClass</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>org.apache.qpid.ra.tm.JBossTransactionManagerLocator</ra-config-property-value>
+ </ra-config-property>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorMethod</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>getTm</ra-config-property-value>
+ </ra-config-property>
+</jboss-ra>
diff --git a/qpid/java/jca/src/main/resources/META-INF/ra.xml b/qpid/java/jca/src/main/resources/META-INF/ra.xml
new file mode 100755
index 0000000000..90dc7b3b8e
--- /dev/null
+++ b/qpid/java/jca/src/main/resources/META-INF/ra.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+
+<connector xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+ http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
+ version="1.5">
+
+ <description>QPID Resource Adapter</description>
+ <display-name>QPID Resource Adapter</display-name>
+
+ <vendor-name>Apache Software Foundation</vendor-name>
+ <eis-type>JMS 1.1 Server</eis-type>
+ <resourceadapter-version>1.0</resourceadapter-version>
+
+ <license>
+ <description>
+ The ASF licenses this file to you under the Apache License,
+ Version 2.0 (the "License"); you may not use this file except
+ in compliance with the License. You may obtain a copy of the
+ License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ </description>
+ <license-required>true</license-required>
+ </license>
+
+ <resourceadapter>
+ <resourceadapter-class>org.apache.qpid.ra.QpidResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientId</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Number of setup attempts before failing</description>
+ <config-property-name>SetupAttempts</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Interval between setup attempts</description>
+ <config-property-name>SetupInterval</config-property-name>
+ <config-property-type>java.lang.Long</config-property-type>
+ <config-property-value>5000</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'</config-property-value>
+ </config-property>
+
+ <outbound-resourceadapter>
+ <connection-definition>
+ <managedconnectionfactory-class>org.apache.qpid.ra.QpidRAManagedConnectionFactory</managedconnectionfactory-class>
+
+ <config-property>
+ <description>Default session type</description>
+ <config-property-name>sessionDefaultType</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>javax.jms.Queue</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Specify lock timeout in seconds</description>
+ <config-property-name>useTryLock</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>0</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientID</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value></config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <connectionfactory-interface>org.apache.qpid.ra.QpidRAConnectionFactory</connectionfactory-interface>
+ <connectionfactory-impl-class>org.apache.qpid.ra.QpidRAConnectionFactoryImpl</connectionfactory-impl-class>
+ <connection-interface>javax.jms.Session</connection-interface>
+ <connection-impl-class>org.apache.qpid.ra.QpidRASessionImpl</connection-impl-class>
+ </connection-definition>
+ <transaction-support>XATransaction</transaction-support>
+ <authentication-mechanism>
+ <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>
+ <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>
+ </authentication-mechanism>
+ <reauthentication-support>false</reauthentication-support>
+ </outbound-resourceadapter>
+ <inbound-resourceadapter>
+ <messageadapter>
+ <messagelistener>
+ <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
+ <activationspec>
+ <activationspec-class>org.apache.qpid.ra.inflow.QpidActivationSpec</activationspec-class>
+ <required-config-property>
+ <config-property-name>destination</config-property-name>
+ </required-config-property>
+ </activationspec>
+ </messagelistener>
+ </messageadapter>
+ </inbound-resourceadapter>
+
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <config-property>
+ <config-property-name>destinationAddress </config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ <config-property>
+ <config-property-name>destinationType</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidConnectionFactoryProxy</adminobject-class>
+ <config-property>
+ <config-property-name>connectionURL</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ </resourceadapter>
+</connector>
diff --git a/qpid/java/lib/geronimo-ejb_3.0_spec-1.0.1.jar b/qpid/java/lib/geronimo-ejb_3.0_spec-1.0.1.jar
new file mode 100644
index 0000000000..29087f2f46
--- /dev/null
+++ b/qpid/java/lib/geronimo-ejb_3.0_spec-1.0.1.jar
Binary files differ
diff --git a/qpid/java/lib/geronimo-j2ee-connector_1.5_spec-2.0.0.jar b/qpid/java/lib/geronimo-j2ee-connector_1.5_spec-2.0.0.jar
new file mode 100644
index 0000000000..70e7ed4a93
--- /dev/null
+++ b/qpid/java/lib/geronimo-j2ee-connector_1.5_spec-2.0.0.jar
Binary files differ
diff --git a/qpid/java/lib/geronimo-jta_1.1_spec-1.1.1.jar b/qpid/java/lib/geronimo-jta_1.1_spec-1.1.1.jar
new file mode 100644
index 0000000000..ee9963dfc8
--- /dev/null
+++ b/qpid/java/lib/geronimo-jta_1.1_spec-1.1.1.jar
Binary files differ
diff --git a/qpid/java/lib/geronimo-kernel-2.2.1.jar b/qpid/java/lib/geronimo-kernel-2.2.1.jar
new file mode 100644
index 0000000000..34c46c3183
--- /dev/null
+++ b/qpid/java/lib/geronimo-kernel-2.2.1.jar
Binary files differ
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
index b5c80a4fed..b74342df1f 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
@@ -23,6 +23,7 @@ package org.apache.qpid.management.common.mbeans;
import java.io.IOException;
import java.util.List;
+import java.util.Map;
import javax.management.JMException;
import javax.management.MBeanException;
@@ -118,6 +119,24 @@ public interface ManagedBroker
throws IOException, JMException, MBeanException;
/**
+ * Create a new Queue in the VirtualHost
+ *
+ * @since Qpid JMX API 2.4
+ * @param queueName name of the new queue
+ * @param durable true if the queue should be durable
+ * @param owner owner
+ * @param arguments declaration arguments for use when creating the queue, may be null.
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="createNewQueue", description="Create a new Queue in the VirtualHost", impact= MBeanOperationInfo.ACTION)
+ void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName,
+ @MBeanOperationParameter(name="owner", description="Owner name")String owner,
+ @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable,
+ @MBeanOperationParameter(name="arguments", description="Map of arguments")Map<String,Object> arguments)
+ throws IOException, JMException;
+
+ /**
* Unregisters the Queue bindings, removes the subscriptions and unregisters
* from the managed objects.
*
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
index d16db65d5d..c2900a3533 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
@@ -80,33 +80,12 @@ public interface ManagedConnection
Date getLastIoTime();
/**
- * Tells the total number of bytes written till now.
- * @return number of bytes written.
- *
- @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now")
- Long getWrittenBytes();
- */
- /**
- * Tells the total number of bytes read till now.
- * @return number of bytes read.
- *
- @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now")
- Long getReadBytes();
- */
-
- /**
* Threshold high value for no of channels. This is useful in setting notifications or
* taking required action is there are more channels being created.
* @return threshold limit for no of channels
*/
- Long getMaximumNumberOfChannels();
-
- /**
- * Sets the threshold high value for number of channels for a connection
- * @param value
- */
@MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection")
- void setMaximumNumberOfChannels(Long value);
+ Long getMaximumNumberOfChannels();
//********** Operations *****************//
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java
index be31d8ef88..c23a0f5076 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java
@@ -50,7 +50,8 @@ public interface ManagedQueue
String MSG_SIZE = "Size(bytes)";
String MSG_REDELIVERED = "Redelivered";
String MSG_QUEUE_POS = "Queue Position";
- List<String> VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC = Collections.unmodifiableList(Arrays.asList(MSG_AMQ_ID, MSG_HEADER, MSG_SIZE, MSG_REDELIVERED, MSG_QUEUE_POS));
+ String MSG_DELIVERY_COUNT = "Delivery Count";
+ List<String> VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC = Collections.unmodifiableList(Arrays.asList(MSG_AMQ_ID, MSG_HEADER, MSG_SIZE, MSG_REDELIVERED, MSG_QUEUE_POS, MSG_DELIVERY_COUNT));
List<String> VIEW_MSGS_TABULAR_UNIQUE_INDEX = Collections.unmodifiableList(Arrays.asList(MSG_QUEUE_POS));
//CompositeType key/description information for message content
@@ -67,6 +68,7 @@ public interface ManagedQueue
static final String ATTR_MAX_MSG_COUNT = "MaximumMessageCount";
static final String ATTR_MAX_QUEUE_DEPTH = "MaximumQueueDepth";
static final String ATTR_MAX_MSG_SIZE = "MaximumMessageSize";
+ static final String ATTR_MAXIMUM_DELIVERY_COUNT = "MaximumDeliveryCount";
static final String ATTR_DURABLE = "Durable";
static final String ATTR_AUTODELETE = "AutoDelete";
static final String ATTR_CONSUMER_COUNT = "ConsumerCount";
@@ -78,7 +80,8 @@ public interface ManagedQueue
static final String ATTR_FLOW_OVERFULL = "FlowOverfull";
static final String ATTR_FLOW_RESUME_CAPACITY = "FlowResumeCapacity";
static final String ATTR_EXCLUSIVE = "Exclusive";
-
+ static final String ATTR_ALT_EXCHANGE = "AlternateExchange";
+
//All attribute names constant
static final List<String> QUEUE_ATTRIBUTES
= Collections.unmodifiableList(
@@ -91,6 +94,7 @@ public interface ManagedQueue
ATTR_MAX_MSG_COUNT,
ATTR_MAX_QUEUE_DEPTH,
ATTR_MAX_MSG_SIZE,
+ ATTR_MAXIMUM_DELIVERY_COUNT,
ATTR_DURABLE,
ATTR_AUTODELETE,
ATTR_CONSUMER_COUNT,
@@ -101,7 +105,9 @@ public interface ManagedQueue
ATTR_CAPACITY,
ATTR_FLOW_OVERFULL,
ATTR_FLOW_RESUME_CAPACITY,
- ATTR_EXCLUSIVE))));
+ ATTR_EXCLUSIVE,
+ ATTR_ALT_EXCHANGE
+ ))));
/**
* Returns the Name of the ManagedQueue.
@@ -120,6 +126,16 @@ public interface ManagedQueue
Integer getMessageCount() throws IOException;
/**
+ * Maximum number of times a message is permitted to be delivered or zero if not enforced.
+ *
+ * @since Qpid JMX API 2.4
+ * @return maximum delivery count
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MaximumDeliveryCount", description = "Maximum number of times a message is permitted to be delivered or zero if not enforced")
+ Integer getMaximumDeliveryCount() throws IOException;
+
+ /**
* Tells the total number of messages receieved by the queue since startup.
* @return total number of messages received.
* @throws IOException
@@ -309,7 +325,7 @@ public interface ManagedQueue
/**
* Sets whether the queue is exclusive or not.
- *
+ *
* @since Qpid JMX API 2.0
* @param exclusive the capacity in bytes
* @throws IOException
@@ -318,6 +334,25 @@ public interface ManagedQueue
@MBeanAttribute(name="Exclusive", description="Whether the queue is Exclusive or not")
void setExclusive(boolean exclusive) throws IOException, JMException;
+ /**
+ * Sets the Alternate Exchange for the queue, for use in dead letter queue functionality.
+ *
+ * @since Qpid JMX API 2.4
+ * @param the name of the exchange to use. Specifying null or the empty string will clear the alternate exchange.
+ * @throws IOException
+ */
+ void setAlternateExchange(String exchangeName) throws IOException;
+
+ /**
+ * Returns the name of the Alternate Exchange for the queue, or null if there isn't one.
+ *
+ * @since Qpid JMX API 2.4
+ * @return the name of the Alternate Exchange for the queue, or null if there isn't one
+ * @throws IOException
+ */
+ @MBeanAttribute(name="AlternateExchange", description="Alternate exchange for the queue")
+ String getAlternateExchange() throws IOException;
+
//********** Operations *****************//
diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
index 12ae69571e..9d40edd8d0 100644
--- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
+++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
@@ -47,7 +47,7 @@ public interface ServerInformation
* Qpid JMX API 1.1 can be assumed.
*/
int QPID_JMX_API_MAJOR_VERSION = 2;
- int QPID_JMX_API_MINOR_VERSION = 3;
+ int QPID_JMX_API_MINOR_VERSION = 4;
/**
diff --git a/qpid/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java b/qpid/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java
index 1a4a73f207..c931b921df 100644
--- a/qpid/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java
+++ b/qpid/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java
@@ -23,7 +23,6 @@ package org.apache.qpid.management.common.mbeans;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanAttributeInfo;
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
index 4a59176374..faa6769c63 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
@@ -47,7 +47,7 @@ public abstract class ApplicationRegistry
//max supported broker management interface supported by this release of the management console
public static final int SUPPORTED_QPID_JMX_API_MAJOR_VERSION = 2;
- public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 3;
+ public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 4;
public static final String DATA_DIR = System.getProperty("user.home") + File.separator + ".qpidmc";
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
index 417734e5fb..cc2e4290a0 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
@@ -579,7 +579,7 @@ public class NavigationView extends ViewPart
List<TreeObject> childNodes = typeNode.getChildren();
for (TreeObject child : childNodes)
{
- if (MBEAN.equals(child.getType()) && mbeanName.equals(child.getName()))
+ if (MBEAN.equals(child.getType()) && mbeanName != null && mbeanName.equals(child.getName()))
{
return true;
}
diff --git a/qpid/java/maven-settings.xml b/qpid/java/maven-settings.xml
index 985f39b6f1..0f2e3e6156 100644
--- a/qpid/java/maven-settings.xml
+++ b/qpid/java/maven-settings.xml
@@ -1,2 +1,22 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
<settings>
</settings>
diff --git a/qpid/java/systests/etc/global-default.txt b/qpid/java/systests/etc/global-default.txt
deleted file mode 100644
index 01b2c41809..0000000000
--- a/qpid/java/systests/etc/global-default.txt
+++ /dev/null
@@ -1,31 +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.
-#
-
-CONFIG expand=true
-
-# This section grants the admin user access to all management methods
-ACL ALLOW admin ALL METHOD
-
-# This section grants the client user access to all management methods except logging
-ACL DENY client ALL METHOD component="LoggingManagement"
-ACL ALLOW client ALL METHOD
-
-# This section grants the server user access to all management methods except configuration
-ACL DENY server ALL METHOD component="ConfigurationManagement"
-ACL ALLOW server ALL METHOD
diff --git a/qpid/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt b/qpid/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt
deleted file mode 100644
index a59b3176cb..0000000000
--- a/qpid/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt
+++ /dev/null
@@ -1,24 +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.
-#
-
-# This section denies the admin user access to logging
-ACL DENY admin UPDATE METHOD component="LoggingManagement" name="setRuntimeRootLoggerLevel"
-
-# This section grants the admin user access to management methods
-ACL ALLOW admin ALL METHOD
diff --git a/qpid/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt b/qpid/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt
deleted file mode 100644
index ff024b5ee8..0000000000
--- a/qpid/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt
+++ /dev/null
@@ -1,25 +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.
-#
-
-# This section denies the admin user access to logging methods
-ACL DENY admin ACCESS METHOD component="LoggingManagement" name="getAvailableLoggerLevels"
-
-# This section grants the admin user access to all management methods
-ACL ALLOW admin ALL METHOD
-
diff --git a/qpid/java/systests/etc/test-default.txt b/qpid/java/systests/etc/test-default.txt
deleted file mode 100644
index 95e733d077..0000000000
--- a/qpid/java/systests/etc/test-default.txt
+++ /dev/null
@@ -1,73 +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.
-#
-
-# This section grants virtualhost access rights
-ACL ALLOW client ACCESS VIRTUALHOST
-ACL ALLOW server ACCESS VIRTUALHOST
-
-# This section grants publish rights to an exchange + routing key pair
-
-# Allow clients to publish requests
-ACL ALLOW client PUBLISH EXCHANGE name="amq.direct" routingKey="example.RequestQueue"
-
-# Allow the processor to respond to a client on their Temporary Topic
-ACL ALLOW server PUBLISH EXCHANGE name="amq.direct" routingKey="tmp_*"
-ACL ALLOW server PUBLISH EXCHANGE name="amq.direct" routingKey="TempQueue*"
-
-# This section grants users the ability to consume from the broker
-
-# Allow client to consume from temporary queues
-ACL ALLOW client CONSUME QUEUE temporary=true
-
-# Only allow the server to consume from the Request Queue
-ACL ALLOW server CONSUME QUEUE name="example.RequestQueue"
-
-# Allow client and server to consume from kipper queues
-ACL ALLOW client CONSUME QUEUE name="clientid:kipper"
-ACL ALLOW server CONSUME QUEUE name="clientid:kipper"
-
-# This section grants users the ability to create/delete queues and exchanges
-
-# Allow clients to create and delete temporary and kipper queue on this exchange
-ACL ALLOW client CREATE QUEUE temporary=true
-ACL ALLOW client DELETE QUEUE temporary=true
-ACL ALLOW client CREATE QUEUE durable="true"
-ACL ALLOW client DELETE QUEUE durable="true"
-
-# Allow the server to create the Request Queue and kipper queue
-ACL ALLOW server CREATE QUEUE name="example.RequestQueue"
-ACL ALLOW server CREATE QUEUE name="clientid:kipper"
-
-## Allow client and server exchange access for the relevant queues
-ACL ALLOW client BIND EXCHANGE name="amq.direct" temporary=true
-ACL ALLOW client UNBIND EXCHANGE name="amq.direct" temporary=true
-ACL ALLOW client BIND EXCHANGE name="amq.direct" durable=true
-ACL ALLOW client UNBIND EXCHANGE name="amq.direct" durable=true
-ACL ALLOW server BIND EXCHANGE name="amq.direct" queueName="example.RequestQueue"
-
-## Allow client and server exchange access for the relevant topics
-ACL ALLOW client BIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
-ACL ALLOW client UNBIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
-ACL ALLOW server BIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
-
-# Action[operation=BIND,objectType=EXCHANGE,properties={OWNER=client, DURABLE=true, QUEUE_NAME=IllegalQueue, AUTO_DELETE=false, ROUTING_KEY=IllegalQueue, NAME=amq.direct, TEMPORARY=false, EXCLUSIVE=false}]
-
-
-ACL ALLOW client CREATE EXCHANGE
-ACL ALLOW server CREATE EXCHANGE
diff --git a/qpid/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt b/qpid/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt
deleted file mode 100644
index 197fe9dabe..0000000000
--- a/qpid/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt
+++ /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.
-#
-
-# This section grants virtualhost management rights
-ACL ALLOW admin ALL METHOD
-
-# testDeleteExchangeFailure()
-ACL ALLOW admin CREATE EXCHANGE name="amq.kipper.delete"
-ACL DENY admin DELETE EXCHANGE name="amq.kipper.delete"
-
diff --git a/qpid/java/systests/etc/test-externalacljmx.txt b/qpid/java/systests/etc/test-externalacljmx.txt
deleted file mode 100644
index f8a94bd44a..0000000000
--- a/qpid/java/systests/etc/test-externalacljmx.txt
+++ /dev/null
@@ -1,35 +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.
-#
-
-# This section grants management access to the virtualhost
-ACL ALLOW admin ALL METHOD
-ACL ALLOW client ALL METHOD
-ACL ALLOW server ALL METHOD
-
-# Allow create kipper queue
-ACL ALLOW admin CREATE QUEUE name="kipper" owner = client # kipper
-ACL ALLOW admin BIND EXCHANGE name="amq.direct"
-
-# testCreateExchangeSuccess(), testDeleteExchangeSuccess()
-ACL ALLOW admin CREATE EXCHANGE name="amq.kipper.success"
-ACL ALLOW admin DELETE EXCHANGE name="amq.kipper.success"
-
-# testCreateExchangeFailure()
-ACL DENY admin CREATE EXCHANGE name="amq.kipper.failure"
-
diff --git a/qpid/java/systests/etc/test-logging.txt b/qpid/java/systests/etc/test-logging.txt
deleted file mode 100644
index 76c6e442e0..0000000000
--- a/qpid/java/systests/etc/test-logging.txt
+++ /dev/null
@@ -1,23 +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.
-#
-
-ACL ALLOW client CREATE QUEUE name="allow"
-ACL ALLOW-LOG client CREATE QUEUE name="allow-log"
-ACL DENY client CREATE QUEUE name="deny"
-ACL DENY-LOG client CREATE QUEUE name="deny-log"
diff --git a/qpid/java/systests/etc/test2-default.txt b/qpid/java/systests/etc/test2-default.txt
deleted file mode 100644
index 0855e631d7..0000000000
--- a/qpid/java/systests/etc/test2-default.txt
+++ /dev/null
@@ -1,21 +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.
-#
-
-# This section grants all access rights
-ACL ALLOW guest ALL ALL \ No newline at end of file
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java
index 980fc7285d..99fcbc5dc0 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.client.failover;
import javax.jms.Destination;
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java
index a5b9c618bc..45aa6a0e18 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java
@@ -56,7 +56,7 @@ public class FailoverBehaviourTest extends FailoverBaseCase implements Connectio
private static boolean CLUSTERED = Boolean.getBoolean("profile.clustered");
/** Default number of messages to send before failover */
- private static final int DEFAULT_NUMBER_OF_MESSAGES = 10;
+ private static final int DEFAULT_NUMBER_OF_MESSAGES = 40;
/** Actual number of messages to send before failover */
protected int _messageNumber = Integer.getInteger("profile.failoverMsgCount", DEFAULT_NUMBER_OF_MESSAGES);
@@ -1157,7 +1157,6 @@ public class FailoverBehaviourTest extends FailoverBaseCase implements Connectio
{
init(acknowledgeMode, false);
_consumer.close();
- QueueBrowser browser = _consumerSession.createBrowser((Queue) _destination);
_connection.start();
produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false);
@@ -1165,6 +1164,8 @@ public class FailoverBehaviourTest extends FailoverBaseCase implements Connectio
{
_producerSession.commit();
}
+
+ QueueBrowser browser = _consumerSession.createBrowser((Queue) _destination);
return browser;
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
index c0b07f239b..d2950b095b 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
@@ -17,6 +17,26 @@ import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 PrefetchBehaviourTest extends QpidBrokerTestCase
{
protected static final Logger _logger = LoggerFactory.getLogger(PrefetchBehaviourTest.class);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java
new file mode 100644
index 0000000000..a8fa183cbe
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java
@@ -0,0 +1,50 @@
+package org.apache.qpid.client.redelivered;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class RedeliveredMessageTest extends QpidBrokerTestCase
+{
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+ }
+
+ public void testRedeliveredFlagOnSessionClose() throws Exception
+ {
+ Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Destination destination = session.createQueue(getTestQueueName());
+ MessageConsumer consumer = session.createConsumer(destination);
+
+ final int numberOfMessages = 3;
+ sendMessage(session, destination, numberOfMessages);
+
+ _connection.start();
+
+ for(int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = consumer.receive(1000l);
+ assertNotNull("Message is not recieved at " + i, m);
+ assertFalse("Redelivered should be not set", m.getJMSRedelivered());
+ }
+
+ session.close();
+ session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ destination = session.createQueue(getTestQueueName());
+ consumer = session.createConsumer(destination);
+
+ for(int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = consumer.receive(1000l);
+ assertNotNull("Message is not recieved at " + i, m);
+ assertTrue("Redelivered should be set", m.getJMSRedelivered());
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java
new file mode 100644
index 0000000000..97ba9afc32
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.management.jmx;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Tests the JMX API for the Managed Broker.
+ *
+ */
+public class ManagedBrokerMBeanTest extends QpidBrokerTestCase
+{
+ /**
+ * Test virtual host
+ */
+ private static final String VIRTUAL_HOST = "test";
+
+ /**
+ * Test exchange type
+ */
+ private static final String EXCHANGE_TYPE = "topic";
+
+ /**
+ * JMX helper.
+ */
+ private JMXTestUtils _jmxUtils;
+ private ManagedBroker _managedBroker;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+ super.setUp();
+ _jmxUtils.open();
+ _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Tests queue creation/deletion also verifying the automatic binding to the default exchange.
+ */
+ public void testCreateQueueAndDeletion() throws Exception
+ {
+ final String queueName = getTestQueueName();
+ final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString());
+
+ // Check that bind does not exist before queue creation
+ assertFalse("Binding to " + queueName + " should not exist in default exchange before queue creation",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+
+ _managedBroker.createNewQueue(queueName, "testowner", true);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ // Now verify that the default exchange has been bound.
+ assertTrue("Binding to " + queueName + " should exist in default exchange after queue creation",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+
+ // Now delete the queue
+ _managedBroker.deleteQueue(queueName);
+
+ // Finally ensure that the binding has been removed.
+ assertFalse("Binding to " + queueName + " should not exist in default exchange after queue deletion",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+ }
+
+ /**
+ * Tests exchange creation/deletion via JMX API.
+ */
+ public void testCreateExchangeAndUnregister() throws Exception
+ {
+ String exchangeName = getTestName();
+ _managedBroker.createNewExchange(exchangeName, "topic", true);
+ String queryString = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost="
+ + ObjectName.quote(VIRTUAL_HOST) + ",name=" + ObjectName.quote(exchangeName) + ",ExchangeType="
+ + EXCHANGE_TYPE;
+ ManagedExchange exchange = _jmxUtils.getManagedObject(ManagedExchange.class, queryString);
+ assertNotNull("Exchange should exist", exchange);
+
+ _managedBroker.unregisterExchange(exchangeName);
+ assertFalse("Exchange should have been removed", _jmxUtils.isManagedObjectExist(queryString));
+ }
+
+ /**
+ * Tests that it is disallowed to unregister the default exchange.
+ */
+ public void testUnregisterOfDefaultExchangeDisallowed() throws Exception
+ {
+ String defaultExchangeName = ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString();
+
+ try
+ {
+ _managedBroker.unregisterExchange(defaultExchangeName);
+ fail("Exception not thrown");
+ }
+ catch (MBeanException mbe)
+ {
+ // PASS
+ assertEquals("Error in unregistering exchange " + defaultExchangeName, mbe.getMessage());
+ assertTrue(mbe.getCause().getMessage().contains("Cannot unregister the default exchange"));
+ }
+ final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(defaultExchangeName);
+ assertNotNull("Exchange should exist", defaultExchange);
+ }
+
+ /**
+ * Tests queue creation with {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests
+ * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}.
+ */
+ public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Integer deliveryCount = 1;
+ final Map<String, Object> args = Collections.singletonMap(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount);
+ managedBroker.createNewQueue(queueName, "testowner", true, args);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount());
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java
new file mode 100644
index 0000000000..5f758061d5
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.management.jmx;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class ManagedConnectionMBeanTest extends QpidBrokerTestCase
+{
+ /**
+ * JMX helper.
+ */
+ private JMXTestUtils _jmxUtils;
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+ super.setUp();
+ _jmxUtils.open();
+ _connection = getConnection();
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ public void testChannels() throws Exception
+ {
+ final String queueName = getTestQueueName();
+
+ final Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ final Destination destination = session.createQueue(queueName);
+ final MessageConsumer consumer = session.createConsumer(destination);
+
+ final int numberOfMessages = 2;
+ sendMessage(session, destination, numberOfMessages);
+ _connection.start();
+
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = consumer.receive(1000l);
+ assertNotNull("Message " + i + " is not received", m);
+ }
+
+ List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test");
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+
+ TabularData channelsData = mBean.channels();
+ assertNotNull("Channels data are null", channelsData);
+ assertEquals("Unexpected number of rows in channel table", 1, channelsData.size());
+
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator();
+ final CompositeDataSupport row = rowItr.next();
+ Number unackCount = (Number) row.get(ManagedConnection.UNACKED_COUNT);
+ final Boolean transactional = (Boolean) row.get(ManagedConnection.TRANSACTIONAL);
+ final Boolean flowBlocked = (Boolean) row.get(ManagedConnection.FLOW_BLOCKED);
+ assertNotNull("Channel should have unacknowledged messages", unackCount);
+ assertEquals("Unexpected number of unacknowledged messages", 2, unackCount.intValue());
+ assertNotNull("Channel should have transaction flag", transactional);
+ assertTrue("Unexpected transaction flag", transactional);
+ assertNotNull("Channel should have flow blocked flag", flowBlocked);
+ assertFalse("Unexpected value of flow blocked flag", flowBlocked);
+
+ final Date initialLastIOTime = mBean.getLastIoTime();
+ session.commit();
+ assertTrue("Last IO time should have been updated", mBean.getLastIoTime().after(initialLastIOTime));
+
+ channelsData = mBean.channels();
+ assertNotNull("Channels data are null", channelsData);
+ assertEquals("Unexpected number of rows in channel table", 1, channelsData.size());
+
+ final Iterator<CompositeDataSupport> rowItr2 = (Iterator<CompositeDataSupport>) channelsData.values().iterator();
+ final CompositeDataSupport row2 = rowItr2.next();
+ unackCount = (Number) row2.get(ManagedConnection.UNACKED_COUNT);
+ assertNotNull("Channel should have unacknowledged messages", unackCount);
+ assertEquals("Unexpected number of anacknowledged messages", 0, unackCount.intValue());
+
+ _connection.close();
+
+ connections = _jmxUtils.getManagedConnections("test");
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 0, connections.size());
+ }
+
+ public void testCommit() throws Exception
+ {
+ final String queueName = getTestQueueName();
+
+ final Session consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ final Destination destination = producerSession.createQueue(queueName);
+ final MessageConsumer consumer = consumerSession.createConsumer(destination);
+ final MessageProducer producer = producerSession.createProducer(destination);
+
+ _connection.start();
+
+ List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test");
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+
+ final int numberOfMessages = 2;
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ producer.send(producerSession.createTextMessage("Test " + i));
+ }
+
+ // sync to make sure that messages are received on the broker
+ // before we commit via JMX
+ ((AMQSession<?, ?>) producerSession).sync();
+
+ Message m = consumer.receive(500l);
+ assertNull("Unexpected message received", m);
+
+ Number channelId = getFirstTransactedChannelId(mBean, 2);
+ mBean.commitTransactions(channelId.intValue());
+
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message " + i + " is not received", m);
+ assertEquals("Unexpected message received at " + i, "Test " + i, ((TextMessage) m).getText());
+ }
+ producerSession.commit();
+ m = consumer.receive(500l);
+ assertNull("Unexpected message received", m);
+ }
+
+ protected Number getFirstTransactedChannelId(final ManagedConnection mBean, int channelNumber) throws IOException, JMException
+ {
+ TabularData channelsData = mBean.channels();
+ assertNotNull("Channels data are null", channelsData);
+ assertEquals("Unexpected number of rows in channel table", channelNumber, channelsData.size());
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator();
+ while (rowItr.hasNext())
+ {
+ final CompositeDataSupport row = rowItr.next();
+ Boolean transacted = (Boolean) row.get(ManagedConnection.TRANSACTIONAL);
+ if (transacted.booleanValue())
+ {
+ return (Number) row.get(ManagedConnection.CHAN_ID);
+ }
+ }
+ return null;
+ }
+
+ public void testRollback() throws Exception
+ {
+ final String queueName = getTestQueueName();
+
+ final Session consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ final Destination destination = producerSession.createQueue(queueName);
+ final MessageConsumer consumer = consumerSession.createConsumer(destination);
+ final MessageProducer producer = producerSession.createProducer(destination);
+
+ List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test");
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+
+ final int numberOfMessages = 2;
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ producer.send(producerSession.createTextMessage("Test " + i));
+ }
+
+ // sync to make sure that messages are received on the broker
+ // before we rollback via JMX
+ ((AMQSession<?, ?>) producerSession).sync();
+
+ Number channelId = getFirstTransactedChannelId(mBean, 2);
+ mBean.rollbackTransactions(channelId.intValue());
+
+ Message m = consumer.receive(1000l);
+ assertNull("Unexpected message received", m);
+
+ producerSession.commit();
+
+ _connection.start();
+ m = consumer.receive(1000l);
+ assertNull("Unexpected message received", m);
+ }
+
+ public void testAuthorisedId() throws Exception
+ {
+ List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test");
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+ assertEquals("Unexpected authorized id", "guest", mBean.getAuthorizedId());
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java
new file mode 100644
index 0000000000..0e60cc5d8f
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.management.jmx;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.Connection;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+
+import org.apache.commons.lang.time.FastDateFormat;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.server.queue.AMQQueueMBean;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Tests the JMX API for the Managed Queue.
+ *
+ */
+public class ManagedQueueMBeanTest extends QpidBrokerTestCase
+{
+ /**
+ * JMX helper.
+ */
+ private JMXTestUtils _jmxUtils;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+ super.setUp();
+ _jmxUtils.open();
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Tests {@link ManagedQueue#viewMessages(long, long)} interface.
+ */
+ public void testViewSingleMessage() throws Exception
+ {
+ final String queueName = getTestQueueName();
+
+ // Create queue and send numMessages messages to it.
+ final Connection con = getConnection();
+ final Session session = con.createSession(true, Session.SESSION_TRANSACTED);
+ final Destination dest = session.createQueue(queueName);
+ session.createConsumer(dest).close(); // Create a consumer only to cause queue creation
+
+ final List<Message> sentMessages = sendMessage(session, dest, 1);
+ final Message sentMessage = sentMessages.get(0);
+
+ // Obtain the management interface.
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNotNull("ManagedQueue expected to be available", managedQueue);
+ assertEquals("Unexpected queue depth", 1, managedQueue.getMessageCount().intValue());
+
+ // Check the contents of the message
+ final TabularData tab = managedQueue.viewMessages(1l, 1l);
+ assertEquals("Unexpected number of rows in table", 1, tab.size());
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) tab.values().iterator();
+
+ final CompositeDataSupport row1 = rowItr.next();
+ assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID));
+ assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS));
+ assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED));
+
+ // Check the contents of header (encoded in a string array)
+ final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER);
+ assertNotNull("Expected message header array", headerArray);
+ final Map<String, String> headers = headerArrayToMap(headerArray);
+
+ final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID();
+ final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(AMQQueueMBean.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp());
+ assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID"));
+ assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority"));
+ assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp"));
+ }
+
+ /**
+ *
+ * Utility method to convert array of Strings in the form x = y into a
+ * map with key/value x =&gt; y.
+ *
+ */
+ private Map<String,String> headerArrayToMap(final String[] headerArray)
+ {
+ final Map<String, String> headerMap = new HashMap<String, String>();
+ final List<String> headerList = Arrays.asList(headerArray);
+ for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();)
+ {
+ final String nameValuePair = iterator.next();
+ final String[] nameValue = nameValuePair.split(" *= *", 2);
+ headerMap.put(nameValue[0], nameValue[1]);
+ }
+ return headerMap;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
index 12a1682212..0e2875235f 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
@@ -45,12 +45,11 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
{
private JMXTestUtils _jmxUtils;
private boolean _closed = false;
- private static final String USER = "admin";
@Override
public void setUp() throws Exception
{
- _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils = new JMXTestUtils(this);
_jmxUtils.setUp();
super.setUp();
_jmxUtils.open();
@@ -364,7 +363,7 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
List<String> results = waitAndFindMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
String log = getLogMessage(results, 0);
@@ -391,7 +390,7 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
List<String> results = waitAndFindMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
String log = getLogMessage(results, 0);
@@ -418,7 +417,7 @@ public class ManagementActorLoggingTest extends AbstractTestLogging
List<String> results = waitAndFindMatches("BND-1001");
- assertEquals("More than one bind creation found", 1, results.size());
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
String log = getLogMessage(results, 0);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
deleted file mode 100644
index fd33266414..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
+++ /dev/null
@@ -1,336 +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.failover;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.protocol.AMQProtocolSession;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.test.utils.FailoverBaseCase;
-
-import javax.jms.Destination;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test case based on user reported error.
- *
- * Summary:
- * A user has reported message loss from their application. On bouncing of
- * the broker the 'lost' messages are delivered to the broker.
- *
- * Note:
- * The client was using Spring so that may influence the situation.
- *
- * Issue:
- * The log files show 7 instances of the following which result in 7
- * missing messages.
- *
- * The client log files show:
- *
- * The broker log file show:
- *
- *
- * 7 missing messages have delivery tags 5-11. Which says that they are
- * sequentially the next message from the broker.
- *
- * The only way for the 'without a handler' log to occur is if the consumer
- * has been removed from the look up table of the dispatcher.
- * And the only way for the 'null message' log to occur on the broker is is
- * if the message does not exist in the unacked-map
- *
- * The consumer is only removed from the list during session
- * closure and failover.
- *
- * If the session was closed then the broker would requeue the unacked
- * messages so the potential exists to have an empty map but the broker
- * will not send a message out after the unacked map has been cleared.
- *
- * When failover occurs the _consumer map is cleared and the consumers are
- * resubscribed. This is down without first stopping any existing
- * dispatcher so there exists the potential to receive a message after
- * the _consumer map has been cleared which is how the 'without a handler'
- * log statement occurs.
- *
- * Scenario:
- *
- * Looking over logs the sequence that best fits the events is as follows:
- * - Something causes Mina to be delayed causing the WriteTimoutException.
- * - This exception is recevied by AMQProtocolHandler#exceptionCaught
- * - As the WriteTimeoutException is an IOException this will cause
- * sessionClosed to be called to start failover.
- * + This is potentially the issues here. All IOExceptions are treated
- * as connection failure events.
- * - Failover Runs
- * + Failover assumes that the previous connection has been closed.
- * + Failover binds the existing objects (AMQConnection/Session) to the
- * new connection objects.
- * - Everything is reported as being successfully failed over.
- * However, what is neglected is that the original connection has not
- * been closed.
- * + So what occurs is that the broker sends a message to the consumer on
- * the original connection, as it was not notified of the client
- * failing over.
- * As the client failover reuses the original AMQSession and Dispatcher
- * the new messages the broker sends to the old consumer arrives at the
- * client and is processed by the same AMQSession and Dispatcher.
- * However, as the failover process cleared the _consumer map and
- * resubscribe the consumers the Dispatcher does not recognise the
- * delivery tag and so logs the 'without a handler' message.
- * - The Dispatcher then attempts to reject the message, however,
- * + The AMQSession/Dispatcher pair have been swapped to using a new Mina
- * ProtocolSession as part of the failover process so the reject is
- * sent down the second connection. The broker receives the Reject
- * request but as the Message was sent on a different connection the
- * unacknowledgemap is empty and a 'message is null' log message
- * produced.
- *
- * Test Strategy:
- *
- * It should be easy to demonstrate if we can send an IOException to
- * AMQProtocolHandler#exceptionCaught and then try sending a message.
- *
- * The current unknowns here are the type of consumers that are in use.
- * If it was an exclusive queue(Durable Subscription) then why did the
- * resubscribe not fail.
- *
- * If it was not exclusive then why did the messages not round robin?
- */
-public class MessageDisappearWithIOExceptionTest extends FailoverBaseCase implements ConnectionListener
-{
- private CountDownLatch _failoverOccured = new CountDownLatch(1);
- AMQConnection _connection;
- Session _session;
- Queue _queue;
- MessageConsumer _consumer;
-
- public void setUp() throws Exception
- {
- super.setUp();
- stopBroker(getFailingPort());
-
- }
-
- /**
- * Test Summary:
- *
- * Create a queue consumer and send 10 messages to the broker.
- *
- * Consume the first message.
- * This will pull the rest into the prefetch
- *
- * Send an IOException to the MinaProtocolHandler.
- *
- * This will force failover to occur.
- *
- * 9 messages would normally be expected but it is expected that none will
- * arrive. As they are still in the prefetch of the first session.
- *
- * To free the messages we need to close all connections.
- * - Simply doing connection.close() and retesting will not be enough as
- * the original connection's IO layer will still exist and is nolonger
- * connected to the connection object as a result of failover.
- *
- * - Test will need to retain a reference to the original connection IO so
- * that it can be closed releasing the messages to validate that the
- * messages have indeed been 'lost' on that sesssion.
- */
- public void test() throws Exception
- {
- initialiseConnection();
-
- // Create Producer
- // Send 10 messages
- List<Message> messages = sendNumberedBytesMessage(_session, _queue, 10);
-
- // Consume first messasge
- Message received = _consumer.receive(2000);
-
- // Verify received messages
- assertNotNull("First message not received.", received);
- assertEquals("Incorrect message Received",
- messages.remove(0).getIntProperty("count"),
- received.getIntProperty("count"));
-
- // When the Exception is received by the underlying IO layer it will
- // initiate failover. The first step of which is to ensure that the
- // existing conection is closed. So in this situation the connection
- // will be flushed casuing the above ACK to be sent to the broker.
- //
- // That said:
- // when the socket close is detected on the server it will rise up the
- // Mina filter chain and interrupt processing.
- // this has been raised as QPID-2138
- _session.createConsumer(_session.createTemporaryQueue()).close();
-
- //Retain IO Layer
- AMQProtocolSession protocolSession = _connection.getProtocolHandler().getProtocolSession();
-
- // Send IO Exception - causing failover
- _connection.getProtocolHandler().
- exception(new IOException("IOException to cause failover."));
-
- // Verify Failover occured through ConnectionListener
- assertTrue("Failover did not occur",
- _failoverOccured.await(4000, TimeUnit.MILLISECONDS));
-
- /***********************************/
- // This verifies that the bug has been resolved
-
- // Attempt to consume again. Expect 9 messages
- for (int count = 1; count < 10; count++)
- {
- received = _consumer.receive(2000);
- assertNotNull("Expected message not received:" + count, received);
- assertEquals(messages.remove(0).getIntProperty("count"),
- received.getIntProperty("count"));
- }
-
- //Verify there are no more messages
- received = _consumer.receive(1000);
- assertNull("Message receieved when there should be none:" + received,
- received);
-
-// /***********************************/
-// // This verifies that the bug exists
-//
-// // Attempt to consume remaining 9 messages.. Expecting NONE.
-// // receiving just one message should fail so no need to fail 9 times
-// received = _consumer.receive(1000);
-// assertNull("Message receieved when it should be null:" + received, received);
-//
-//// //Close the Connection which you would assume would free the messages
-//// _connection.close();
-////
-//// // Reconnect
-//// initialiseConnection();
-////
-//// // We should still be unable to receive messages
-//// received = _consumer.receive(1000);
-//// assertNull("Message receieved when it should be null:" + received, received);
-////
-//// _connection.close();
-//
-// // Close original IO layer. Expecting messages to be released
-// protocolSession.closeProtocolSession();
-//
-// // Reconnect and all should be good.
-//// initialiseConnection();
-//
-// // Attempt to consume again. Expect 9 messages
-// for (int count = 1; count < 10; count++)
-// {
-// received = _consumer.receive(2000);
-// assertNotNull("Expected message not received:" + count, received);
-// assertEquals(messages.remove(0).getIntProperty("count"),
-// received.getIntProperty("count"));
-// }
-//
-// //Verify there are no more messages
-// received = _consumer.receive(1000);
-// assertNull("Message receieved when there should be none:" + received,
-// received);
- }
-
- private void initialiseConnection()
- throws Exception
- {
- //Create Connection using the default connection URL. i.e. not the Failover URL that would be used by default
- _connection = (AMQConnection) getConnectionFactory("default").createConnection("guest", "guest");
- // The default connection does not have any retries configured so
- // Allow this connection to retry so that we can block on the failover.
- // The alternative would be to use the getConnection() default. However,
- // this would add additional complexity in the logging as a second
- // broker is defined in that url. We do not need it for this test.
- _connection.getFailoverPolicy().getCurrentMethod().setRetries(1);
- _connection.setConnectionListener(this);
-
- _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- _queue = _session.createQueue(getTestQueueName());
-
- // Create Consumer
- _consumer = _session.createConsumer(_queue);
-
- //Start connection
- _connection.start();
- }
-
- /** QpidTestCase back port to this release */
-
- // modified from QTC as sendMessage is not testable.
- // - should be renamed sendBlankBytesMessage
- // - should be renamed sendNumberedBytesMessage
- public List<Message> sendNumberedBytesMessage(Session session, Destination destination,
- int count) throws Exception
- {
- List<Message> messages = new ArrayList<Message>(count);
-
- MessageProducer producer = session.createProducer(destination);
-
- for (int i = 0; i < count; i++)
- {
- Message next = session.createMessage();
-
- next.setIntProperty("count", i);
-
- producer.send(next);
-
- messages.add(next);
- }
-
- producer.close();
- return messages;
- }
-
- public void bytesSent(long count)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void bytesReceived(long count)
- {
- }
-
- public boolean preFailover(boolean redirect)
- {
- //Allow failover to occur
- return true;
- }
-
- public boolean preResubscribe()
- {
- //Allow failover to occur
- return true;
- }
-
- public void failoverComplete()
- {
- _failoverOccured.countDown();
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
index 2629e82831..e7da4472f5 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
@@ -18,7 +18,6 @@
*/
package org.apache.qpid.server.logging;
-import java.io.File;
import java.util.List;
import javax.jms.Connection;
@@ -29,6 +28,7 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
/**
* ACL version 2/3 file testing to verify that ACL actor logging works correctly.
@@ -49,13 +49,18 @@ public class AccessControlLoggingTest extends AbstractTestLogging
public void setUp() throws Exception
{
- setConfigurationProperty("virtualhosts.virtualhost.test.security.aclv2",
- QpidHome + File.separator + "etc" + File.separator + "test-logging.txt");
-
+ // Write out ACL for this test
+ AbstractACLTestCase.writeACLFileUtil(this, "test",
+ "ACL ALLOW client ACCESS VIRTUALHOST",
+ "ACL ALLOW client CREATE QUEUE name='allow'",
+ "ACL ALLOW-LOG client CREATE QUEUE name='allow-log'",
+ "ACL DENY client CREATE QUEUE name='deny'",
+ "ACL DENY-LOG client CREATE QUEUE name='deny-log'");
+
super.setUp();
+
}
- /** FIXME This comes from SimpleACLTest and makes me suspicious. */
@Override
public void tearDown() throws Exception
{
@@ -69,7 +74,7 @@ public class AccessControlLoggingTest extends AbstractTestLogging
//that we provoked with authentication failures, where the test passes - we can ignore on con close
}
}
-
+
/**
* Test that {@code allow} ACL entries do not log anything.
*/
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
index 24e6aa4207..ed9109ebba 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
@@ -20,9 +20,9 @@
*/
package org.apache.qpid.server.logging;
-import junit.framework.AssertionFailedError;
import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.test.utils.JMXTestUtils;
import org.apache.qpid.util.LogMonitor;
import java.util.List;
@@ -41,6 +41,8 @@ import java.io.File;
* MNG-1004 : Ready
* MNG-1005 : Stopped
* MNG-1006 : Using SSL Keystore : <path>
+ * MNG-1007 : Open : User <username>
+ * MNG-1008 : Close : User <username>
*/
public class ManagementLoggingTest extends AbstractTestLogging
{
@@ -86,33 +88,24 @@ public class ManagementLoggingTest extends AbstractTestLogging
waitForMessage("MNG-1001");
List<String> results = findMatches(MNG_PREFIX);
-
- try
- {
- // Validation
+ // Validation
- assertTrue("MNGer message not logged", results.size() > 0);
+ assertTrue("MNGer message not logged", results.size() > 0);
- String log = getLogMessage(results, 0);
+ String log = getLogMessage(results, 0);
- //1
- validateMessageID("MNG-1001", log);
+ //1
+ validateMessageID("MNG-1001", log);
- //2
- //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J)
- results = findMatches("MNG-1001");
- assertEquals("Unexpected startup message count.",
- 2, results.size());
+ //2
+ //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J)
+ results = findMatches("MNG-1001");
+ assertEquals("Unexpected startup message count.",
+ 2, results.size());
- //3
- assertEquals("Startup log message is not 'Startup'.", "Startup",
- getMessageString(log));
- }
- catch (AssertionFailedError afe)
- {
- dumpLogs(results, _monitor);
- throw afe;
- }
+ //3
+ assertEquals("Startup log message is not 'Startup'.", "Startup",
+ getMessageString(log));
}
}
@@ -135,17 +128,9 @@ public class ManagementLoggingTest extends AbstractTestLogging
startBrokerAndCreateMonitor(false, false);
List<String> results = findMatches(MNG_PREFIX);
- try
- {
- // Validation
+ // Validation
- assertEquals("MNGer messages logged", 0, results.size());
- }
- catch (AssertionFailedError afe)
- {
- dumpLogs(results, _monitor);
- throw afe;
- }
+ assertEquals("MNGer messages logged", 0, results.size());
}
}
@@ -194,39 +179,31 @@ public class ManagementLoggingTest extends AbstractTestLogging
startBrokerAndCreateMonitor(true, false);
List<String> results = waitAndFindMatches("MNG-1002");
- try
- {
- // Validation
+ // Validation
- //There will be 4 startup messages (two via SystemOut, and two via Log4J)
- assertEquals("Unexpected MNG-1002 message count", 4, results.size());
+ //There will be 4 startup messages (two via SystemOut, and two via Log4J)
+ assertEquals("Unexpected MNG-1002 message count", 4, results.size());
- String log = getLogMessage(results, 0);
+ String log = getLogMessage(results, 0);
- //1
- validateMessageID("MNG-1002", log);
+ //1
+ validateMessageID("MNG-1002", log);
- //Check the RMI Registry port is as expected
- int mPort = getManagementPort(getPort());
- assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log),
- getMessageString(log).endsWith(String.valueOf(mPort)));
+ //Check the RMI Registry port is as expected
+ int mPort = getManagementPort(getPort());
+ assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(mPort)));
- log = getLogMessage(results, 2);
+ log = getLogMessage(results, 2);
- //1
- validateMessageID("MNG-1002", log);
+ //1
+ validateMessageID("MNG-1002", log);
- // We expect the RMI Registry port (the defined 'management port') to be
- // 100 lower than the JMX RMIConnector Server Port (the actual JMX server)
- int jmxPort = mPort + ServerConfiguration.JMXPORT_CONNECTORSERVER_OFFSET;
- assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log),
- getMessageString(log).endsWith(String.valueOf(jmxPort)));
- }
- catch (AssertionFailedError afe)
- {
- dumpLogs(results, _monitor);
- throw afe;
- }
+ // We expect the RMI Registry port (the defined 'management port') to be
+ // 100 lower than the JMX RMIConnector Server Port (the actual JMX server)
+ int jmxPort = mPort + ServerConfiguration.JMXPORT_CONNECTORSERVER_OFFSET;
+ assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(jmxPort)));
}
}
@@ -251,35 +228,75 @@ public class ManagementLoggingTest extends AbstractTestLogging
startBrokerAndCreateMonitor(true, true);
List<String> results = waitAndFindMatches("MNG-1006");
- try
- {
- // Validation
- assertTrue("MNGer message not logged", results.size() > 0);
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLogMessage(results, 0);
- String log = getLogMessage(results, 0);
+ //1
+ validateMessageID("MNG-1006", log);
- //1
- validateMessageID("MNG-1006", log);
+ // Validate we only have two MNG-1002 (one via stdout, one via log4j)
+ results = findMatches("MNG-1006");
+ assertEquals("Upexpected SSL Keystore message count",
+ 2, results.size());
+
+ // Validate the keystore path is as expected
+ assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
+ getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName()));
+ }
+ }
- // Validate we only have two MNG-1002 (one via stdout, one via log4j)
- results = findMatches("MNG-1006");
- assertEquals("Upexpected SSL Keystore message count",
- 2, results.size());
+ /**
+ * Description: Tests the management connection open/close are logged correctly.
+ *
+ * Output:
+ *
+ * <date> MESSAGE MNG-1007 : Open : User <username>
+ * <date> MESSAGE MNG-1008 : Close : User <username>
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The message and username are correct
+ */
+ public void testManagementUserOpenClose() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
- // Validate the keystore path is as expected
- assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
- getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName()));
+ final JMXTestUtils jmxUtils = new JMXTestUtils(this);
+ List<String> openResults = null;
+ List<String> closeResults = null;
+ try
+ {
+ jmxUtils.setUp();
+ jmxUtils.open();
+ openResults = waitAndFindMatches("MNG-1007");
}
- catch (AssertionFailedError afe)
+ finally
{
- dumpLogs(results, _monitor);
- throw afe;
+ if (jmxUtils != null)
+ {
+ jmxUtils.close();
+ closeResults = waitAndFindMatches("MNG-1008");
+ }
}
- }
+ assertNotNull("Management Open results null", openResults.size());
+ assertEquals("Management Open logged unexpected number of times", 1, openResults.size());
+
+ assertNotNull("Management Close results null", closeResults.size());
+ assertEquals("Management Close logged unexpected number of times", 1, closeResults.size());
+
+ final String openMessage = getMessageString(getLogMessage(openResults, 0));
+ assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin"));
+ final String closeMessage = getMessageString(getLogMessage(closeResults, 0));
+ assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin"));
+ }
}
-
+
private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception
{
//Ensure management is on
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
index e3fd042560..ddc51f69bd 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
@@ -60,7 +60,6 @@ import java.lang.reflect.UndeclaredThrowableException;
public class ModelTest extends QpidBrokerTestCase
{
- private static final String USER = "admin";
private JMXTestUtils _jmxUtils;
private static final String VIRTUALHOST_NAME = "test";
@@ -68,7 +67,7 @@ public class ModelTest extends QpidBrokerTestCase
public void setUp() throws Exception
{
// Create a JMX Helper
- _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils = new JMXTestUtils(this);
_jmxUtils.setUp();
super.setUp();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java
index 2ce1251eab..962aec0d1e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java
@@ -20,35 +20,26 @@
*/
package org.apache.qpid.server.queue;
-import junit.framework.TestCase;
-import junit.framework.Assert;
-import org.apache.log4j.Logger;
-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.test.utils.QpidBrokerTestCase;
-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;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.NamingException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
-public class PriorityTest extends QpidBrokerTestCase
+public class PriorityQueueTest extends QpidBrokerTestCase
{
private static final int TIMEOUT = 1500;
-
- private static final Logger _logger = Logger.getLogger(PriorityTest.class);
-
protected final String QUEUE = "PriorityQueue";
private static final int MSG_COUNT = 50;
@@ -60,9 +51,8 @@ public class PriorityTest extends QpidBrokerTestCase
private Connection consumerConnection;
private Session consumerSession;
-
private MessageConsumer consumer;
-
+
protected void setUp() throws Exception
{
super.setUp();
@@ -71,10 +61,10 @@ public class PriorityTest extends QpidBrokerTestCase
producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE);
producerConnection.start();
-
+
consumerConnection = getConnection();
consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
+
}
protected void tearDown() throws Exception
@@ -111,7 +101,7 @@ public class PriorityTest extends QpidBrokerTestCase
Message previous = null;
int messageCount = 0;
while((received = consumer.receive(1000))!=null)
- {
+ {
messageCount++;
if(previous != null)
{
@@ -124,17 +114,17 @@ public class PriorityTest extends QpidBrokerTestCase
assertEquals("Incorrect number of message received", 50, receivedCount);
}
-
+
public void testOddOrdering() throws AMQException, JMSException
{
final Map<String,Object> arguments = new HashMap<String, Object>();
arguments.put("x-qpid-priorities",3);
((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
queue = producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
-
+
((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
producer = producerSession.createProducer(queue);
-
+
// In order ABC
producer.setPriority(9);
producer.send(nextMessage(1, false, producerSession, producer));
@@ -151,14 +141,14 @@ public class PriorityTest extends QpidBrokerTestCase
producer.setPriority(1);
producer.send(nextMessage(6, false, producerSession, producer));
- // Out of order BCA
+ // Out of order BCA
producer.setPriority(4);
producer.send(nextMessage(7, false, producerSession, producer));
producer.setPriority(1);
producer.send(nextMessage(8, false, producerSession, producer));
producer.setPriority(9);
producer.send(nextMessage(9, false, producerSession, producer));
-
+
// Reverse order CBA
producer.setPriority(1);
producer.send(nextMessage(10, false, producerSession, producer));
@@ -167,10 +157,10 @@ public class PriorityTest extends QpidBrokerTestCase
producer.setPriority(9);
producer.send(nextMessage(12, false, producerSession, producer));
producerSession.commit();
-
+
consumer = consumerSession.createConsumer(queue);
consumerConnection.start();
-
+
Message msg = consumer.receive(TIMEOUT);
assertEquals(1, msg.getIntProperty("msg"));
msg = consumer.receive(TIMEOUT);
@@ -179,7 +169,7 @@ public class PriorityTest extends QpidBrokerTestCase
assertEquals(9, msg.getIntProperty("msg"));
msg = consumer.receive(TIMEOUT);
assertEquals(12, msg.getIntProperty("msg"));
-
+
msg = consumer.receive(TIMEOUT);
assertEquals(2, msg.getIntProperty("msg"));
msg = consumer.receive(TIMEOUT);
@@ -188,7 +178,7 @@ public class PriorityTest extends QpidBrokerTestCase
assertEquals(7, msg.getIntProperty("msg"));
msg = consumer.receive(TIMEOUT);
assertEquals(11, msg.getIntProperty("msg"));
-
+
msg = consumer.receive(TIMEOUT);
assertEquals(3, msg.getIntProperty("msg"));
msg = consumer.receive(TIMEOUT);
@@ -206,6 +196,4 @@ public class PriorityTest extends QpidBrokerTestCase
return send;
}
-
-
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
index a724e6c66e..775d2c3eb0 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
@@ -55,11 +55,10 @@ public class ProducerFlowControlTest extends AbstractTestLogging
private JMXTestUtils _jmxUtils;
private boolean _jmxUtilConnected;
- private static final String USER = "admin";
public void setUp() throws Exception
{
- _jmxUtils = new JMXTestUtils(this, USER , USER);
+ _jmxUtils = new JMXTestUtils(this);
_jmxUtils.setUp();
_jmxUtilConnected=false;
super.setUp();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java
new file mode 100644
index 0000000000..bf4dbcb19f
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java
@@ -0,0 +1,523 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class SortedQueueTest extends QpidBrokerTestCase
+{
+ private static final Logger LOGGER = Logger.getLogger(SortedQueueTest.class);
+ public static final String TEST_SORT_KEY = "testSortKey";
+ private static final String VALUES[] = SortedQueueEntryListTest.keys.clone();
+ private static final String VALUES_SORTED[] = SortedQueueEntryListTest.keys.clone();
+ public final static String SUBSET_KEYS[] = { "000", "100", "200", "300", "400", "500", "600", "700", "800", "900" };
+
+ private Connection _producerConnection;
+ private Session _producerSession;
+ private Connection _consumerConnection;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1");
+ // Sort value array to generated "expected" order of messages.
+ Arrays.sort(VALUES_SORTED);
+ _producerConnection = getConnection();
+ _consumerConnection = getConnection();
+ _producerSession = _producerConnection.createSession(true, Session.SESSION_TRANSACTED);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _producerSession.close();
+ _producerConnection.close();
+ _consumerConnection.close();
+ super.tearDown();
+ }
+
+ public void testSortOrder() throws JMSException, NamingException, AMQException
+ {
+ final Queue queue = createQueue();
+ final MessageProducer producer = _producerSession.createProducer(queue);
+
+ for(String value : VALUES)
+ {
+ final Message msg = _producerSession.createTextMessage("Message Text:" + value);
+ msg.setStringProperty(TEST_SORT_KEY, value);
+ producer.send(msg);
+ }
+
+ _producerSession.commit();
+ producer.close();
+
+ final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final MessageConsumer consumer = consumerSession.createConsumer(queue);
+ _consumerConnection.start();
+ TextMessage received;
+ int messageCount = 0;
+ while((received = (TextMessage) consumer.receive(1000)) != null)
+ {
+ assertEquals("Received message with unexpected sorted key value", VALUES_SORTED[messageCount],
+ received.getStringProperty(TEST_SORT_KEY));
+ assertEquals("Received message with unexpected message value",
+ "Message Text:" + VALUES_SORTED[messageCount], received.getText());
+ messageCount++;
+ }
+
+ assertEquals("Incorrect number of messages received", VALUES.length, messageCount);
+ }
+
+ public void testAutoAckSortedQueue() throws JMSException, NamingException, AMQException
+ {
+ runThroughSortedQueueForSessionMode(Session.AUTO_ACKNOWLEDGE);
+ }
+
+ public void testTransactedSortedQueue() throws JMSException, NamingException, AMQException
+ {
+ runThroughSortedQueueForSessionMode(Session.SESSION_TRANSACTED);
+ }
+
+ public void testClientAckSortedQueue() throws JMSException, NamingException, AMQException
+ {
+ runThroughSortedQueueForSessionMode(Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ private void runThroughSortedQueueForSessionMode(final int sessionMode) throws JMSException, NamingException,
+ AMQException
+ {
+ final Queue queue = createQueue();
+ final MessageProducer producer = _producerSession.createProducer(queue);
+
+ final TestConsumerThread consumerThread = new TestConsumerThread(sessionMode, queue);
+ consumerThread.start();
+ final Calendar cal = Calendar.getInstance(Locale.UK);
+
+ for(String value : VALUES)
+ {
+ final Message msg = _producerSession.createTextMessage(String.valueOf(cal.getTimeInMillis()));
+ msg.setStringProperty(TEST_SORT_KEY, value);
+ producer.send(msg);
+ _producerSession.commit();
+ }
+
+ synchronized(consumerThread)
+ {
+ try
+ {
+ consumerThread.join(5000L);
+ }
+ catch(InterruptedException e)
+ {
+ fail("Test failed waiting for consumer to complete");
+ }
+ }
+ assertTrue("Consumer timed out", consumerThread.isStopped());
+ assertEquals("Incorrect number of messages received", VALUES.length, consumerThread.getConsumed());
+
+ producer.close();
+ }
+
+ public void testSortedQueueWithAscendingSortedKeys() throws JMSException, NamingException, AMQException
+ {
+ final Queue queue = createQueue();
+ final MessageProducer producer = _producerSession.createProducer(queue);
+
+ final TestConsumerThread consumerThread = new TestConsumerThread(Session.AUTO_ACKNOWLEDGE, queue);
+ consumerThread.start();
+
+ for(int i = 0; i < 200; i++)
+ {
+ final String ascendingKey = AscendingSortedKeys.getNextKey();
+ final Message msg = _producerSession.createTextMessage("Message Text:" + ascendingKey);
+ msg.setStringProperty(TEST_SORT_KEY, ascendingKey);
+ producer.send(msg);
+ _producerSession.commit();
+ }
+
+ synchronized(consumerThread)
+ {
+ try
+ {
+ consumerThread.join(5000L);
+ }
+ catch(InterruptedException e)
+ {
+ fail("Test failed waiting for consumer to complete");
+ }
+ }
+ assertTrue("Consumer timed out", consumerThread.isStopped());
+ assertEquals("Incorrect number of messages received", 200, consumerThread.getConsumed());
+
+ producer.close();
+ }
+
+ public void testSortOrderWithNonUniqueKeys() throws JMSException, NamingException, AMQException
+ {
+ final Queue queue = createQueue();
+ final MessageProducer producer = _producerSession.createProducer(queue);
+
+ int count = 0;
+ while(count < 200)
+ {
+ final Message msg = _producerSession.createTextMessage("Message Text:" + count++);
+ msg.setStringProperty(TEST_SORT_KEY, "samesortkeyvalue");
+ producer.send(msg);
+ }
+
+ _producerSession.commit();
+ producer.close();
+
+ final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final MessageConsumer consumer = consumerSession.createConsumer(queue);
+ _consumerConnection.start();
+ TextMessage received = null;
+ int messageCount = 0;
+
+ while((received = (TextMessage) consumer.receive(1000)) != null)
+ {
+ assertEquals("Received message with unexpected sorted key value", "samesortkeyvalue",
+ received.getStringProperty(TEST_SORT_KEY));
+ assertEquals("Received message with unexpected message value", "Message Text:" + messageCount,
+ received.getText());
+ messageCount++;
+ }
+
+ assertEquals("Incorrect number of messages received", 200, messageCount);
+ }
+
+ public void testSortOrderWithUniqueKeySubset() throws JMSException, NamingException, AMQException
+ {
+ final Queue queue = createQueue();
+ final MessageProducer producer = _producerSession.createProducer(queue);
+
+ int count = 0;
+ while(count < 100)
+ {
+ int keyValueIndex = count % 10;
+ final Message msg = _producerSession.createTextMessage("Message Text:" + count);
+ msg.setStringProperty(TEST_SORT_KEY, SUBSET_KEYS[keyValueIndex]);
+ producer.send(msg);
+ count++;
+ }
+
+ _producerSession.commit();
+ producer.close();
+
+ final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ final MessageConsumer consumer = consumerSession.createConsumer(queue);
+ _consumerConnection.start();
+ TextMessage received;
+ int messageCount = 0;
+
+ while((received = (TextMessage) consumer.receive(1000)) != null)
+ {
+ assertEquals("Received message with unexpected sorted key value", SUBSET_KEYS[messageCount / 10],
+ received.getStringProperty(TEST_SORT_KEY));
+ messageCount++;
+ }
+
+ assertEquals("Incorrect number of messages received", 100, messageCount);
+ }
+
+ public void testGetNextWithAck() throws JMSException, NamingException, AMQException
+ {
+ Queue _queue = createQueue();
+ MessageProducer producer = _producerSession.createProducer(_queue);
+ Message received = null;
+
+ //Send 3 out of order
+ sendAndCommitMessage(producer,"2");
+ sendAndCommitMessage(producer,"3");
+ sendAndCommitMessage(producer,"1");
+
+ final Session consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ final MessageConsumer consumer = consumerSession.createConsumer(_queue);
+ _consumerConnection.start();
+
+ //Receive 3 in sorted order
+ received = receiveAndValidateMessage(consumer, "1");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "2");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "3");
+ received.acknowledge();
+
+ //Send 1
+ sendAndCommitMessage(producer,"4");
+
+ //Receive 1 and recover
+ received = receiveAndValidateMessage(consumer, "4");
+ consumerSession.recover();
+
+ //Receive same 1
+ received = receiveAndValidateMessage(consumer, "4");
+ received.acknowledge();
+
+ //Send 3 out of order
+ sendAndCommitMessage(producer,"7");
+ sendAndCommitMessage(producer,"6");
+ sendAndCommitMessage(producer,"5");
+
+ //Receive 1 of 3 (out of order due to pre-fetch) and recover
+ received = receiveAndValidateMessage(consumer, "7");
+ consumerSession.recover();
+
+ if (isBroker010())
+ {
+ //Receive 3 in sorted order (not as per JMS recover)
+ received = receiveAndValidateMessage(consumer, "5");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "6");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "7");
+ received.acknowledge();
+ }
+ else
+ {
+ //Receive 3 in partial sorted order due to recover
+ received = receiveAndValidateMessage(consumer, "7");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "5");
+ received.acknowledge();
+ received = receiveAndValidateMessage(consumer, "6");
+ received.acknowledge();
+ }
+ }
+
+ protected Queue createQueue() throws AMQException, JMSException
+ {
+ final Map<String, Object> arguments = new HashMap<String, Object>();
+ arguments.put(AMQQueueFactory.QPID_QUEUE_SORT_KEY, TEST_SORT_KEY);
+ ((AMQSession<?,?>) _producerSession).createQueue(new AMQShortString(getTestQueueName()), false, true, false, arguments);
+ final Queue queue = new AMQQueue("amq.direct", getTestQueueName());
+ ((AMQSession<?,?>) _producerSession).declareAndBind((AMQDestination) queue);
+ return queue;
+ }
+
+ private Message getSortableTestMesssage(final String key) throws JMSException
+ {
+ final Message msg = _producerSession.createTextMessage("Message Text: Key Value" + key);
+ msg.setStringProperty(TEST_SORT_KEY, key);
+ return msg;
+ }
+
+ private void sendAndCommitMessage(final MessageProducer producer, final String keyValue) throws JMSException
+ {
+ producer.send(getSortableTestMesssage(keyValue));
+ _producerSession.commit();
+ }
+
+ private Message receiveAndValidateMessage(final MessageConsumer consumer, final String expectedKey) throws JMSException
+ {
+ final Message received = (TextMessage) consumer.receive(10000);
+ assertNotNull("Received message is unexpectedly null", received);
+ assertEquals("Received message with unexpected sorted key value", expectedKey,
+ received.getStringProperty(TEST_SORT_KEY));
+ return received;
+ }
+
+ private class TestConsumerThread extends Thread
+ {
+ private boolean _stopped = false;
+ private int _count = 0;
+ private int _consumed = 0;
+ private int _sessionType = Session.AUTO_ACKNOWLEDGE;
+ private Queue _queue;
+
+ public TestConsumerThread(final int sessionType, final Queue queue)
+ {
+ _sessionType = sessionType;
+ _queue = queue;
+ }
+
+ public void run()
+ {
+ try
+ {
+ Connection conn = null;
+ try
+ {
+ conn = getConnection();
+ }
+ catch(Exception e)
+ {
+ fail("Could not get connection");
+ }
+
+ final Session session = conn.createSession((_sessionType == Session.SESSION_TRANSACTED ? true : false),
+ _sessionType);
+ final MessageConsumer consumer = session.createConsumer(_queue);
+
+ conn.start();
+
+ TextMessage msg;
+ Calendar cal = Calendar.getInstance(Locale.UK);
+ while((msg = (TextMessage) consumer.receive(1000)) != null)
+ {
+ if(_sessionType == Session.SESSION_TRANSACTED)
+ {
+ if (_count%10 == 0)
+ {
+ LOGGER.debug("transacted session rollback");
+ session.rollback();
+ }
+ else
+ {
+ LOGGER.debug("transacted session commit");
+ session.commit();
+ _consumed++;
+ }
+ }
+ else if(_sessionType == Session.CLIENT_ACKNOWLEDGE)
+ {
+ if (_count%10 == 0)
+ {
+ LOGGER.debug("client ack session recover");
+ session.recover();
+ }
+ else
+ {
+ LOGGER.debug("client ack session acknowledge");
+ msg.acknowledge();
+ _consumed++;
+ }
+ }
+ else
+ {
+ LOGGER.debug("auto ack session");
+ _consumed++;
+ }
+
+ _count++;
+ LOGGER.debug("Message consumed at : " + cal.getTimeInMillis());
+ LOGGER.debug("Message consumed with key: " + msg.getStringProperty(TEST_SORT_KEY));
+ LOGGER.debug("Message consumed with text: " + msg.getText());
+ LOGGER.debug("Message consumed with consumed index: " + _consumed);
+ }
+
+ _stopped = true;
+ session.close();
+ conn.close();
+ }
+ catch(JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public synchronized boolean isStopped()
+ {
+ return _stopped;
+ }
+
+ public synchronized int getConsumed()
+ {
+ return _consumed;
+ }
+ }
+
+ private static class AscendingSortedKeys
+ {
+ public static final String[] KEYS = { "Ul4a1", "WaWsv", "2Yz7E", "ix74r", "okgRi", "HlUbF", "LewvM", "lweGy",
+ "TXQ0Z", "0Kyfs", "s7Mxk", "dmoS7", "8RCUA", "W3VFH", "aez9y", "uQIcz", "0h1b1", "cmXIX",
+ "4dEz6", "zHF1q", "D6rBy", "5drc6", "0BmCy", "BCxeC", "t59lR", "aL6AJ", "OHaBz", "WmadA",
+ "B3qem", "CxVEf", "AIYUu", "uJScX", "uoStw", "ogLgc", "AgJHQ", "hUTw7", "Rxrsm", "9GXkX",
+ "7hyVv", "y94nw", "Twano", "TCgPp", "pFrrl", "POUYS", "L7cGc", "0ao3l", "CNHmv", "MaJQs",
+ "OUqFM", "jeskS", "FPfSE", "v1Hln", "14FLR", "KZamH", "G1RhS", "FVMxo", "rKDLJ", "nnP8o",
+ "nFqik", "zmLYD", "1j5L8", "e6e4z", "WDVWJ", "aDGtS", "fcwDa", "nlaBy", "JJs5m", "vLsmS",
+ "No0Qb", "JXljW", "Waim6", "MezSW", "l83Ud", "SjskQ", "uPX7G", "5nmWv", "ZhwG1", "uTacx",
+ "t98iW", "JkzUn", "fmIK1", "i7WMQ", "bgJAz", "n1pmO", "jS1aj", "4W0Tl", "Yf2Ec", "sqVrf",
+ "MojnP", "qQxHP", "pWiOs", "yToGW", "kB5nP", "BpYhV", "Cfgr3", "zbIYY", "VLTy6", "he9IA",
+ "lm0pD", "WreyP", "8hJdt", "QnJ1S", "n8pJ9", "iqv4k", "OUYuF", "8cVD3", "sx5Gl", "cQOnv",
+ "wiHrZ", "oGu6x", "7fsYM", "gf8rI", "7fKYU", "pT8wu", "lCMxy", "prNT6", "5Drn0", "guMb8",
+ "OxWIH", "uZPqg", "SbRYy", "In3NS", "uvf7A", "FLsph", "pmeCd", "BbwgA", "ru4UG", "YOfrY",
+ "W7cTs", "K4GS8", "AOgEe", "618Di", "dpe1v", "3otm6", "oVQp6", "5Mg9r", "Y1mC0", "VIlwP",
+ "aFFss", "Mkgy8", "pv0i7", "S77LH", "XyPZN", "QYxC0", "vkCHH", "MGlTF", "24ARF", "v2eC3",
+ "ZUnqt", "HfyNQ", "FjHXR", "45cIH", "1LB1L", "zqH0W", "fLNg8", "oQ87r", "Cp3mZ", "Zv7z0",
+ "O3iyQ", "EOE1o", "5ZaEz", "tlILt", "MmsIo", "lXFOB", "gtCA5", "yEfy9", "7X3uy", "d7vjM",
+ "XflUq", "Fhtgl", "NOHsz", "GWqqX", "xciqp", "BFkb8", "P6bcg", "lViBv", "2TRI7", "2hEEU",
+ "9XyT9", "29QAz", "U3yw5", "FxX9q", "C2Irc", "8U2nU", "m4bxU", "5iGN5", "mX2GE", "cShY2",
+ "JRJQB", "yvOMI", "4QMc9", "NAFuw", "RmDcr", "faHir", "2ZHdk", "zY1GY", "a00b5", "ZuDtD",
+ "JIqXi", "K20wK", "gdQsS", "5Namm", "lkMUA", "IBe8k", "FcWrW", "FFDui", "tuDyS", "ZJTXH",
+ "AkKTk", "zQt6Q", "FNYIM", "RpBQm", "RsQUq", "Mm8si", "gjUTu", "zz4ZU", "jiVBP", "ReKEW",
+ "5VZjS", "YjB9t", "zFgtB", "8TxD7", "euZA5", "MK07Y", "CK5W7", "16lHc", "6q6L9", "Z4I1v",
+ "UlU3M", "SWfou", "0PktI", "55rfB", "jfREu", "580YD", "Uvlv4", "KASQ8", "AmdQd", "piJSk",
+ "hE1Ql", "LDk6f", "NcICA", "IKxdL", "iwzGk", "uN6r3", "lsQGo", "QClRL", "iKqhr", "FGzgp",
+ "RkQke", "b29RJ", "CIShG", "9eoRc", "F6PT2", "LbRTH", "M3zXL", "GXdoH", "IjTwP", "RBhp0",
+ "yluBx", "mz8gx", "MmKGJ", "Q6Lix", "uupzk", "RACuj", "d85a9", "qaofN", "kZANm", "jtn0X",
+ "lpF6W", "suY4x", "rz7Ut", "wDajX", "1v5hH", "Yw2oU", "ksJby", "WMiS3", "lj07Q", "EdBKc",
+ "6AFT0", "0YAGH", "ThjNn", "JKWYR", "9iGoT", "UmaEv", "3weIF", "CdyBV", "pAhR1", "djsrv",
+ "xReec", "8FmFH", "Dz1R3", "Ta8f6", "DG4sT", "VjCZq", "jSjS3", "Pb1pa", "VNCPd", "Kr8ys",
+ "AXpwE", "ZzJHW", "Nxx9V", "jzUqR", "dhSuH", "DQimp", "07n1c", "HP433", "RzaZA", "cL0aE",
+ "Ss0Zu", "FnPFB", "7lUXZ", "9rlg9", "lH1kt", "ni2v1", "48cHL", "soy9t", "WPmlx", "2Nslm",
+ "hSSvQ", "9y4lw", "ulk41", "ECMvU", "DLhzM", "GrDg7", "x3LDe", "QChxs", "xXTI4", "Gv3Fq",
+ "rhl0J", "QssNC", "brhlQ", "s93Ml", "tl72W", "pvgjS", "Qworu", "DcpWB", "X6Pin", "J2mQi",
+ "BGaQY", "CqqaD", "NhXdu", "dQ586", "Yh1hF", "HRxd8", "PYBf4", "64s8N", "tvdkD", "azIWp",
+ "tAOsr", "v8yFN", "h1zcH", "SmGzv", "bZLvS", "fFDrJ", "Oz8yZ", "0Wr5y", "fcJOy", "7ku1p",
+ "QbxXc", "VerEA", "QWxoT", "hYBCK", "o8Uyd", "FwEJz", "hi5X7", "uAWyp", "I7p2a", "M6qcG",
+ "gIYvE", "HzZT8", "iB08l", "StlDJ", "tjQxs", "k85Ae", "taOXK", "s4786", "2DREs", "atef2",
+ "Vprf2", "VBjhz", "EoToP", "blLA9", "qUJMd", "ydG8U", "8xEKz", "uLtKs", "GSQwj", "S2Dfu",
+ "ciuWz", "i3pyd", "7Ow5C", "IRh48", "vOqCE", "Q6hMC", "yofH3", "KsjRK", "5IhmG", "fqypy",
+ "0MR5X", "Chuy3" };
+
+ private static int _i = 0;
+ private static int _j = 0;
+
+ static
+ {
+ Arrays.sort(KEYS);
+ }
+
+ public static String getNextKey()
+ {
+ if(_j == KEYS.length)
+ {
+ _j = 0;
+ _i++;
+ if(_i == KEYS.length)
+ {
+ _i = 0;
+ }
+ }
+ return new StringBuffer().append(KEYS[_i]).append("-").append(KEYS[_j++]).toString();
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
deleted file mode 100644
index c41de94121..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
+++ /dev/null
@@ -1,290 +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.server.AMQChannel;
-import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.framing.AMQShortString;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
-
-public class SubscriptionTestHelper implements Subscription
-{
- private final List<QueueEntry> messages;
- private final Object key;
- private boolean isSuspended;
- private AMQQueue.Context _queueContext;
-
- public SubscriptionTestHelper(Object key)
- {
- this(key, new ArrayList<QueueEntry>());
- }
-
- public SubscriptionTestHelper(final Object key, final boolean isSuspended)
- {
- this(key);
- setSuspended(isSuspended);
- }
-
- SubscriptionTestHelper(Object key, List<QueueEntry> messages)
- {
- this.key = key;
- this.messages = messages;
- }
-
- List<QueueEntry> getMessages()
- {
- return messages;
- }
-
- public void setQueue(AMQQueue queue, boolean exclusive)
- {
-
- }
-
- public void setNoLocal(boolean noLocal)
- {
-
- }
-
- public void send(QueueEntry msg)
- {
- messages.add(msg);
- }
-
- public void setSuspended(boolean suspended)
- {
- isSuspended = suspended;
- }
-
- public boolean isSuspended()
- {
- return isSuspended;
- }
-
- public boolean wouldSuspend(QueueEntry msg)
- {
- return isSuspended;
- }
-
- public void addToResendQueue(QueueEntry msg)
- {
- //no-op
- }
-
- 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 onDequeue(final QueueEntry queueEntry)
- {
-
- }
-
- public void restoreCredit(QueueEntry queueEntry)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setStateListener(final StateListener listener)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public State getState()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public AMQQueue.Context getQueueContext()
- {
- return _queueContext;
- }
-
- public void setQueueContext(AMQQueue.Context queueContext)
- {
- _queueContext = queueContext;
- }
-
- public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public AMQChannel getChannel()
- {
- return null;
- }
-
- public void start()
- {
- //no-op
- }
-
- public AMQShortString getConsumerTag()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getSubscriptionID()
- {
- return 0; //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 void set(String key, Object value)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Object get(String key)
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public LogActor getLogActor()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isTransient()
- {
- return false;
- }
-
- public AMQQueue getQueue()
- {
- return null;
- }
-
- public QueueEntry.SubscriptionAcquiredState getOwningState()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public QueueEntry.SubscriptionAssignedState getAssignedState()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void queueDeleted(AMQQueue queue)
- {
- }
-
- public boolean filtersMessages()
- {
- return false;
- }
-
- public boolean hasInterest(QueueEntry msg)
- {
- return true;
- }
-
- public Queue<QueueEntry> getPreDeliveryQueue()
- {
- return null;
- }
-
- public Queue<QueueEntry> getResendQueue()
- {
- return null;
- }
-
- public Queue<QueueEntry> getNextQueue(Queue<QueueEntry> messages)
- {
- return messages;
- }
-
- public void enqueueForPreDelivery(QueueEntry msg, boolean deliverFirst)
- {
- //no-op
- }
-
- public void close()
- {
- //no-op
- }
-
- public boolean isClosed()
- {
- return false;
- }
-
- public boolean acquires()
- {
- return true;
- }
-
- public boolean seesRequeues()
- {
- return true;
- }
-
- public boolean isBrowser()
- {
- return false;
- }
-
- public int hashCode()
- {
- return key.hashCode();
- }
-
- public boolean equals(Object o)
- {
- return o instanceof SubscriptionTestHelper && ((SubscriptionTestHelper) o).key.equals(key);
- }
-
- public String toString()
- {
- return key.toString();
- }
-
- public boolean isSessionTransactional()
- {
- return false;
- }
-
- public void queueEmpty() throws AMQException
- {
- //TODO
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
index 32b0185f88..262051ff89 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
@@ -24,8 +24,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -53,31 +51,25 @@ import org.apache.qpid.url.URLSyntaxException;
* TODO move the pre broker-startup setup method invocation code to {@link QpidBrokerTestCase}
*
* @see ExternalACLTest
- * @see ExternalACLFileTest
* @see ExternalACLJMXTest
- * @see ExternalAdminACLTest
* @see ExhaustiveACLTest
*/
public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements ConnectionListener
{
/** Used to synchronise {@link #tearDown()} when exceptions are thrown */
- protected CountDownLatch _exceptionReceived;
-
- /** Override this to return the name of the configuration XML file. */
- public abstract String getConfig();
+ protected CountDownLatch _exceptionReceived;
- /** Override this to setup external ACL files for virtual hosts. */
- public List<String> getHostList()
+ /** Override this to return the name of the configuration XML file. */
+ public String getConfig()
{
- return Collections.emptyList();
+ return "config-systests.xml";
}
-
+
/**
* This setup method checks {@link #getConfig()} and {@link #getHostList()} to initialise the broker with specific
* ACL configurations and then runs an optional per-test setup method, which is simply a method with the same name
* as the test, but starting with {@code setUp} rather than {@code test}.
*
- * @see #setUpACLFile(String)
* @see org.apache.qpid.test.utils.QpidBrokerTestCase#setUp()
*/
@Override
@@ -85,12 +77,7 @@ public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements
{
// Initialise ACLs.
_configFile = new File("build" + File.separator + "etc" + File.separator + getConfig());
- // Initialise ACL files
- for (String virtualHost : getHostList())
- {
- setUpACLFile(virtualHost);
- }
-
+
// run test specific setup
String testSetup = StringUtils.replace(getName(), "test", "setUp");
try
@@ -124,73 +111,27 @@ public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements
}
}
- /**
- * Configures specific ACL files for a virtual host.
- *
- * This method checks for ACL files that exist on the filesystem. If dynamically generatyed ACL files are required in a test,
- * then it is easier to use the {@code setUp} prefix on a method to generate the ACL file. In order, this method looks
- * for three files:
- * <ol>
- * <li><em>virtualhost</em>-<em>class</em>-<em>test</em>.txt
- * <li><em>virtualhost</em>-<em>class</em>.txt
- * <li><em>virtualhost</em>-default.txt
- * </ol>
- * The <em>class</em> and <em>test</em> parts are the test class and method names respectively, with the word {@code test}
- * removed and the rest of the text converted to lowercase. For example, the test class and method named
- * {@code org.apache.qpid.test.AccessExampleTest#testExampleMethod} on the {@code testhost} virtualhost would use
- * one of the following files:
- * <ol>
- * <li>testhost-accessexample-examplemethod.txt
- * <li>testhost-accessexample.txt
- * <li>testhost-default.txt
- * </ol>
- * These files should be copied to the <em>${QPID_HOME}/etc</em> directory when the test is run.
- *
- * @see #writeACLFile(String, String...)
- */
- public void setUpACLFile(String virtualHost) throws IOException, ConfigurationException
+ public void writeACLFile(final String vhost, final String...rules) throws ConfigurationException, IOException
{
- String path = "build" + File.separator + "etc";
- String className = StringUtils.substringBeforeLast(getClass().getSimpleName().toLowerCase(), "test");
- String testName = StringUtils.substringAfter(getName(), "test").toLowerCase();
-
- File aclFile = new File(path, virtualHost + "-" + className + "-" + testName + ".txt");
- if (!aclFile.exists())
- {
- aclFile = new File(path, virtualHost + "-" + className + ".txt");
- if (!aclFile.exists())
- {
- aclFile = new File(path, virtualHost + "-" + "default.txt");
- }
- }
-
- // Set the ACL file configuration property
- if (virtualHost.equals("global"))
- {
- setConfigurationProperty("security.aclv2", aclFile.getAbsolutePath());
- }
- else
- {
- setConfigurationProperty("virtualhosts.virtualhost." + virtualHost + ".security.aclv2", aclFile.getAbsolutePath());
- }
+ writeACLFileUtil(this, vhost, rules);
}
- public void writeACLFile(String vhost, String...rules) throws ConfigurationException, IOException
+ public static void writeACLFileUtil(QpidBrokerTestCase testcase, String vhost, String...rules) throws ConfigurationException, IOException
{
- File aclFile = File.createTempFile(getClass().getSimpleName(), getName());
+ File aclFile = File.createTempFile(testcase.getClass().getSimpleName(), testcase.getName());
aclFile.deleteOnExit();
- if ("global".equals(vhost))
+ if (vhost == null)
{
- setConfigurationProperty("security.aclv2", aclFile.getAbsolutePath());
+ testcase.setConfigurationProperty("security.acl", aclFile.getAbsolutePath());
}
else
{
- setConfigurationProperty("virtualhosts.virtualhost." + vhost + ".security.aclv2", aclFile.getAbsolutePath());
+ testcase.setConfigurationProperty("virtualhosts.virtualhost." + vhost + ".security.acl", aclFile.getAbsolutePath());
}
PrintWriter out = new PrintWriter(new FileWriter(aclFile));
- out.println(String.format("# %s", getTestName()));
+ out.println(String.format("# %s", testcase.getName()));
for (String line : rules)
{
out.println(line);
@@ -265,7 +206,7 @@ public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements
public void check403Exception(Throwable t) throws Exception
{
assertNotNull("There was no linked exception", t);
- assertTrue("Wrong linked exception type", t instanceof AMQException);
+ assertTrue("Wrong linked exception type : " + t.getClass(), t instanceof AMQException);
assertEquals("Incorrect error code received", 403, ((AMQException) t).getErrorCode().getCode());
//use the latch to ensure the control thread waits long enough for the exception thread
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java
index 1b2c98d30a..4f2464e186 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java
@@ -18,9 +18,6 @@
*/
package org.apache.qpid.server.security.acl;
-import java.util.Arrays;
-import java.util.List;
-
import javax.jms.Connection;
import javax.jms.Session;
@@ -31,7 +28,7 @@ import org.apache.qpid.protocol.AMQConstant;
/**
* ACL version 2/3 file testing to verify that ACL entries control queue creation with specific properties.
- *
+ *
* Tests have their own ACL files that setup specific permissions, and then try to create queues with every possible combination
* of properties to show that rule matching works correctly. For example, a rule that specified {@code autodelete="true"} for
* queues with {@link name="temp.true.*"} as well should not affect queues that have names that do not match, or queues that
@@ -39,18 +36,7 @@ import org.apache.qpid.protocol.AMQConstant;
*/
public class ExhaustiveACLTest extends AbstractACLTestCase
{
- @Override
- public String getConfig()
- {
- return "config-systests-aclv2.xml";
- }
- @Override
- public List<String> getHostList()
- {
- return Arrays.asList("test", "test2");
- }
-
/**
* Creates a queue.
*
@@ -130,11 +116,6 @@ public class ExhaustiveACLTest extends AbstractACLTestCase
createQueueFailure("test", "client", "temp.false.07", true, false);
createQueueFailure("test", "server", "temp.true.08", true, false);
createQueueFailure("test", "client", "temp.other.09", false, false);
- createQueueSuccess("test2", "guest", "temp.true.01", false, false);
- createQueueSuccess("test2", "guest", "temp.false.02", true, false);
- createQueueSuccess("test2", "guest", "temp.true.03", true, false);
- createQueueSuccess("test2", "guest", "temp.false.04", false, false);
- createQueueSuccess("test2", "guest", "temp.other.05", false, false);
}
public void setUpAuthoriseCreateQueue() throws Exception
@@ -161,10 +142,6 @@ public class ExhaustiveACLTest extends AbstractACLTestCase
createQueueFailure("test", "server", "create.05", true, false);
createQueueFailure("test", "server", "create.06", false, true);
createQueueFailure("test", "server", "create.07", true, false);
- createQueueSuccess("test2", "guest", "create.00", true, true);
- createQueueSuccess("test2", "guest", "create.01", true, false);
- createQueueSuccess("test2", "guest", "create.02", false, true);
- createQueueSuccess("test2", "guest", "create.03", true, false);
}
public void setUpAuthoriseCreateQueueBoth() throws Exception
@@ -190,6 +167,5 @@ public class ExhaustiveACLTest extends AbstractACLTestCase
createQueueSuccess("test", "client", "tmp.00", true, false);
createQueueSuccess("test", "server", "tmp.01", true, false);
createQueueSuccess("test", "guest", "tmp.02", true, false);
- createQueueSuccess("test2", "guest", "create.02", false, false);
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java
deleted file mode 100644
index 1d08015669..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java
+++ /dev/null
@@ -1,184 +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.security.acl;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.jms.Connection;
-import javax.jms.Session;
-
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.AMQShortString;
-
-/**
- * Tests that ACL version 2/3 files following the specification work correctly.
- *
- * ACL lines that are identical in meaning apart from differences allowed by the specification, such as whitespace or case
- * of tokens are set up for numbered queues and the queues are then created to show that the meaning is correctly parsed by
- * the plugin.
- *
- * TODO move this to the access-control plugin unit tests instead
- */
-public class ExternalACLFileTest extends AbstractACLTestCase
-{
- @Override
- public String getConfig()
- {
- return "config-systests-aclv2.xml";
- }
-
- @Override
- public List<String> getHostList()
- {
- return Arrays.asList("test");
- }
-
- private void createQueuePrefixList(String prefix, int count)
- {
- try
- {
- Connection conn = getConnection("test", "client", "guest");
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- conn.start();
-
- //Create n queues
- for (int n = 0; n < count; n++)
- {
- AMQShortString queueName = new AMQShortString(String.format("%s.%03d", prefix, n));
- ((AMQSession<?, ?>) sess).createQueue(queueName, false, false, false);
- }
-
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
- }
-
- private void createQueueNameList(String...queueNames)
- {
- try
- {
- Connection conn = getConnection("test", "client", "guest");
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- conn.start();
-
- //Create all queues
- for (String queueName : queueNames)
- {
- ((AMQSession<?, ?>) sess).createQueue(new AMQShortString(queueName), false, false, false);
- }
-
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
- }
-
- public void setUpCreateQueueMixedCase() throws Exception
- {
- writeACLFile(
- "test",
- "acl allow client create queue name=mixed.000",
- "ACL ALLOW client CREATE QUEUE NAME=mixed.001",
- "Acl Allow client Create Queue Name=mixed.002",
- "aCL aLLOW client cREATE qUEUE nAME=mixed.003",
- "aCl AlLoW client cReAtE qUeUe NaMe=mixed.004"
- );
- }
-
- public void testCreateQueueMixedCase()
- {
- createQueuePrefixList("mixed", 5);
- }
-
- public void setUpCreateQueueContinuation() throws Exception
- {
- writeACLFile(
- "test",
- "acl allow client create queue name=continuation.000",
- "acl allow client create queue \\",
- " name=continuation.001",
- "acl allow client \\",
- " create queue \\",
- " name=continuation.002",
- "acl allow \\",
- " client \\",
- " create queue \\",
- " name=continuation.003",
- "acl \\",
- " allow \\",
- " client \\",
- " create queue \\",
- " name=continuation.004"
- );
- }
-
- public void testCreateQueueContinuation()
- {
- createQueuePrefixList("continuation", 5);
- }
-
- public void setUpCreateQueueWhitespace() throws Exception
- {
- writeACLFile(
- "test",
- "acl allow client create queue name=whitespace.000",
- "acl\tallow\tclient\tcreate\tqueue\tname=whitespace.001",
- "acl allow client create queue name = whitespace.002",
- "acl\tallow\tclient\tcreate\tqueue\tname\t=\twhitespace.003",
- "acl allow\t\tclient\t \tcreate\t\t queue\t \t name \t =\t \twhitespace.004"
- );
- }
-
- public void testCreateQueueWhitespace()
- {
- createQueuePrefixList("whitespace", 5);
- }
-
- public void setUpCreateQueueQuoting() throws Exception
- {
- writeACLFile(
- "test",
- "acl allow client create queue name='quoting.ABC.000'",
- "acl allow client create queue name='quoting.*.000'",
- "acl allow client create queue name='quoting.#.000'",
- "acl allow client create queue name='quoting. .000'",
- "acl allow client create queue name='quoting.!@$%.000'"
- );
- }
-
- public void testCreateQueueQuoting()
- {
- createQueueNameList(
- "quoting.ABC.000",
- "quoting.*.000",
- "quoting.#.000",
- "quoting. .000",
- "quoting.!@$%.000"
- );
- }
-}
-
-
-
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java
index b823690002..427d253ca5 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java
@@ -18,41 +18,31 @@
*/
package org.apache.qpid.server.security.acl;
-import java.util.Arrays;
-import java.util.List;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
-import org.apache.qpid.AMQConnectionClosedException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQSecurityException;
-import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.security.access.ObjectType;
import org.apache.qpid.test.utils.JMXTestUtils;
/**
- * Tests that ACL entries that apply to AMQP objects also apply when those objects are accessed via JMX.
+ * Tests that access to the JMX interface is governed only by {@link ObjectType#METHOD}/{@link ObjectType#ALL}
+ * rules and AMQP rights have no effect.
+ *
+ * Ensures that objects outside the Qpid domain ({@link ManagedObject#DOMAIN}) are not governed by the ACL model.
*/
public class ExternalACLJMXTest extends AbstractACLTestCase
{
private JMXTestUtils _jmx;
-
- private static final String QUEUE_NAME = "kipper";
- private static final String EXCHANGE_NAME = "amq.kipper";
-
- @Override
- public String getConfig()
- {
- return "config-systests-aclv2.xml";
- }
- @Override
- public List<String> getHostList()
- {
- return Arrays.asList("test");
- }
+ private static final String TEST_QUEUE_OWNER = "admin";
+ private static final String TEST_VHOST = "test";
@Override
public void setUp() throws Exception
{
- _jmx = new JMXTestUtils(this, "admin", "admin");
+ _jmx = new JMXTestUtils(this);
_jmx.setUp();
super.setUp();
_jmx.open();
@@ -65,180 +55,264 @@ public class ExternalACLJMXTest extends AbstractACLTestCase
super.tearDown();
}
- // test-externalacljmx.txt
- // create queue owner=client # success
- public void testCreateClientQueueSuccess() throws Exception
- {
- //Queue Parameters
- String queueOwner = "client";
-
- _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
+ /**
+ * Ensure an empty ACL defaults to DENY ALL.
+ */
+ public void setUpDenyAllIsDefault() throws Exception
+ {
+ writeACLFile(null, "#Empty ACL file");
}
- // test-externalacljmx.txt
- // create queue owner=client # failure
- public void testCreateServerQueueFailure() throws Exception
- {
- //Queue Parameters
- String queueOwner = "server";
-
+ public void testDenyAllIsDefault() throws Exception
+ {
+ //try a broker-level method
+ ServerInformation info = _jmx.getServerInformation();
try
{
- _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
-
- fail("Queue create should fail");
+ info.resetStatistics();
+ fail("Exception not thrown");
}
- catch (Exception e)
+ catch (SecurityException e)
{
- assertNotNull("Cause is not set", e.getCause());
- assertEquals("Cause message incorrect",
- "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Update resetStatistics", e.getMessage());
}
- }
- // no create queue acl in file # failure
- public void testCreateQueueFailure() throws Exception
- {
- //Queue Parameters
- String queueOwner = "guest";
-
+ //try a vhost-level method
try
{
- _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
-
- fail("Queue create should fail");
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ fail("Exception not thrown");
}
catch (Exception e)
{
- assertNotNull("Cause is not set", e.getCause());
- assertEquals("Cause message incorrect",
- "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Update createNewQueue", e.getMessage());
}
+
+ // Ensure that calls to MBeans outside the Qpid domain are not impeded.
+ final RuntimeMXBean runtimeBean = _jmx.getManagedObject(RuntimeMXBean.class, ManagementFactory.RUNTIME_MXBEAN_NAME);
+ runtimeBean.getName();
+ // PASS
}
- // test-externalacljmx.txt
- // allow create exchange name=amq.kipper.success
- public void testCreateExchangeSuccess() throws Exception
- {
- _jmx.createExchange("test", EXCHANGE_NAME + ".success", "direct", true);
+ /**
+ * Ensure an ALLOW ALL ALL rule allows access to both getters/setters.
+ */
+ public void setUpAllowAll() throws Exception
+ {
+ writeACLFile(null, "ACL ALLOW ALL ALL");
}
- // test-externalacljmx.txt
- // deny create exchange name=amq.kipper.failure
- public void testCreateExchangeFailure() throws Exception
- {
- try
- {
- _jmx.createExchange("test", EXCHANGE_NAME + ".failure", "direct", true);
-
- fail("Exchange create should fail");
- }
- catch (Exception e)
- {
- assertNotNull("Cause is not set", e.getCause());
- assertEquals("Cause message incorrect",
- "org.apache.qpid.AMQSecurityException: Permission denied: exchange-name 'amq.kipper.failure' [error code 403: access refused]", e.getCause().getMessage());
- }
+ public void testAllowAll() throws Exception
+ {
+ ServerInformation info = _jmx.getServerInformation();
+ info.getBuildVersion(); // getter - requires ACCESS
+ info.resetStatistics(); // setter - requires UPDATE
+ // PASS
}
- // test-externalacljmx.txt
- // allow create exchange name=amq.kipper.success
- // allow delete exchange name=amq.kipper.success
- public void testDeleteExchangeSuccess() throws Exception
- {
- _jmx.createExchange("test", EXCHANGE_NAME + ".success", "direct", true);
- _jmx.unregisterExchange("test", EXCHANGE_NAME + ".success");
+ /**
+ * admin user is denied at broker level but allowed at vhost level.
+ */
+ public void setUpVhostAllowOverridesGlobalDeny() throws Exception
+ {
+ writeACLFile(null,
+ "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'");
+ writeACLFile(TEST_VHOST,
+ "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'");
}
- // test-externalacljmx-deleteexchangefailure.txt
- // allow create exchange name=amq.kipper.delete
- // deny delete exchange name=amq.kipper.delete
- public void testDeleteExchangeFailure() throws Exception
- {
- _jmx.createExchange("test", EXCHANGE_NAME + ".delete", "direct", true);
+ public void testVhostAllowOverridesGlobalDeny() throws Exception
+ {
+ //try a vhost-level method on the allowed vhost
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+
+ //try a vhost-level method on a different vhost
try
{
- _jmx.unregisterExchange("test", EXCHANGE_NAME + ".delete");
-
- fail("Exchange delete should fail");
+ _jmx.createQueue("development", getTestQueueName(), TEST_QUEUE_OWNER, true);
+ fail("Exception not thrown");
}
- catch (Exception e)
+ catch (SecurityException e)
{
- assertNotNull("Cause is not set", e.getCause());
- assertEquals("Cause message incorrect",
- "org.apache.qpid.AMQSecurityException: Permission denied [error code 403: access refused]", e.getCause().getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Update createNewQueue", e.getMessage());
}
}
-
+
+
/**
- * admin user has JMX right but not AMQP
+ * admin user is allowed all update methods on the component at broker level.
*/
- public void setUpCreateQueueJMXRights() throws Exception
+ public void setUpUpdateComponentOnlyAllow() throws Exception
{
- writeACLFile("test",
- "ACL ALLOW admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
- "ACL DENY admin CREATE QUEUE");
+ writeACLFile(null,
+ "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager'");
}
-
- public void testCreateQueueJMXRights() throws Exception
+
+ public void testUpdateComponentOnlyAllow() throws Exception
+ {
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ // PASS
+ _jmx.deleteQueue(TEST_VHOST, getTestQueueName());
+ // PASS
+ }
+
+
+ /**
+ * admin user is allowed all update methods on all components at broker level.
+ */
+ public void setUpUpdateMethodOnlyAllow() throws Exception
+ {
+ writeACLFile(null,
+ "ACL ALLOW admin UPDATE METHOD");
+ }
+
+ public void testUpdateMethodOnlyAllow() throws Exception
+ {
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ //PASS
+ _jmx.deleteQueue(TEST_VHOST, getTestQueueName());
+ // PASS
+ }
+
+
+ /**
+ * admin user has JMX right, AMPQ right is irrelevant.
+ */
+ public void setUpCreateQueueSuccess() throws Exception
+ {
+ writeACLFile(TEST_VHOST,
+ "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'");
+ }
+
+ public void testCreateQueueSuccess() throws Exception
+ {
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ }
+
+
+ /**
+ * admin user has JMX right, verifies lack of AMPQ rights is irrelevant.
+ */
+ public void setUpCreateQueueSuccessNoAMQPRights() throws Exception
+ {
+ writeACLFile(TEST_VHOST,
+ "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'",
+ "ACL DENY admin CREATE QUEUE");
+ }
+
+ public void testCreateQueueSuccessNoAMQPRights() throws Exception
+ {
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ }
+
+
+ /**
+ * admin user does not have JMX right, AMPQ right is irrelevant.
+ */
+ public void setUpCreateQueueDenied() throws Exception
+ {
+ writeACLFile(TEST_VHOST,
+ "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'");
+ }
+
+ public void testCreateQueueDenied() throws Exception
{
try
{
- _jmx.createQueue("test", QUEUE_NAME, "admin", true);
-
- fail("Queue create should fail");
+ _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true);
+ fail("Exception not thrown");
}
- catch (Exception e)
+ catch (SecurityException e)
{
- assertNotNull("Cause is not set", e.getCause());
- assertEquals("Cause message incorrect",
- "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Update createNewQueue", e.getMessage());
}
}
+
/**
- * admin user has AMQP right but not JMX
+ * admin user does not have JMX right
*/
- public void setUpCreateQueueAMQPRights() throws Exception
+ public void setUpServerInformationUpdateDenied() throws Exception
{
- writeACLFile("test",
- "ACL DENY admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
- "ACL ALLOW admin CREATE QUEUE");
+ writeACLFile(null,
+ "ACL DENY admin UPDATE METHOD component='ServerInformation' name='resetStatistics'");
}
-
- public void testCreateQueueAMQPRights() throws Exception
+
+ public void testServerInformationUpdateDenied() throws Exception
{
+ ServerInformation info = _jmx.getServerInformation();
try
{
- _jmx.createQueue("test", QUEUE_NAME, "admin", true);
-
- fail("Queue create should fail");
+ info.resetStatistics();
+ fail("Exception not thrown");
}
- catch (Exception e)
+ catch (SecurityException e)
{
- assertEquals("Cause message incorrect", "Permission denied: Execute createNewQueue", e.getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Update resetStatistics", e.getMessage());
}
}
+
/**
- * admin has both JMX and AMQP rights
+ * admin user has JMX right to check management API major version (but not minor version)
*/
- public void setUpCreateQueueJMXAMQPRights() throws Exception
+ public void setUpServerInformationAccessGranted() throws Exception
{
- writeACLFile("test",
- "ACL ALLOW admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
- "ACL ALLOW admin CREATE QUEUE");
+ writeACLFile(null,
+ "ACL ALLOW-LOG admin ACCESS METHOD component='ServerInformation' name='getManagementApiMajorVersion'");
}
-
- public void testCreateQueueJMXAMQPRights() throws Exception
+
+ public void testServerInformationAccessGranted() throws Exception
{
+ ServerInformation info = _jmx.getServerInformation();
+ info.getManagementApiMajorVersion();
+
try
{
- _jmx.createQueue("test", QUEUE_NAME, "admin", true);
+ info.getManagementApiMinorVersion();
+ fail("Exception not thrown");
}
- catch (Exception e)
+ catch (SecurityException e)
{
- fail("Queue create should succeed: " + e.getCause().getMessage());
+ assertEquals("Cause message incorrect", "Permission denied: Access getManagementApiMinorVersion", e.getMessage());
}
}
+
+
+ /**
+ * admin user has JMX right to use the update method
+ */
+ public void setUpServerInformationUpdateMethodPermission() throws Exception
+ {
+ writeACLFile(null,
+ "ACL ALLOW admin UPDATE METHOD component='ServerInformation' name='resetStatistics'");
+ }
+
+ public void testServerInformationUpdateMethodPermission() throws Exception
+ {
+ ServerInformation info = _jmx.getServerInformation();
+ info.resetStatistics();
+ // PASS
+ }
+
+
+ /**
+ * admin user has JMX right to use all types of method on ServerInformation
+ */
+ public void setUpServerInformationAllMethodPermissions() throws Exception
+ {
+ writeACLFile(null, "ACL ALLOW admin ALL METHOD component='ServerInformation'");
+ }
+
+ public void testServerInformationAllMethodPermissions() throws Exception
+ {
+ //try an update method
+ ServerInformation info = _jmx.getServerInformation();
+ info.resetStatistics();
+ // PASS
+ //try an access method
+ info.getManagementApiMinorVersion();
+ // PASS
+ }
+
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
index 254e1fe6ac..e9b8a2efd5 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
@@ -18,13 +18,8 @@
*/
package org.apache.qpid.server.security.acl;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
import javax.jms.Connection;
-import javax.jms.DeliveryMode;
-import javax.jms.IllegalStateException;
+import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
@@ -37,9 +32,6 @@ import javax.jms.TopicSubscriber;
import javax.naming.NamingException;
import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.url.URLSyntaxException;
@@ -49,7 +41,13 @@ import org.apache.qpid.url.URLSyntaxException;
*/
public class ExternalACLTest extends AbstractACLTestCase
{
- public void testAccessAuthorizedSuccess() throws AMQException, URLSyntaxException, Exception
+
+ public void setUpAccessAuthorizedSuccess() throws Exception
+ {
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST");
+ }
+
+ public void testAccessAuthorizedSuccess() throws Exception
{
try
{
@@ -68,43 +66,9 @@ public class ExternalACLTest extends AbstractACLTestCase
}
}
- public void testAccessVhostAuthorisedGuestSuccess() throws IOException, Exception
+ public void setUpAccessNoRightsFailure() throws Exception
{
- //The 'guest' user has no access to the 'test' vhost, as tested below in testAccessNoRights(), and so
- //is unable to perform actions such as connecting (and by extension, creating a queue, and consuming
- //from a queue etc). In order to test the vhost-wide 'access' ACL right, the 'guest' user has been given
- //this right in the 'test2' vhost.
-
- try
- {
- //get a connection to the 'test2' vhost using the guest user and perform various actions.
- Connection conn = getConnection("test2", "guest", "guest");
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- conn.start();
-
- //create Queues and consumers for each
- Queue namedQueue = sess.createQueue("vhostAccessCreatedQueue" + getTestQueueName());
- Queue tempQueue = sess.createTemporaryQueue();
- MessageConsumer consumer = sess.createConsumer(namedQueue);
- MessageConsumer tempConsumer = sess.createConsumer(tempQueue);
-
- //send a message to each queue (also causing an exchange declare)
- MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null);
- ((org.apache.qpid.jms.MessageProducer) sender).send(namedQueue, sess.createTextMessage("test"),
- DeliveryMode.NON_PERSISTENT, 0, 0L, false, false);
- ((org.apache.qpid.jms.MessageProducer) sender).send(tempQueue, sess.createTextMessage("test"),
- DeliveryMode.NON_PERSISTENT, 0, 0L, false, false);
-
- //consume the messages from the queues
- consumer.receive(2000);
- tempConsumer.receive(2000);
-
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
+ writeACLFile("test", "ACL DENY-LOG client ACCESS VIRTUALHOST");
}
public void testAccessNoRightsFailure() throws Exception
@@ -131,228 +95,124 @@ public class ExternalACLTest extends AbstractACLTestCase
}
}
- public void testClientDeleteQueueSuccess() throws Exception
+ public void setUpClientDeleteQueueSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "client", "guest");
- Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
- conn.start();
-
- // create kipper
- Topic kipper = sess.createTopic("kipper");
- TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
-
- subscriber.close();
- sess.unsubscribe("kipper");
-
- //Do something to show connection is active.
- sess.rollback();
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"" ,
+ "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"",
+ "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper",
+ "ACL ALLOW-LOG client DELETE QUEUE durable=\"true\"",
+ "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper");
}
- public void testServerDeleteQueueFailure() throws Exception
+ public void testClientDeleteQueueSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
- Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
- conn.start();
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
- // create kipper
- Topic kipper = sess.createTopic("kipper");
- TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
+ // create kipper
+ Topic kipper = sess.createTopic("kipper");
+ TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
- subscriber.close();
- sess.unsubscribe("kipper");
+ subscriber.close();
+ sess.unsubscribe("kipper");
- //Do something to show connection is active.
- sess.rollback();
- conn.close();
- }
- catch (JMSException e)
- {
- // JMSException -> linedException = AMQException.403
- check403Exception(e.getLinkedException());
- }
+ //Do something to show connection is active.
+ sess.rollback();
+ conn.close();
}
- public void testClientConsumeFromTempQueueSuccess() throws AMQException, URLSyntaxException, Exception
- {
- try
- {
- Connection conn = getConnection("test", "client", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- sess.createConsumer(sess.createTemporaryQueue());
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
+ public void setUpClientDeleteQueueFailure() throws Exception
+ {
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"" ,
+ "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"",
+ "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper",
+ "ACL DENY-LOG client DELETE QUEUE durable=\"true\"",
+ "ACL DENY-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper");
}
- public void testClientConsumeFromNamedQueueFailure() throws NamingException, Exception
+ public void testClientDeleteQueueFailure() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ // create kipper
+ Topic kipper = sess.createTopic("kipper");
+ TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
- conn.start();
+ subscriber.close();
+ try
+ {
+ sess.unsubscribe("kipper");
- sess.createConsumer(sess.createQueue("IllegalQueue"));
+ //Do something to show connection is active.
+ sess.rollback();
- fail("Test failed as consumer was created.");
+ fail("Exception was not thrown");
}
catch (JMSException e)
{
+ // JMSException -> linedException = AMQException.403
check403Exception(e.getLinkedException());
}
}
- public void testClientCreateTemporaryQueueSuccess() throws JMSException, URLSyntaxException, Exception
- {
- try
- {
- Connection conn = getConnection("test", "client", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
- //Create Temporary Queue - can't use the createTempQueue as QueueName is null.
- ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("doesnt_matter_as_autodelete_means_tmp"),
- true, false, false);
-
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
- }
-
- public void testClientCreateNamedQueueFailure() throws NamingException, JMSException, AMQException, Exception
+ public void testClientConsumeFromTempQueueSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- conn.start();
+ conn.start();
- //Create a Named Queue
- ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
-
- fail("Test failed as Queue creation succeded.");
- //conn will be automatically closed
- }
- catch (AMQException e)
- {
- check403Exception(e);
- }
+ sess.createConsumer(sess.createTemporaryQueue());
}
- public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, Exception
+ public void setUpClientConsumeFromNamedQueueValid() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "client", "guest");
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE name=\"example.RequestQueue\"" ,
+ "ACL ALLOW-LOG client CONSUME QUEUE name=\"example.RequestQueue\"",
+ "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\"");
+ }
- Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
- conn.start();
-
- MessageProducer sender = sess.createProducer(sess.createQueue("example.RequestQueue"));
+ public void testClientConsumeFromNamedQueueValid() throws Exception
+ {
+ Connection conn = getConnection("test", "client", "guest");
- sender.send(sess.createTextMessage("test"));
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
- sess.commit();
+ conn.start();
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test publish failed:" + e);
- }
+ sess.createConsumer(sess.createQueue("example.RequestQueue"));
}
- public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException, Exception
+ public void setUpClientConsumeFromNamedQueueFailure() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "client", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null);
-
- Queue queue = sess.createQueue("example.RequestQueue");
-
- // Send a message that we will wait to be sent, this should give the broker time to process the msg
- // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
- // queue existence.
- ((org.apache.qpid.jms.MessageProducer) sender).send(queue, sess.createTextMessage("test"),
- DeliveryMode.NON_PERSISTENT, 0, 0L, false, false);
-
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test publish failed:" + e);
- }
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE" ,
+ "ACL ALLOW-LOG client BIND EXCHANGE",
+ "ACL DENY-LOG client CONSUME QUEUE name=\"IllegalQueue\"");
}
- public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
+ public void testClientConsumeFromNamedQueueFailure() throws NamingException, Exception
{
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
+ Destination dest = sess.createQueue("IllegalQueue");
+
try
{
- Connection conn = getConnection("test", "client", "guest");
-
- Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null);
-
- Queue queue = session.createQueue("Invalid");
-
- // Send a message that we will wait to be sent, this should give the broker time to close the connection
- // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
- // queue existence.
- ((org.apache.qpid.jms.MessageProducer) sender).send(queue, session.createTextMessage("test"),
- DeliveryMode.NON_PERSISTENT, 0, 0L, false, false);
-
- // Test the connection with a valid consumer
- // This may fail as the session may be closed before the queue or the consumer created.
- Queue temp = session.createTemporaryQueue();
+ sess.createConsumer(dest);
- session.createConsumer(temp).close();
-
- //Connection should now be closed and will throw the exception caused by the above send
- conn.close();
-
- fail("Close is not expected to succeed.");
- }
- catch (IllegalStateException e)
- {
- _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error.");
+ fail("Test failed as consumer was created.");
}
catch (JMSException e)
{
@@ -360,39 +220,43 @@ public class ExternalACLTest extends AbstractACLTestCase
}
}
- public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException, Exception
+ public void setUpClientCreateTemporaryQueueSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE temporary=\"true\"" ,
+ "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true",
+ "ACL ALLOW-LOG client DELETE QUEUE temporary=\"true\"",
+ "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true");
+ }
- conn.start();
+ public void testClientCreateTemporaryQueueSuccess() throws JMSException, URLSyntaxException, Exception
+ {
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
- sess.createConsumer(sess.createQueue("example.RequestQueue"));
+ sess.createTemporaryQueue();
+ conn.close();
+ }
- conn.close();
- }
- catch (Exception e)
- {
- fail("Test failed due to:" + e.getMessage());
- }
+ public void setUpClientCreateTemporaryQueueFailed() throws Exception
+ {
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL DENY-LOG client CREATE QUEUE temporary=\"true\"");
}
- public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException, Exception
+ public void testClientCreateTemporaryQueueFailed() throws NamingException, Exception
{
+ Connection conn = getConnection("test", "client", "guest");
+ Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
+
try
{
- Connection conn = getConnection("test", "client", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
- conn.start();
-
- sess.createConsumer(sess.createQueue("Invalid"));
+ session.createTemporaryQueue();
- fail("Test failed as consumer was created.");
+ fail("Test failed as creation succeded.");
}
catch (JMSException e)
{
@@ -400,247 +264,139 @@ public class ExternalACLTest extends AbstractACLTestCase
}
}
- public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException, Exception
+ public void setUpClientCreateNamedQueueFailure() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- sess.createConsumer(sess.createTemporaryQueue());
-
- fail("Test failed as consumer was created.");
- }
- catch (JMSException e)
- {
- check403Exception(e.getLinkedException());
- }
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE name=\"ValidQueue\"",
+ "ACL ALLOW-LOG client CONSUME QUEUE");
}
- public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException, Exception
+ public void testClientCreateNamedQueueFailure() throws NamingException, JMSException, AMQException, Exception
{
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
+ Destination dest = sess.createQueue("IllegalQueue");
+
try
{
- Connection conn = getConnection("test", "server", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- //Create Temporary Queue
- ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("example.RequestQueue"), false, false, false);
-
- conn.close();
+ //Create a Named Queue as side effect
+ sess.createConsumer(dest);
+ fail("Test failed as Queue creation succeded.");
}
- catch (Exception e)
+ catch (JMSException e)
{
- fail("Test failed due to:" + e.getMessage());
+ check403Exception(e.getLinkedException());
}
}
- public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException, Exception
+ public void setUpClientPublishUsingTransactionSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
-
- Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- //Create a Named Queue
- ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
-
- fail("Test failed as creation succeded.");
- }
- catch (Exception e)
- {
- check403Exception(e);
- }
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client CREATE QUEUE" ,
+ "ACL ALLOW-LOG client BIND EXCHANGE",
+ "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\"");
}
- public void testServerCreateTemporaryQueueInvalid() throws NamingException, Exception
+ public void testClientPublishUsingTransactionSuccess() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
- Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Connection conn = getConnection("test", "client", "guest");
- conn.start();
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
- session.createTemporaryQueue();
+ conn.start();
- fail("Test failed as creation succeded.");
- }
- catch (JMSException e)
- {
- check403Exception(e.getLinkedException());
- }
- }
+ MessageProducer sender = sess.createProducer(sess.createQueue("example.RequestQueue"));
- public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException, Exception
- {
- try
- {
- Connection connection = getConnection("test", "server", "guest");
+ sender.send(sess.createTextMessage("test"));
- Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
+ sess.commit();
- connection.start();
+ conn.close();
+ }
- ((AMQSession<?, ?>) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
- true, false, false);
- fail("Test failed as creation succeded.");
- }
- catch (Exception e)
- {
- check403Exception(e);
- }
+ public void setUpRequestResponseSuccess() throws Exception
+ {
+ writeACLFile("test", "GROUP messaging-users client server",
+ "ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST",
+ "# Server side",
+ "ACL ALLOW-LOG server CREATE QUEUE name=\"example.RequestQueue\"" ,
+ "ACL ALLOW-LOG server BIND EXCHANGE",
+ "ACL ALLOW-LOG server PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"TempQueue*\"",
+ "ACL ALLOW-LOG server CONSUME QUEUE name=\"example.RequestQueue\"",
+ "# Client side",
+ "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\"",
+ "ACL ALLOW-LOG client CONSUME QUEUE temporary=true",
+ "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true",
+ "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true",
+ "ACL ALLOW-LOG client CREATE QUEUE temporary=true",
+ "ACL ALLOW-LOG client DELETE QUEUE temporary=true");
}
- /**
- * This test uses both the cilent and sender to validate that the Server is able to publish to a temporary queue.
- * The reason the client must be involved is that the Server is unable to create its own Temporary Queues.
- *
- * @throws AMQException
- * @throws URLSyntaxException
- * @throws JMSException
- */
- public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
+
+ public void testRequestResponseSuccess() throws Exception
{
//Set up the Server
Connection serverConnection = getConnection("test", "server", "guest");
-
Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED);
-
Queue requestQueue = serverSession.createQueue("example.RequestQueue");
-
MessageConsumer server = serverSession.createConsumer(requestQueue);
-
serverConnection.start();
//Set up the consumer
Connection clientConnection = getConnection("test", "client", "guest");
-
- //Send a test mesage
- Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
+ Session clientSession = clientConnection.createSession(true, Session.SESSION_TRANSACTED);
Queue responseQueue = clientSession.createTemporaryQueue();
-
MessageConsumer clientResponse = clientSession.createConsumer(responseQueue);
-
clientConnection.start();
+ // Client
Message request = clientSession.createTextMessage("Request");
-
- assertNotNull("Response Queue is null", responseQueue);
-
request.setJMSReplyTo(responseQueue);
clientSession.createProducer(requestQueue).send(request);
-
- try
- {
- Message msg = null;
-
- msg = server.receive(2000);
-
- while (msg != null && !((TextMessage) msg).getText().equals("Request"))
- {
- msg = server.receive(2000);
- }
-
- assertNotNull("Message not received", msg);
-
- assertNotNull("Reply-To is Null", msg.getJMSReplyTo());
-
- MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo());
-
- sender.send(serverSession.createTextMessage("Response"));
-
- //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
- serverSession.commit();
-
- //Ensure Response is received.
- Message clientResponseMsg = clientResponse.receive(2000);
- assertNotNull("Client did not receive response message,", clientResponseMsg);
- assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText());
-
- }
- catch (Exception e)
- {
- fail("Test publish failed:" + e);
- }
- finally
- {
- try
- {
- serverConnection.close();
- }
- finally
- {
- clientConnection.close();
- }
- }
+ clientSession.commit();
+
+ // Server
+ Message msg = server.receive(2000);
+ assertNotNull("Server should have received client's request", msg);
+ assertNotNull("Received msg should have Reply-To", msg.getJMSReplyTo());
+
+ MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo());
+ sender.send(serverSession.createTextMessage("Response"));
+ serverSession.commit();
+
+ // Client
+ Message clientResponseMsg = clientResponse.receive(2000);
+ clientSession.commit();
+ assertNotNull("Client did not receive response message,", clientResponseMsg);
+ assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText());
}
- public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
+ public void setUpClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception
{
- try
- {
- Connection conn = getConnection("test", "server", "guest");
-
- ((AMQConnection) conn).setConnectionListener(this);
-
- Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- conn.start();
-
- MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null);
-
- Queue queue = session.createQueue("Invalid");
-
- // Send a message that we will wait to be sent, this should give the broker time to close the connection
- // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
- // queue existence.
- ((org.apache.qpid.jms.MessageProducer) sender).send(queue, session.createTextMessage("test"),
- DeliveryMode.NON_PERSISTENT, 0, 0L, false, false);
-
- // Test the connection with a valid consumer
- // This may not work as the session may be closed before the queue or consumer creation can occur.
- // The correct JMSexception with linked error will only occur when the close method is recevied whilst in
- // the failover safe block
- session.createConsumer(session.createQueue("example.RequestQueue")).close();
-
- //Connection should now be closed and will throw the exception caused by the above send
- conn.close();
-
- fail("Close is not expected to succeed.");
- }
- catch (IllegalStateException e)
- {
- _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error.");
- }
- catch (JMSException e)
- {
- check403Exception(e.getLinkedException());
- }
+ writeACLFile("test", "ACL ALLOW-LOG client ACCESS VIRTUALHOST",
+ "ACL ALLOW-LOG client ALL QUEUE",
+ "ACL ALLOW-LOG client ALL EXCHANGE");
}
-
- @Override
- public String getConfig()
+ public void testClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception
{
- return "config-systests-aclv2.xml";
- }
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
- @Override
- public List<String> getHostList()
- {
- return Arrays.asList("test", "test2");
+ // create kipper
+ Topic kipper = sess.createTopic("kipper");
+ TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
+
+ subscriber.close();
+ sess.unsubscribe("kipper");
+
+ //Do something to show connection is active.
+ sess.rollback();
+ conn.close();
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java
deleted file mode 100644
index 290cbfdc14..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java
+++ /dev/null
@@ -1,186 +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.security.acl;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.qpid.server.logging.management.LoggingManagementMBean;
-import org.apache.qpid.test.utils.JMXTestUtils;
-
-/**
- * Tests that ACLs can be applied to mangement operations that do not correspond to a specific AMQP object.
- *
- * Theses tests use the logging component, exposed as the {@link LoggingManagementMBean}, to get and set properties.
- */
-public class ExternalAdminACLTest extends AbstractACLTestCase
-{
- private static final String CATEGORY_PRIORITY = "LogManMBeanTest.category.priority";
- private static final String CATEGORY_LEVEL = "LogManMBeanTest.category.level";
- private static final String LOGGER_LEVEL = "LogManMBeanTest.logger.level";
-
- private static final String NEWLINE = System.getProperty("line.separator");
-
- private JMXTestUtils _jmx;
- private File _testConfigFile;
-
- @Override
- public String getConfig()
- {
- return "config-systests-aclv2.xml";
- }
-
- @Override
- public List<String> getHostList()
- {
- return Arrays.asList("global");
- }
-
- @Override
- public void setUp() throws Exception
- {
- _testConfigFile = createTempTestLog4JConfig();
-
- _jmx = new JMXTestUtils(this, "admin", "admin");
- _jmx.setUp();
- super.setUp();
- _jmx.open();
- }
-
- @Override
- public void tearDown() throws Exception
- {
- _jmx.close();
- super.tearDown();
- }
-
- private File createTempTestLog4JConfig()
- {
- File tmpFile = null;
- try
- {
- tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp");
- tmpFile.deleteOnExit();
-
- FileWriter fstream = new FileWriter(tmpFile);
- BufferedWriter writer = new BufferedWriter(fstream);
-
- writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE);
- writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE);
-
- writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " +
- "threshold=\"null\">"+NEWLINE);
-
- writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE);
- writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE);
- writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE);
- writer.write(" </layout>"+NEWLINE);
- writer.write(" </appender>"+NEWLINE);
-
- //Example of a 'category' with a 'priority'
- writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_PRIORITY +"\">"+NEWLINE);
- writer.write(" <priority value=\"info\"/>"+NEWLINE);
- writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
- writer.write(" </category>"+NEWLINE);
-
- //Example of a 'category' with a 'level'
- writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_LEVEL +"\">"+NEWLINE);
- writer.write(" <level value=\"warn\"/>"+NEWLINE);
- writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
- writer.write(" </category>"+NEWLINE);
-
- //Example of a 'logger' with a 'level'
- writer.write(" <logger additivity=\"true\" name=\"" + LOGGER_LEVEL + "\">"+NEWLINE);
- writer.write(" <level value=\"error\"/>"+NEWLINE);
- writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
- writer.write(" </logger>"+NEWLINE);
-
- //'root' logger
- writer.write(" <root>"+NEWLINE);
- writer.write(" <priority value=\"info\"/>"+NEWLINE);
- writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
- writer.write(" </root>"+NEWLINE);
-
- writer.write("</log4j:configuration>"+NEWLINE);
-
- writer.flush();
- writer.close();
- }
- catch (IOException e)
- {
- fail("Unable to create temporary test log4j configuration");
- }
-
- return tmpFile;
- }
-
- public void testGetAllLoggerLevels() throws Exception
- {
- String[] levels = _jmx.getAvailableLoggerLevels();
- for (int i = 0; i < levels.length; i++)
- {
- System.out.println(levels[i]);
- }
- assertEquals("Got incorrect number of log levels", 9, levels.length);
- }
-
- public void testGetAllLoggerLevelsDenied() throws Exception
- {
- try
- {
- _jmx.getAvailableLoggerLevels();
- fail("Got list of log levels");
- }
- catch (Exception e)
- {
- // Exception throws
- e.printStackTrace();
- assertEquals("Permission denied: Access getAvailableLoggerLevels", e.getMessage());
- }
- }
-
- public void testChangeLoggerLevel() throws Exception
- {
- String oldLevel = _jmx.getRuntimeRootLoggerLevel();
- System.out.println("old level = " + oldLevel);
- _jmx.setRuntimeRootLoggerLevel("DEBUG");
- String newLevel = _jmx.getRuntimeRootLoggerLevel();
- System.out.println("new level = " + newLevel);
- assertEquals("Logging level was not changed", "DEBUG", newLevel);
- }
-
- public void testChangeLoggerLevelDenied() throws Exception
- {
- try
- {
- _jmx.setRuntimeRootLoggerLevel("DEBUG");
- fail("Logging level was changed");
- }
- catch (Exception e)
- {
- assertEquals("Permission denied: Update setRuntimeRootLoggerLevel", e.getMessage());
- }
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
index 4eb328f091..f2ac590a3c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
@@ -25,6 +25,7 @@ import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQDestination;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.test.utils.FailoverBaseCase;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
import javax.jms.Connection;
import javax.jms.JMSException;
@@ -39,13 +40,12 @@ import javax.naming.NamingException;
import java.util.Enumeration;
import java.util.Random;
-public class QueueBrowserAutoAckTest extends FailoverBaseCase
+public class QueueBrowserAutoAckTest extends QpidBrokerTestCase
{
protected Connection _clientConnection;
protected Session _clientSession;
protected Queue _queue;
protected static final String MESSAGE_ID_PROPERTY = "MessageIDProperty";
- protected boolean CLUSTERED = Boolean.getBoolean("profile.clustered");
public void setUp() throws Exception
{
@@ -94,22 +94,6 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
sendMessages(producerConnection, num);
}
- protected void sendMessages(String connection, int num) throws JMSException
- {
- Connection producerConnection = null;
- try
- {
- producerConnection = getConnectionFactory(connection).createConnection("guest", "guest");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- fail("Unable to lookup connection in JNDI.");
- }
- sendMessages(producerConnection, num);
- }
-
-
protected void sendMessages(Connection producerConnection, int messageSendCount) throws JMSException
{
producerConnection.start();
@@ -440,88 +424,4 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
validate(messages);
}
- /**
- * Testing that a QueueBrowser doesn't actually consume messages from a broker when it fails over.
- * @throws JMSException
- */
- public void testFailoverWithQueueBrowser() throws JMSException
- {
- int messages = 5;
-
- sendMessages("connection1", messages);
- if (!CLUSTERED)
- {
- sendMessages("connection2", messages);
- }
-
- checkQueueDepth(messages);
-
- _logger.info("Creating Queue Browser");
- QueueBrowser queueBrowser = _clientSession.createBrowser(_queue);
-
- long queueDepth = 0;
-
- try
- {
- queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _queue);
- }
- catch (AMQException e)
- {
- fail("Caught exception getting queue depth: " + e.getMessage());
- }
-
- assertEquals("Session reports Queue depth not as expected", messages, queueDepth);
-
- int msgCount = 0;
- int failPoint = 0;
-
- failPoint = new Random().nextInt(messages) + 1;
-
- Enumeration msgs = queueBrowser.getEnumeration();
- while (msgs.hasMoreElements())
- {
- msgs.nextElement();
- msgCount++;
-
- if (msgCount == failPoint)
- {
- failBroker(getFailingPort());
- }
- }
-
- assertTrue("We should get atleast " + messages + " msgs (found " + msgCount +").", msgCount >= messages);
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("QBAAT Found " + msgCount + " messages total in browser");
- }
-
- //Close browser
- queueBrowser.close();
-
- _logger.info("Closed Queue Browser, validating messages on broker.");
-
- //Validate all messages still on Broker
- validate(messages);
- }
-
- public void testFailoverAsQueueBrowserCreated() throws JMSException
- {
- // The IoServiceListenerSupport seems to get stuck in with a managedSession that isn't closing when requested.
- // So it hangs waiting for the session.
- int messages = 50;
-
- sendMessages("connection1", messages);
- if (!CLUSTERED)
- {
- sendMessages("connection2", messages);
- }
-
- failBroker(getFailingPort());
-
- checkQueueDepth(messages);
-
- //Validate all messages still on Broker 1
- validate(messages);
- }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
index 3068deecf8..5b01c28fcc 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
@@ -37,16 +37,13 @@ import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.ConnectionURL;
import org.apache.qpid.test.utils.FailoverBaseCase;
public class FailoverTest extends FailoverBaseCase implements ConnectionListener
{
private static final Logger _logger = Logger.getLogger(FailoverTest.class);
- private static final String QUEUE = "queue";
private static final int DEFAULT_NUM_MESSAGES = 10;
private static final int DEFAULT_SEED = 20080921;
protected int numMessages = 0;
@@ -192,7 +189,6 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
protected void runP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws JMSException, NamingException
{
- Message msg = null;
int toProduce = totalMessages;
_logger.debug("===================================================================");
@@ -281,45 +277,6 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
}
/**
- * The client used to have a fixed timeout of 4 minutes after which failover would no longer work.
- * Check that this code has not regressed
- *
- * @throws Exception if something unexpected occurs in the test.
- */
-
- public void test4MinuteFailover() throws Exception
- {
- ConnectionURL connectionURL = getConnectionFactory().getConnectionURL();
-
- int RETRIES = 4;
- int DELAY = 60000;
-
- //Set up a long delay on and large number of retries
- BrokerDetails details = connectionURL.getBrokerDetails(1);
- details.setProperty(BrokerDetails.OPTIONS_RETRY, String.valueOf(RETRIES));
- details.setProperty(BrokerDetails.OPTIONS_CONNECT_DELAY, String.valueOf(DELAY));
-
- connection = new AMQConnection(connectionURL);
-
- ((AMQConnection) connection).setConnectionListener(this);
-
- //Start the connection
- connection.start();
-
- long FAILOVER_DELAY = ((long)RETRIES * (long)DELAY);
-
- // Use Nano seconds as it is more accurate for comparision.
- long failTime = System.nanoTime() + FAILOVER_DELAY * 1000000;
-
- //Fail the first broker
- causeFailure(getFailingPort(), FAILOVER_DELAY + DEFAULT_FAILOVER_TIME);
-
- //Reconnection should occur
- assertTrue("Failover did not take long enough", System.nanoTime() > failTime);
- }
-
-
- /**
* The idea is to run a failover test in a loop by failing over
* to the other broker each time.
*/
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java
index a7efe4922b..2d326d73b8 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java
@@ -58,7 +58,6 @@ public class JMSDestinationTest extends QpidBrokerTestCase
private Connection _connection;
private Session _session;
- private static final String USER = "admin";
private CountDownLatch _receiveMessage;
private Message _message;
@@ -143,7 +142,7 @@ public class JMSDestinationTest extends QpidBrokerTestCase
public void testMovedToQueue() throws Exception
{
// Setup JMXUtils
- JMXTestUtils jmxUtils = new JMXTestUtils(this, USER, USER);
+ JMXTestUtils jmxUtils = new JMXTestUtils(this);
jmxUtils.setUp();
// Open the JMX Connection
jmxUtils.open();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
deleted file mode 100644
index d73d012250..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.ack;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.util.FileUtils;
-
-import javax.jms.Connection;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.Session;
-import javax.jms.TransactionRolledBackException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.io.File;
-
-/**
- * The AcknowlegeAfterFailoverOnMessageTests
- *
- * Extends the OnMessage AcknowledgeTests to validate that after the client has
- * failed over that the client can still receive and ack messages.
- *
- * All the AcknowledgeTest ack modes are exercised here though some are disabled
- * due to know issues (e.g. DupsOk, AutoAck : QPID-143 and the clientAck
- * and dirtyClientAck due to QPID-1816)
- *
- * This class has two main test structures, overrides of AcknowledgeOnMessageTest
- * to perform the clean acking based on session ack mode and a series of dirty
- * ack tests that test what happends if you receive a message then try and ack
- * AFTER you have failed over.
- *
- *
- */
-public class AcknowledgeAfterFailoverOnMessageTest extends AcknowledgeOnMessageTest implements ConnectionListener
-{
-
- protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
- private MessageListener _listener = null;
-
- @Override
- public void setUp() throws Exception
- {
- super.setUp();
- NUM_MESSAGES = 10;
- }
-
- /**
- * Override default init to add connectionListener so we can verify that
- * failover took place
- *
- * @param transacted create a transacted session for this test
- * @param mode if not transacted what ack mode to use for this test
- *
- * @throws Exception if a problem occured during test setup.
- */
- @Override
- public void init(boolean transacted, int mode) throws Exception
- {
- super.init(transacted, mode);
- ((AMQConnection) _connection).setConnectionListener(this);
- // Override the listener for the dirtyAck testing.
- if (_listener != null)
- {
- _consumer.setMessageListener(_listener);
- }
- }
-
- /**
- * Prepare the broker for the next round.
- *
- * Called after acknowledging the messsage this method shuts the current
- * broker down connnects to the new broker and send a new message for the
- * client to failover to and receive.
- *
- * It ends by restarting the orignal broker so that the cycle can repeat.
- *
- * When we are able to cluster the java broker then will not need to do the
- * message repopulation or QPID_WORK clearing. All that we will need to do
- * is send the initial NUM_MESSAGES during startup and then bring the
- * brokers down at the right time to cause the client to fail between them.
- *
- * @param index
- * @throws Exception
- */
- protected void prepBroker(int index) throws Exception
- {
- // Alternate killing the broker based on the message index we are at.
-
- if (index % 2 == 0)
- {
- failBroker(getFailingPort());
- // Clean up the failed broker
- FileUtils.delete(new File(System.getProperty("QPID_WORK") + "/" + getFailingPort()), true);
- }
- else
- {
- failBroker(getPort());
- // Clean up the failed broker
- FileUtils.delete(new File(System.getProperty("QPID_WORK") + "/" + getPort()), true);
- }
-
- _failoverCompleted = new CountDownLatch(1);
-
- _logger.info("AAFOMT: prepNewBroker for message send");
- Connection connection = getConnection();
-
- try
- {
-
- //Stop the connection whilst we repopulate the broker, or the no_ack
- // test will drain the msgs before we can check we put the right number
- // back on again.
-
- Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
- // ensure destination is created.
- session.createConsumer(_queue).close();
-
-
- // If this is the last message then we can skip the send.
- // But we MUST ensure that we have created the queue with the
- // above createConsumer(_queue).close() as the test will end by
- // testing the queue depth which will fail if we don't ensure we
- // declare the queue.
- // index is 0 based so we need to check +1 against NUM_MESSAGES
- if ((index + 1) == NUM_MESSAGES)
- {
- return;
- }
-
-
- sendMessage(session, _queue, 1, index + 1, 0);
-
- // Validate that we have the message on the queue
- // In NoAck mode though the messasge may already have been sent to
- // the client so we have to skip the vaildation.
- if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
- {
- assertEquals("Wrong number of messages on queue", 1,
- ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
- }
-
-
- }
- catch (Exception e)
- {
- fail("Unable to prep new broker," + e.getMessage());
- }
- finally
- {
- connection.close();
- }
-
- try
- {
-
- //Restart the broker
- if (index % 2 == 0)
- {
- startBroker(getFailingPort());
- }
- else
- {
- startBroker(getPort());
- }
- }
- catch (Exception e)
- {
- fail("Unable to start failover broker," + e.getMessage());
- }
-
- }
-
- @Override
- public void doAcknowlegement(Message msg) throws JMSException
- {
- //Acknowledge current message
- super.doAcknowlegement(msg);
-
- try
- {
- prepBroker(msg.getIntProperty(INDEX));
- }
- catch (Exception e)
- {
- // Provide details of what went wrong with the stack trace
- e.printStackTrace();
- fail("Unable to prep new broker," + e);
- }
- }
-
- // Instance varilable for DirtyAcking test
- int _msgCount = 0;
- boolean _cleaned = false;
-
- class DirtyAckingHandler implements MessageListener
- {
- /**
- * Validate first message but do nothing with it.
- *
- * Failover
- *
- * The receive the message again
- *
- * @param message
- */
- public void onMessage(Message message)
- {
- // Stop processing if we have an error and had to stop running.
- if (_receivedAll.getCount() == 0)
- {
- _logger.debug("Dumping msgs due to error(" + _causeOfFailure.get().getMessage() + "):" + message);
- return;
- }
-
- try
- {
- // Check we have the next message as expected
- assertNotNull("Message " + _msgCount + " not correctly received.", message);
- assertEquals("Incorrect message received", _msgCount, message.getIntProperty(INDEX));
-
- if (_msgCount == 0 && _failoverCompleted.getCount() != 0)
- {
- // This is the first message we've received so lets fail the broker
-
- failBroker(getFailingPort());
-
- repopulateBroker();
-
- _logger.error("Received first msg so failing over");
-
- return;
- }
-
- _msgCount++;
-
- // Don't acknowlege the first message after failover so we can commit
- // them together
- if (_msgCount == 1)
- {
- _logger.error("Received first msg after failover ignoring:" + _msgCount);
-
- // Acknowledge the first message if we are now on the cleaned pass
- if (_cleaned)
- {
- _receivedAll.countDown();
- }
-
- return;
- }
-
- if (_consumerSession.getTransacted())
- {
- try
- {
- _consumerSession.commit();
- if (!_cleaned)
- {
- fail("Session is dirty we should get an TransactionRolledBackException");
- }
- }
- catch (TransactionRolledBackException trbe)
- {
- //expected path
- }
- }
- else
- {
- try
- {
- message.acknowledge();
- if (!_cleaned)
- {
- fail("Session is dirty we should get an IllegalStateException");
- }
- }
- catch (javax.jms.IllegalStateException ise)
- {
- assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
- // Recover the sesion and try again.
- _consumerSession.recover();
- }
- }
-
- // Acknowledge the last message if we are in a clean state
- // this will then trigger test teardown.
- if (_cleaned)
- {
- _receivedAll.countDown();
- }
-
- //Reset message count so we can try again.
- _msgCount = 0;
- _cleaned = true;
- }
- catch (Exception e)
- {
- // If something goes wrong stop and notifiy main thread.
- fail(e);
- }
- }
- }
-
- /**
- * Test that Acking/Committing a message received before failover causes
- * an exception at commit/ack time.
- *
- * Expected behaviour is that in:
- * * tx mode commit() throws a transacted RolledBackException
- * * client ack mode throws an IllegalStateException
- *
- * @param transacted is this session trasacted
- * @param mode What ack mode should be used if not trasacted
- *
- * @throws Exception if something goes wrong.
- */
- protected void testDirtyAcking(boolean transacted, int mode) throws Exception
- {
- NUM_MESSAGES = 2;
- _listener = new DirtyAckingHandler();
-
- super.testAcking(transacted, mode);
- }
-
- public void testDirtyClientAck() throws Exception
- {
- testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
- }
-
- public void testDirtyAckingTransacted() throws Exception
- {
- testDirtyAcking(true, Session.SESSION_TRANSACTED);
- }
-
- private void repopulateBroker() throws Exception
- {
- // Repopulate this new broker so we can test what happends after failover
-
- //Get the connection to the first (main port) broker.
- Connection connection = getConnection();
- // Use a transaction to send messages so we can be sure they arrive.
- Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
- // ensure destination is created.
- session.createConsumer(_queue).close();
-
- sendMessage(session, _queue, NUM_MESSAGES);
-
- assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
- ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
-
- connection.close();
- }
-
- // AMQConnectionListener Interface.. used so we can validate that we
- // actually failed over.
-
- public void bytesSent(long count)
- {
- }
-
- public void bytesReceived(long count)
- {
- }
-
- public boolean preFailover(boolean redirect)
- {
- //Allow failover
- return true;
- }
-
- public boolean preResubscribe()
- {
- //Allow failover
- return true;
- }
-
- public void failoverComplete()
- {
- _failoverCompleted.countDown();
- }
-
- /**
- * Override so we can block until failover has completd
- *
- * @param port
- */
- @Override
- public void failBroker(int port)
- {
- super.failBroker(port);
-
- try
- {
- if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
- {
- // Use an exception so that we use our local fail() that notifies the main thread of failure
- throw new Exception("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
- }
-
- }
- catch (Exception e)
- {
- // Use an exception so that we use our local fail() that notifies the main thread of failure
- fail(e);
- }
- }
-
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
deleted file mode 100644
index acc7d5a4c1..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
-package org.apache.qpid.test.unit.ack;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.util.FileUtils;
-
-import javax.jms.Connection;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.Session;
-import javax.jms.TransactionRolledBackException;
-import java.io.File;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- *
- */
-public class AcknowledgeAfterFailoverTest extends AcknowledgeTest implements ConnectionListener
-{
-
- protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
-
- @Override
- public void setUp() throws Exception
- {
- super.setUp();
- // This must be even for the test to run correctly.
- // Otherwise we will kill the standby broker
- // not the one we are connected to.
- // The test will still pass but it will not be exactly
- // as described.
- NUM_MESSAGES = 6;
- }
-
- /**
- * Override default init to add connectionListener so we can verify that
- * failover took place
- *
- * @param transacted create a transacted session for this test
- * @param mode if not transacted what ack mode to use for this test
- * @throws Exception if a problem occured during test setup.
- */
- @Override
- protected void init(boolean transacted, int mode) throws Exception
- {
- super.init(transacted, mode);
- ((AMQConnection) _connection).setConnectionListener(this);
- }
-
- protected void prepBroker(int index) throws Exception
- {
- // If this is the last message then we can skip the prep.
- if (index == NUM_MESSAGES)
- {
- return;
- }
-
- if (index % 2 == 0)
- {
- failBroker(getFailingPort());
- // Clean up the failed broker
- FileUtils.delete(new File(System.getProperty("QPID_WORK") + "/" + getFailingPort()), true);
- }
- else
- {
- failBroker(getPort());
- // Clean up the failed broker
- FileUtils.delete(new File(System.getProperty("QPID_WORK") + "/" + getPort()), true);
- }
-
- // Ensure we have the right data on the broker
- Connection connection = getConnection();
- Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
- // ensure destination is created.
- session.createConsumer(_queue).close();
-
- sendMessage(session, _queue, 1, index + 1, 0);
-
- if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
- {
- assertEquals("Wrong number of messages on queue", 1,
- ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
- }
-
- connection.close();
-
- try
- {
- if (index % 2 == 0)
- {
- startBroker(getFailingPort());
- }
- else
- {
- startBroker(getPort());
- }
- }
- catch (Exception e)
- {
- fail("Unable to start failover broker," + e.getMessage());
- }
- }
-
- @Override
- public void doAcknowlegement(Message msg) throws JMSException
- {
- //Acknowledge current message
- super.doAcknowlegement(msg);
-
- try
- {
- prepBroker(msg.getIntProperty(INDEX));
- }
- catch (Exception e)
- {
- fail("Unable to prep new broker," + e.getMessage());
- }
-
- }
-
- /**
- * Test that Acking/Committing a message received before failover causes
- * an exception at commit/ack time.
- * <p/>
- * Expected behaviour is that in:
- * * tx mode commit() throws a transacted RolledBackException
- * * client ack mode throws an IllegalStateException
- *
- * @param transacted is this session trasacted
- * @param mode What ack mode should be used if not trasacted
- * @throws Exception if something goes wrong.
- */
- protected void testDirtyAcking(boolean transacted, int mode) throws Exception
- {
- NUM_MESSAGES = 2;
- //Test Dirty Failover Fails
- init(transacted, mode);
-
- _connection.start();
-
- Message msg = _consumer.receive(1500);
-
- int count = 0;
- assertNotNull("Message " + count + " not correctly received.", msg);
- assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX));
-
- //Don't acknowledge just prep the next broker. Without changing count
- // Prep the new broker to have all all the messages so we can validate
- // that they can all be correctly received.
- try
- {
-
- //Stop the connection so we can validate the number of message count
- // on the queue is correct after failover
- _connection.stop();
- failBroker(getFailingPort());
-
- //Get the connection to the first (main port) broker.
- Connection connection = getConnection();//getConnectionFactory("connection1").getConnectionURL());
- // Use a transaction to send messages so we can be sure they arrive.
- Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
- // ensure destination is created.
- session.createConsumer(_queue).close();
-
- sendMessage(session, _queue, NUM_MESSAGES);
-
- assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
- ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
-
- connection.close();
-
- //restart connection
- _connection.start();
- }
- catch (Exception e)
- {
- fail("Unable to prep new broker," + e.getMessage());
- }
-
- // Consume the next message - don't check what it is as a normal would
- // assume it is msg 1 but as we've fallen over it is msg 0 again.
- msg = _consumer.receive(1500);
-
- if (_consumerSession.getTransacted())
- {
- try
- {
- _consumerSession.commit();
- fail("Session is dirty we should get an TransactionRolledBackException");
- }
- catch (TransactionRolledBackException trbe)
- {
- //expected path
- }
- }
- else
- {
- try
- {
- msg.acknowledge();
- fail("Session is dirty we should get an IllegalStateException");
- }
- catch (javax.jms.IllegalStateException ise)
- {
- assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
- // Recover the sesion and try again.
- _consumerSession.recover();
- }
- }
-
- msg = _consumer.receive(1500);
- // Validate we now get the first message back
- assertEquals(0, msg.getIntProperty(INDEX));
-
- msg = _consumer.receive(1500);
- // and the second message
- assertEquals(1, msg.getIntProperty(INDEX));
-
- // And now verify that we can now commit the clean session
- if (_consumerSession.getTransacted())
- {
- _consumerSession.commit();
- }
- else
- {
- msg.acknowledge();
- }
-
- assertEquals("Wrong number of messages on queue", 0,
- ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
- }
-
- public void testDirtyClientAck() throws Exception
- {
- testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
- }
-
- public void testDirtyAckingTransacted() throws Exception
- {
- testDirtyAcking(true, Session.SESSION_TRANSACTED);
- }
-
- // AMQConnectionListener Interface.. used so we can validate that we
- // actually failed over.
-
- public void bytesSent(long count)
- {
- }
-
- public void bytesReceived(long count)
- {
- }
-
- public boolean preFailover(boolean redirect)
- {
- //Allow failover
- return true;
- }
-
- public boolean preResubscribe()
- {
- //Allow failover
- return true;
- }
-
- public void failoverComplete()
- {
- _failoverCompleted.countDown();
- }
-
- /**
- * Override so we can block until failover has completd
- *
- * @param port
- */
- @Override
- public void failBroker(int port)
- {
- super.failBroker(port);
-
- try
- {
- if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
- {
- fail("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
- }
- }
- catch (InterruptedException e)
- {
- fail("Failover was interrupted");
- }
- }
-
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
index efea57e5d2..12039caf25 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
@@ -23,7 +23,7 @@ package org.apache.qpid.test.unit.ack;
import org.apache.qpid.client.AMQDestination;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.test.utils.FailoverBaseCase;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
import javax.jms.Connection;
import javax.jms.JMSException;
@@ -39,7 +39,7 @@ import javax.jms.MessageProducer;
*
* The ack mode is provided from the various test methods.
*/
-public class AcknowledgeTest extends FailoverBaseCase
+public class AcknowledgeTest extends QpidBrokerTestCase
{
protected int NUM_MESSAGES;
protected Connection _connection;
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
deleted file mode 100644
index 13c78c1e14..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.ack;
-
-import java.util.concurrent.CountDownLatch;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.test.utils.QpidBrokerTestCase;
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-
-/**
- * This is a quick manual test to validate acking after failover with a
- * transacted session.
- *
- * Start an external broker then run this test. Std Err will print.
- * Sent Message: 1
- * Received Message: 1
- *
- * You can then restart the external broker, which will cause failover, which
- * will be complete when the following appears.
- *
- * Failover Complete
- *
- * A second message send/receive cycle is then done to validate that the
- * connection/session are still working.
- *
- */
-public class QuickAcking extends QpidBrokerTestCase implements ConnectionListener
-{
- protected AMQConnection _connection;
- protected Queue _queue;
- protected Session _session;
- protected MessageConsumer _consumer;
- private CountDownLatch _failedOver;
- private static final String INDEX = "INDEX";
- private int _count = 0;
-
- public void setUp()
- {
- // Prevent broker startup. Broker must be run manually.
- }
-
- public void test() throws Exception
- {
- _failedOver = new CountDownLatch(1);
-
- _connection = new AMQConnection("amqp://guest:guest@client/test?brokerlist='localhost?retries='20'&connectdelay='2000''");
-
- _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
- _queue = _session.createQueue("QAtest");
- _consumer = _session.createConsumer(_queue);
- _connection.setConnectionListener(this);
- _connection.start();
-
- sendAndReceive();
-
- _failedOver.await();
-
- sendAndReceive();
-
- }
-
- private void sendAndReceive()
- throws Exception
- {
- sendMessage();
-
- Message message = _consumer.receive();
-
- if (message.getIntProperty(INDEX) != _count)
- {
- throw new Exception("Incorrect message recieved:" + _count);
- }
-
- if (_session.getTransacted())
- {
- _session.commit();
- }
- System.err.println("Recevied Message:" + _count);
- }
-
- private void sendMessage() throws JMSException
- {
- MessageProducer producer = _session.createProducer(_queue);
- Message message = _session.createMessage();
- _count++;
- message.setIntProperty(INDEX, _count);
-
- producer.send(message);
- if (_session.getTransacted())
- {
- _session.commit();
- }
- producer.close();
-
- System.err.println("Sent Message:" + _count);
- }
-
- public void bytesSent(long count)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void bytesReceived(long count)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean preFailover(boolean redirect)
- {
- return true;
- }
-
- public boolean preResubscribe()
- {
- return true;
- }
-
- public void failoverComplete()
- {
- System.err.println("Failover Complete");
- _failedOver.countDown();
- }
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
index 66ca1d8345..2fd3811cb4 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
@@ -21,13 +21,14 @@ package org.apache.qpid.test.unit.ack;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.configuration.ClientProperties;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.Session;
import org.apache.qpid.test.utils.FailoverBaseCase;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
@@ -38,14 +39,15 @@ import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.TextMessage;
-import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-public class RecoverTest extends FailoverBaseCase
+public class RecoverTest extends QpidBrokerTestCase
{
static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
+ private static final int POSIITIVE_TIMEOUT = 2000;
+
private volatile Exception _error;
private AtomicInteger count;
@@ -64,7 +66,7 @@ public class RecoverTest extends FailoverBaseCase
protected void initTest() throws Exception
{
- _connection = (AMQConnection) getConnection("guest", "guest");
+ _connection = (AMQConnection) getConnection();
_consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue = _consumerSession.createQueue(getTestQueueName());
@@ -174,7 +176,7 @@ public class RecoverTest extends FailoverBaseCase
public void testAcknowledgePerConsumer() throws Exception
{
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ AMQConnection con = (AMQConnection) getConnection();
Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue =
@@ -186,7 +188,7 @@ public class RecoverTest extends FailoverBaseCase
MessageConsumer consumer = consumerSession.createConsumer(queue);
MessageConsumer consumer2 = consumerSession.createConsumer(queue2);
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
+ AMQConnection con2 = (AMQConnection) getConnection();
Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSession.createProducer(queue);
MessageProducer producer2 = producerSession.createProducer(queue2);
@@ -216,7 +218,7 @@ public class RecoverTest extends FailoverBaseCase
public void testRecoverInAutoAckListener() throws Exception
{
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ AMQConnection con = (AMQConnection) getConnection();
final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue =
@@ -304,16 +306,6 @@ public class RecoverTest extends FailoverBaseCase
_error = e;
}
- private void sendMessages(javax.jms.Session session,Destination dest,int count) throws Exception
- {
- MessageProducer prod = session.createProducer(dest);
- for (int i=0; i<count; i++)
- {
- prod.send(session.createTextMessage("Msg" + i));
- }
- prod.close();
- }
-
/**
* Goal : Check if ordering is preserved when doing recovery under reasonable circumstances.
* Refer QPID-2471 for more details.
@@ -325,48 +317,47 @@ public class RecoverTest extends FailoverBaseCase
* While doing so it will verify that the messages are not
* delivered out of order.
*/
- public void testOderingWithSyncConsumer() throws Exception
+ public void testOrderingWithSyncConsumer() throws Exception
{
- Connection con = (Connection) getConnection("guest", "guest");
+ Connection con = (Connection) getConnection();
javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Destination topic = session.createTopic("myTopic");
MessageConsumer cons = session.createConsumer(topic);
- sendMessages(session,topic,8);
+ sendMessage(session,topic,8);
con.start();
-
- int messageSeen = 0;
- int expectedMsg = 0;
+ int messageSeen = 0;
+ int expectedIndex = 0;
long startTime = System.currentTimeMillis();
- while(expectedMsg < 8)
+ while(expectedIndex < 8)
{
// Based on historical data, on average the test takes about 6 secs to complete.
if (System.currentTimeMillis() - startTime > 8000)
{
fail("Test did not complete on time. Received " +
- expectedMsg + " msgs so far. Please check the logs");
+ expectedIndex + " msgs so far. Please check the logs");
}
- Message message = cons.receive(2000);
- String text=((TextMessage) message).getText();
+ Message message = cons.receive(POSIITIVE_TIMEOUT);
+ int actualIndex = message.getIntProperty(INDEX);
- assertEquals("Received Message Out Of Order","Msg"+expectedMsg,text);
+ assertEquals("Received Message Out Of Order",expectedIndex, actualIndex);
//don't ack the message until we receive it 5 times
if( messageSeen < 5 )
{
- _logger.debug("Ignoring message " + text + " and calling recover");
+ _logger.debug("Ignoring message " + actualIndex + " and calling recover");
session.recover();
messageSeen++;
}
else
{
messageSeen = 0;
- expectedMsg++;
+ expectedIndex++;
message.acknowledge();
- _logger.debug("Acknowledging message " + text);
+ _logger.debug("Acknowledging message " + actualIndex);
}
}
}
@@ -377,44 +368,45 @@ public class RecoverTest extends FailoverBaseCase
* Same as testOderingWithSyncConsumer but using a
* Message Listener instead of a sync receive().
*/
- public void testOderingWithAsyncConsumer() throws Exception
+ public void testOrderingWithAsyncConsumer() throws Exception
{
- Connection con = (Connection) getConnection("guest", "guest");
+ Connection con = (Connection) getConnection();
final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Destination topic = session.createTopic("myTopic");
MessageConsumer cons = session.createConsumer(topic);
- sendMessages(session,topic,8);
+ sendMessage(session,topic,8);
con.start();
-
+
final Object lock = new Object();
final AtomicBoolean pass = new AtomicBoolean(false); //used as work around for 'final'
+
cons.setMessageListener(new MessageListener()
{
int messageSeen = 0;
- int expectedMsg = 0;
-
+ int expectedIndex = 0;
+
public void onMessage(Message message)
{
try
{
- String text = ((TextMessage) message).getText();
- assertEquals("Received Message Out Of Order","Msg"+expectedMsg,text);
+ int actualIndex = message.getIntProperty(INDEX);
+ assertEquals("Received Message Out Of Order", expectedIndex, actualIndex);
//don't ack the message until we receive it 5 times
if( messageSeen < 5 )
{
- _logger.debug("Ignoring message " + text + " and calling recover");
+ _logger.debug("Ignoring message " + actualIndex + " and calling recover");
session.recover();
messageSeen++;
}
else
{
messageSeen = 0;
- expectedMsg++;
+ expectedIndex++;
message.acknowledge();
- _logger.debug("Acknowledging message " + text);
- if (expectedMsg == 8)
+ _logger.debug("Acknowledging message " + actualIndex);
+ if (expectedIndex == 8)
{
pass.set(true);
synchronized (lock)
@@ -426,7 +418,7 @@ public class RecoverTest extends FailoverBaseCase
}
catch (JMSException e)
{
- fail("Exception : " + e.getMessage());
+ _error = e;
synchronized (lock)
{
lock.notifyAll();
@@ -440,10 +432,53 @@ public class RecoverTest extends FailoverBaseCase
// Based on historical data, on average the test takes about 6 secs to complete.
lock.wait(8000);
}
-
+
+ assertNull("Unexpected exception thrown by async listener", _error);
+
if (!pass.get())
{
fail("Test did not complete on time. Please check the logs");
}
}
+
+ /**
+ * This test ensures that after exhausting credit (prefetch), a {@link Session#recover()} successfully
+ * restores credit and allows the same messages to be re-received.
+ */
+ public void testRecoverSessionAfterCreditExhausted() throws Exception
+ {
+ final int maxPrefetch = 5;
+
+ // We send more messages than prefetch size. This ensure that if the 0-10 client were to
+ // complete the message commands before the rollback command is sent, the broker would
+ // send additional messages utilising the release credit. This problem would manifest itself
+ // as an incorrect message (or no message at all) being received at the end of the test.
+
+ final int numMessages = maxPrefetch * 2;
+
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch));
+
+ Connection con = (Connection) getConnection();
+ final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Destination dest = session.createQueue(getTestQueueName());
+ MessageConsumer cons = session.createConsumer(dest);
+
+ sendMessage(session, dest, numMessages);
+ con.start();
+
+ for (int i=0; i< maxPrefetch; i++)
+ {
+ final Message message = cons.receive(POSIITIVE_TIMEOUT);
+ assertNotNull("Received:" + i, message);
+ assertEquals("Unexpected message received", i, message.getIntProperty(INDEX));
+ }
+
+ _logger.info("Recovering");
+ session.recover();
+
+ Message result = cons.receive(POSIITIVE_TIMEOUT);
+ // Expect the first message
+ assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX));
+ }
+
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
index 57ff6a4fa2..474a425b28 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
@@ -54,7 +54,14 @@ public class AMQConnectionTest extends QpidBrokerTestCase
_topic = new AMQTopic(_connection.getDefaultTopicExchangeName(), new AMQShortString("mytopic"));
_queue = new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("myqueue"));
}
-
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ _connection.close();
+ super.tearDown(); //To change body of overridden methods use File | Settings | File Templates.
+ }
+
protected void createConnection() throws Exception
{
_connection = (AMQConnection) getConnection("guest", "guest");
@@ -67,16 +74,27 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testCreateQueueSession() throws JMSException
{
- _queueSession = _connection.createQueueSession(false, AMQSession.NO_ACKNOWLEDGE);
+ createQueueSession();
+ }
+
+ private void createQueueSession() throws JMSException
+ {
+ _queueSession = _connection.createQueueSession(false, AMQSession.NO_ACKNOWLEDGE);
}
public void testCreateTopicSession() throws JMSException
{
+ createTopicSession();
+ }
+
+ private void createTopicSession() throws JMSException
+ {
_topicSession = _connection.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
}
public void testTopicSessionCreateBrowser() throws JMSException
{
+ createTopicSession();
try
{
_topicSession.createBrowser(_queue);
@@ -94,6 +112,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testTopicSessionCreateQueue() throws JMSException
{
+ createTopicSession();
try
{
_topicSession.createQueue("abc");
@@ -111,6 +130,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testTopicSessionCreateTemporaryQueue() throws JMSException
{
+ createTopicSession();
try
{
_topicSession.createTemporaryQueue();
@@ -128,6 +148,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testQueueSessionCreateTemporaryTopic() throws JMSException
{
+ createQueueSession();
try
{
_queueSession.createTemporaryTopic();
@@ -145,6 +166,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testQueueSessionCreateTopic() throws JMSException
{
+ createQueueSession();
try
{
_queueSession.createTopic("abc");
@@ -162,6 +184,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testQueueSessionDurableSubscriber() throws JMSException
{
+ createQueueSession();
try
{
_queueSession.createDurableSubscriber(_topic, "abc");
@@ -179,6 +202,7 @@ public class AMQConnectionTest extends QpidBrokerTestCase
public void testQueueSessionUnsubscribe() throws JMSException
{
+ createQueueSession();
try
{
_queueSession.unsubscribe("abc");
@@ -243,25 +267,6 @@ public class AMQConnectionTest extends QpidBrokerTestCase
assertNotNull("Consumer B should have received the message",msg);
}
- public void testGetChannelID() throws Exception
- {
- long maxChannelID = _connection.getMaximumChannelCount();
- if (isBroker010())
- {
- //Usable numbers are 0 to N-1 when using 0-10
- //and 1 to N for 0-8/0-9
- maxChannelID = maxChannelID-1;
- }
- for (int j = 0; j < 3; j++)
- {
- int i = isBroker010() ? 0 : 1;
- for ( ; i <= maxChannelID; i++)
- {
- int id = _connection.getNextChannelID();
- assertEquals("Unexpected number on iteration "+j, i, id);
- _connection.deregisterSession(id);
- }
- }
- }
+
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java
new file mode 100644
index 0000000000..e59dac8c01
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java
@@ -0,0 +1,695 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Test that the MaxRedelivery feature works as expected, allowing the client to reject
+ * messages during rollback/recover whilst specifying they not be requeued if delivery
+ * to an application has been attempted a specified number of times.
+ *
+ * General approach: specify a set of messages which will cause the test client to then
+ * deliberately rollback/recover the session after consuming, and monitor that they are
+ * re-delivered the specified number of times before the client rejects them without requeue
+ * and then verify that they are not subsequently redelivered.
+ *
+ * Additionally, the queue used in the test is configured for DLQ'ing, and the test verifies
+ * that the messages rejected without requeue are then present on the appropriate DLQ.
+ */
+public class MaxDeliveryCountTest extends QpidBrokerTestCase
+{
+ private static final Logger _logger = Logger.getLogger(MaxDeliveryCountTest.class);
+ private boolean _failed;
+ private String _failMsg;
+ private static final int MSG_COUNT = 15;
+ private static final int MAX_DELIVERY_COUNT = 2;
+ private CountDownLatch _awaitCompletion;
+
+ public void setUp() throws Exception
+ {
+ //enable DLQ/maximumDeliveryCount support for all queues at the vhost level
+ setConfigurationProperty("virtualhosts.virtualhost.test.queues.maximumDeliveryCount",
+ String.valueOf(MAX_DELIVERY_COUNT));
+ setConfigurationProperty("virtualhosts.virtualhost.test.queues.deadLetterQueues",
+ String.valueOf(true));
+
+ //Ensure management is on
+ setConfigurationProperty("management.enabled", "true");
+ setConfigurationProperty("management.ssl.enabled", "false");
+
+ // Set client-side flag to allow the server to determine if messages
+ // dead-lettered or requeued.
+ setTestClientSystemProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, "server");
+
+ super.setUp();
+
+ boolean durableSub = isDurSubTest();
+
+ //declare the test queue
+ Connection consumerConnection = getConnection();
+ Session consumerSession = consumerConnection.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ Destination destination = getDestination(consumerSession, durableSub);
+ if(durableSub)
+ {
+ consumerSession.createDurableSubscriber((Topic)destination, getName()).close();
+ }
+ else
+ {
+ consumerSession.createConsumer(destination).close();
+ }
+
+ consumerConnection.close();
+
+ //Create Producer put some messages on the queue
+ Connection producerConnection = getConnection();
+ producerConnection.start();
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(getDestination(producerSession, durableSub));
+
+ for (int count = 1; count <= MSG_COUNT; count++)
+ {
+ Message msg = producerSession.createTextMessage(generateContent(count));
+ msg.setIntProperty("count", count);
+ producer.send(msg);
+ }
+
+ producerConnection.close();
+
+ _failed = false;
+ _awaitCompletion = new CountDownLatch(1);
+ }
+
+ private Destination getDestination(Session consumerSession, boolean durableSub) throws JMSException
+ {
+ if(durableSub)
+ {
+ return consumerSession.createTopic(getTestQueueName());
+ }
+ else
+ {
+ return consumerSession.createQueue(getTestQueueName());
+ }
+ }
+
+ private String generateContent(int count)
+ {
+ return "Message " + count + " content.";
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using onMessage() on a
+ * Client-Ack session.
+ */
+ public void testAsynchronousClientAckSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.CLIENT_ACKNOWLEDGE, redeliverMsgs, false, false);
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using onMessage() on a
+ * transacted session.
+ */
+ public void testAsynchronousTransactedSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.SESSION_TRANSACTED, redeliverMsgs, false, false);
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using onMessage() on an
+ * Auto-Ack session.
+ */
+ public void testAsynchronousAutoAckSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.AUTO_ACKNOWLEDGE, redeliverMsgs, false, false);
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using onMessage() on a
+ * Dups-OK session.
+ */
+ public void testAsynchronousDupsOkSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.DUPS_OK_ACKNOWLEDGE, redeliverMsgs, false, false);
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using recieve() on a
+ * Client-Ack session.
+ */
+ public void testSynchronousClientAckSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(3);
+ redeliverMsgs.add(14);
+
+ doTest(Session.CLIENT_ACKNOWLEDGE, redeliverMsgs, true, false);
+ }
+
+ /**
+ * Test that Max Redelivery is enforced when using recieve() on a
+ * transacted session.
+ */
+ public void testSynchronousTransactedSession() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.SESSION_TRANSACTED, redeliverMsgs, true, false);
+ }
+
+ public void testDurableSubscription() throws Exception
+ {
+ final ArrayList<Integer> redeliverMsgs = new ArrayList<Integer>();
+ redeliverMsgs.add(1);
+ redeliverMsgs.add(2);
+ redeliverMsgs.add(5);
+ redeliverMsgs.add(14);
+
+ doTest(Session.SESSION_TRANSACTED, redeliverMsgs, false, true);
+ }
+
+ public void doTest(final int deliveryMode, final ArrayList<Integer> redeliverMsgs, final boolean synchronous, final boolean durableSub) throws Exception
+ {
+ final Connection clientConnection = getConnection();
+
+ final boolean transacted = deliveryMode == Session.SESSION_TRANSACTED ? true : false;
+ final Session clientSession = clientConnection.createSession(transacted, deliveryMode);
+
+ MessageConsumer consumer;
+ Destination dest = getDestination(clientSession, durableSub);
+ AMQQueue checkQueue;
+ if(durableSub)
+ {
+ consumer = clientSession.createDurableSubscriber((Topic)dest, getName());
+ checkQueue = new AMQQueue("amq.topic", "clientid" + ":" + getName());
+ }
+ else
+ {
+ consumer = clientSession.createConsumer(dest);
+ checkQueue = (AMQQueue) dest;
+ }
+
+ assertEquals("The queue should have " + MSG_COUNT + " msgs at start",
+ MSG_COUNT, ((AMQSession<?,?>) clientSession).getQueueDepth(checkQueue));
+
+ clientConnection.start();
+
+ int expectedDeliveries = MSG_COUNT + ((MAX_DELIVERY_COUNT -1) * redeliverMsgs.size());
+
+ if(synchronous)
+ {
+ doSynchronousTest(clientSession, consumer, clientSession.getAcknowledgeMode(),
+ MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs);
+ }
+ else
+ {
+ addMessageListener(clientSession, consumer, clientSession.getAcknowledgeMode(),
+ MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs);
+
+ try
+ {
+ if (!_awaitCompletion.await(20, TimeUnit.SECONDS))
+ {
+ fail("Test did not complete in 20 seconds.");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ fail("Unable to wait for test completion");
+ throw e;
+ }
+
+ if(_failed)
+ {
+ fail(_failMsg);
+ }
+ }
+ consumer.close();
+
+ //check the source queue is now empty
+ assertEquals("The queue should have 0 msgs left", 0, ((AMQSession<?,?>) clientSession).getQueueDepth(checkQueue));
+
+ //check the DLQ has the required number of rejected-without-requeue messages
+ verifyDLQdepth(redeliverMsgs.size(), clientSession, durableSub);
+
+ if(isBrokerStorePersistent())
+ {
+ //restart the broker to verify persistence of the DLQ and the messages on it
+ clientConnection.close();
+
+ restartBroker();
+
+ final Connection clientConnection2 = getConnection();
+ final Session clientSession2 = clientConnection2.createSession(transacted, deliveryMode);
+ clientConnection2.start();
+
+ //verify the messages on the DLQ
+ verifyDLQcontent(clientConnection2, redeliverMsgs, getTestQueueName(), durableSub);
+ clientConnection2.close();
+ }
+ else
+ {
+
+ //verify the messages on the DLQ
+ verifyDLQcontent(clientConnection, redeliverMsgs, getTestQueueName(), durableSub);
+ clientConnection.close();
+ }
+
+ }
+
+ private void verifyDLQdepth(int expected, Session clientSession, boolean durableSub) throws AMQException
+ {
+ AMQDestination checkQueueDLQ;
+ if(durableSub)
+ {
+ checkQueueDLQ = new AMQQueue("amq.topic", "clientid" + ":" + getName() + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+ else
+ {
+ checkQueueDLQ = new AMQQueue("amq.direct", getTestQueueName() + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+
+ assertEquals("The DLQ should have " + expected + " msgs on it", expected,
+ ((AMQSession<?,?>) clientSession).getQueueDepth(checkQueueDLQ));
+ }
+
+ private void verifyDLQcontent(Connection clientConnection, List<Integer> redeliverMsgs, String destName, boolean durableSub) throws JMSException
+ {
+ Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageConsumer consumer;
+ if(durableSub)
+ {
+ if (isBroker010())
+ {
+ consumer = clientSession.createConsumer(clientSession.createQueue("clientid:" +getName() + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX));
+ }
+ else
+ {
+ consumer = clientSession.createDurableSubscriber(clientSession.createTopic(destName), getName() + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+ }
+ else
+ {
+ consumer = clientSession.createConsumer(
+ clientSession.createQueue(destName + AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX));
+ }
+
+ //keep track of the message we expect to still be on the DLQ
+ List<Integer> outstandingMessages = new ArrayList<Integer>(redeliverMsgs);
+ int numMsg = outstandingMessages.size();
+
+ for(int i = 0; i < numMsg; i++)
+ {
+ Message message = consumer.receive(250);
+
+ assertNotNull("failed to consume expected message " + i + " from DLQ", message);
+ assertTrue("message " + i + " was the wrong type", message instanceof TextMessage);
+
+ //using Integer here to allow removing the value from the list, using int
+ //would instead result in removal of the element at that index
+ Integer msgId = message.getIntProperty("count");
+
+ TextMessage txt = (TextMessage) message;
+ _logger.info("Received message " + msgId + " at " + i + " from the DLQ: " + txt.getText());
+
+ assertTrue("message " + i + " was not one of those which should have been on the DLQ",
+ redeliverMsgs.contains(msgId));
+ assertTrue("message " + i + " was not one of those expected to still be on the DLQ",
+ outstandingMessages.contains(msgId));
+ assertEquals("Message " + i + " content was not as expected", generateContent(msgId), txt.getText());
+
+ //remove from the list of outstanding msgs
+ outstandingMessages.remove(msgId);
+ }
+
+ if(outstandingMessages.size() > 0)
+ {
+ String failures = "";
+ for(Integer msg : outstandingMessages)
+ {
+ failures = failures.concat(msg + " ");
+ }
+ fail("some DLQ'd messages were not found on the DLQ: " + failures);
+ }
+ }
+
+ private void addMessageListener(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount,
+ final int expectedTotalNumberOfDeliveries, final ArrayList<Integer> redeliverMsgs) throws JMSException
+ {
+ if(deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE
+ || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE)
+ {
+ failAsyncTest("Max Delivery feature is not supported with this acknowledgement mode" +
+ "when using asynchronous message delivery.");
+ }
+
+ consumer.setMessageListener(new MessageListener()
+ {
+ private int _deliveryAttempts = 0; //number of times given message(s) have been seen
+ private int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover
+ private int _totalNumDeliveries = 0;
+ private int _expectedMessage = 1;
+
+ public void onMessage(Message message)
+ {
+ if(_failed || _awaitCompletion.getCount() == 0L)
+ {
+ //don't process anything else
+ return;
+ }
+
+ _totalNumDeliveries++;
+
+ if (message == null)
+ {
+ failAsyncTest("Should not get null messages");
+ return;
+ }
+
+ try
+ {
+ int msgId = message.getIntProperty("count");
+
+ _logger.info("Received message: " + msgId);
+
+ //check the message is the one we expected
+ if(_expectedMessage != msgId)
+ {
+ failAsyncTest("Expected message " + _expectedMessage + " , got message " + msgId);
+ return;
+ }
+
+ _expectedMessage++;
+
+ //keep track of the overall deliveries to ensure we don't see more than expected
+ if(_totalNumDeliveries > expectedTotalNumberOfDeliveries)
+ {
+ failAsyncTest("Expected total of " + expectedTotalNumberOfDeliveries +
+ " message deliveries, reached " + _totalNumDeliveries);
+ }
+
+ //check if this message is one chosen to be rolled back / recovered
+ if(redeliverMsgs.contains(msgId))
+ {
+ _numMsgsToBeRedelivered++;
+
+ //check if next message is going to be rolled back / recovered too
+ if(redeliverMsgs.contains(msgId +1))
+ {
+ switch(deliveryMode)
+ {
+ case Session.SESSION_TRANSACTED:
+ //skip on to next message immediately
+ return;
+ case Session.CLIENT_ACKNOWLEDGE:
+ //skip on to next message immediately
+ return;
+ case Session.DUPS_OK_ACKNOWLEDGE:
+ //fall through
+ case Session.AUTO_ACKNOWLEDGE:
+ //must recover session now or onMessage will ack, so
+ //just fall through the if
+ break;
+ }
+ }
+
+ _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen
+
+ _logger.debug("ROLLBACK/RECOVER");
+ switch(deliveryMode)
+ {
+ case Session.SESSION_TRANSACTED:
+ session.rollback();
+ break;
+ case Session.CLIENT_ACKNOWLEDGE:
+ //fall through
+ case Session.DUPS_OK_ACKNOWLEDGE:
+ //fall through
+ case Session.AUTO_ACKNOWLEDGE:
+ session.recover();
+ break;
+ }
+
+ if( _deliveryAttempts >= maxDeliveryCount)
+ {
+ //the client should have rejected the latest messages upon then
+ //above recover/rollback, adjust counts to compensate
+ _deliveryAttempts = 0;
+ }
+ else
+ {
+ //the message(s) should be redelivered, adjust expected message
+ _expectedMessage -= _numMsgsToBeRedelivered;
+ }
+ _logger.debug("XXX _expectedMessage: " + _expectedMessage + " _deliveryAttempts : " + _deliveryAttempts + " _numMsgsToBeRedelivered=" + _numMsgsToBeRedelivered);
+ //reset count of messages expected to be redelivered
+ _numMsgsToBeRedelivered = 0;
+ }
+ else
+ {
+ //consume the message
+ switch(deliveryMode)
+ {
+ case Session.SESSION_TRANSACTED:
+ session.commit();
+ break;
+ case Session.CLIENT_ACKNOWLEDGE:
+ message.acknowledge();
+ break;
+ case Session.DUPS_OK_ACKNOWLEDGE:
+ //fall-through
+ case Session.AUTO_ACKNOWLEDGE:
+ //do nothing, onMessage will ack on exit.
+ break;
+ }
+ }
+
+ if (msgId == MSG_COUNT)
+ {
+ //if this is the last message let the test complete.
+ if (expectedTotalNumberOfDeliveries == _totalNumDeliveries)
+ {
+ _awaitCompletion.countDown();
+ }
+ else
+ {
+ failAsyncTest("Last message received, but we have not had the " +
+ "expected number of total delivieres. Received " + _totalNumDeliveries + " Expecting : " + expectedTotalNumberOfDeliveries);
+ }
+ }
+ }
+ catch (JMSException e)
+ {
+ failAsyncTest(e.getMessage());
+ }
+ }
+ });
+ }
+
+ private void failAsyncTest(String msg)
+ {
+ _logger.error("Failing test because: " + msg);
+ _failMsg = msg;
+ _failed = true;
+ _awaitCompletion.countDown();
+ }
+
+ private void doSynchronousTest(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount,
+ final int expectedTotalNumberOfDeliveries, final ArrayList<Integer> redeliverMsgs) throws JMSException, AMQException, InterruptedException
+ {
+ if(deliveryMode == Session.AUTO_ACKNOWLEDGE
+ || deliveryMode == Session.DUPS_OK_ACKNOWLEDGE
+ || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE
+ || deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE)
+ {
+ fail("Max Delivery feature is not supported with this acknowledgement mode" +
+ "when using synchronous message delivery.");
+ }
+
+ int _deliveryAttempts = 0; //number of times given message(s) have been seen
+ int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover
+ int _totalNumDeliveries = 0;
+ int _expectedMessage = 1;
+
+ while(!_failed)
+ {
+ Message message = consumer.receive(1000);
+
+ _totalNumDeliveries++;
+
+ if (message == null)
+ {
+ fail("Should not get null messages");
+ return;
+ }
+
+ try
+ {
+ int msgId = message.getIntProperty("count");
+
+ _logger.info("Received message: " + msgId);
+
+ //check the message is the one we expected
+ assertEquals("Unexpected message.", _expectedMessage, msgId);
+
+ _expectedMessage++;
+
+ //keep track of the overall deliveries to ensure we don't see more than expected
+ assertTrue("Exceeded expected total number of deliveries.",
+ _totalNumDeliveries <= expectedTotalNumberOfDeliveries );
+
+ //check if this message is one chosen to be rolled back / recovered
+ if(redeliverMsgs.contains(msgId))
+ {
+ //keep track of the number of messages we will have redelivered
+ //upon rollback/recover
+ _numMsgsToBeRedelivered++;
+
+ if(redeliverMsgs.contains(msgId +1))
+ {
+ //next message is going to be rolled back / recovered too.
+ //skip ahead to it
+ continue;
+ }
+
+ _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen
+
+ switch(deliveryMode)
+ {
+ case Session.SESSION_TRANSACTED:
+ session.rollback();
+ break;
+ case Session.CLIENT_ACKNOWLEDGE:
+ session.recover();
+
+ //sleep then do a synchronous op to give the broker
+ //time to resend all the messages
+ Thread.sleep(500);
+ ((AMQSession) session).sync();
+ break;
+ }
+
+ if( _deliveryAttempts >= maxDeliveryCount)
+ {
+ //the client should have rejected the latest messages upon then
+ //above recover/rollback, adjust counts to compensate
+ _deliveryAttempts = 0;
+ }
+ else
+ {
+ //the message(s) should be redelivered, adjust expected message
+ _expectedMessage -= _numMsgsToBeRedelivered;
+ }
+
+ //As we just rolled back / recovered, we must reset the
+ //count of messages expected to be redelivered
+ _numMsgsToBeRedelivered = 0;
+ }
+ else
+ {
+ //consume the message
+ switch(deliveryMode)
+ {
+ case Session.SESSION_TRANSACTED:
+ session.commit();
+ break;
+ case Session.CLIENT_ACKNOWLEDGE:
+ message.acknowledge();
+ break;
+ }
+ }
+
+ if (msgId == MSG_COUNT)
+ {
+ //if this is the last message let the test complete.
+ assertTrue("Last message received, but we have not had the " +
+ "expected number of total delivieres",
+ expectedTotalNumberOfDeliveries == _totalNumDeliveries);
+
+ break;
+ }
+ }
+ catch (JMSException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ private boolean isDurSubTest()
+ {
+ return getTestQueueName().contains("DurableSubscription");
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java
deleted file mode 100644
index 91e681131f..0000000000
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.client.connection;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.test.utils.QpidBrokerTestCase;
-import org.apache.qpid.url.URLSyntaxException;
-
-import javax.jms.ExceptionListener;
-import javax.jms.JMSException;
-import javax.jms.MessageConsumer;
-import javax.jms.Session;
-import java.util.concurrent.CountDownLatch;
-
-public class CloseAfterConnectionFailureTest extends QpidBrokerTestCase implements ExceptionListener
-{
- private int sessionCount = 0;
- AMQConnection connection;
- Session session;
- MessageConsumer consumer;
- private CountDownLatch _latch = new CountDownLatch(1);
- private JMSException _fail;
-
- public void testNoFailover() throws URLSyntaxException, Exception,
- InterruptedException, JMSException
- {
- //This test uses hard coded connection string so only runs on InVM case
- if (!isExternalBroker())
- {
- String connectionString = "amqp://guest:guest@/test?brokerlist='vm://:1?connectdelay='500',retries='3'',failover='nofailover'";
-
- AMQConnectionURL url = new AMQConnectionURL(connectionString);
-
- try
- {
- //Start the connection so it will use the retries
- connection = new AMQConnection(url);
-
- connection.setExceptionListener(this);
-
- session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- consumer = session.createConsumer(session.createQueue(this.getName()));
-
- //Kill connection
- stopBroker();
-
- _latch.await();
-
- if (_fail != null)
- {
- _fail.printStackTrace(System.out);
- fail("Exception thrown:" + _fail.getMessage());
- }
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
- }
- }
-
- public void onException(JMSException e)
- {
- System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
- try
- {
- consumer.close();
- }
- catch (JMSException jmse)
- {
- System.out.println("Consumer close failed with:" + jmse.getMessage());
- _fail = jmse;
- }
- System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
- try
- {
- //Note that if we actually do session.close() we will lock up as the session will never receive a frame
- // from the
- ((AMQSession) session).close(10);
- }
- catch (JMSException jmse)
- {
- System.out.println("Session close failed with:" + jmse.getMessage());
- _fail = jmse;
- }
- System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
-
- try
- {
- connection.close();
- }
- catch (JMSException jmse)
- {
- System.out.println("Session close failed with:" + jmse.getMessage());
- _fail = jmse;
- }
- System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
-
- _latch.countDown();
-
- }
-
-}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java
index 545081fb43..a313475b11 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.test.unit.client.connection;
import org.apache.qpid.client.AMQConnection;
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
index 9ea116ae53..d3d9cf2984 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
@@ -841,4 +841,147 @@ public class DurableSubscriptionTest extends QpidBrokerTestCase
e.printStackTrace();
}
}
+
+ /**
+ * Tests that a subscriber created on a same <i>session</i> as producer with
+ * no local true does not receive messages.
+ */
+ public void testNoLocalOnSameSession() throws Exception
+ {
+ Connection connection = getConnection();
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic topic = session.createTopic(getTestQueueName());
+ MessageProducer producer = session.createProducer(topic);
+ TopicSubscriber subscriber = null;
+ try
+ {
+ subscriber = session.createDurableSubscriber(topic, getTestName(), null, true);
+ connection.start();
+
+ producer.send(createNextMessage(session, 1));
+
+ Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNull("Unexpected message received", m);
+ }
+ finally
+ {
+ session.unsubscribe(getTestName());
+ }
+ }
+
+
+ /**
+ * Tests that a subscriber created on a same <i>connection</i> but separate
+ * <i>sessionM</i> as producer with no local true does not receive messages.
+ */
+ public void testNoLocalOnSameConnection() throws Exception
+ {
+ Connection connection = getConnection();
+
+ Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic topic = consumerSession.createTopic(getTestQueueName());
+ MessageProducer producer = producerSession.createProducer(topic);
+
+ TopicSubscriber subscriber = null;
+ try
+ {
+ subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true);
+ connection.start();
+
+ producer.send(createNextMessage(producerSession, 1));
+
+ Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNull("Unexpected message received", m);
+ }
+ finally
+ {
+ consumerSession.unsubscribe(getTestName());
+ }
+ }
+
+ /**
+ * Tests that if no-local is in use, that the messages are delivered when
+ * the client reconnects.
+ *
+ * Currently fails on the Java Broker due to QPID-3605.
+ */
+ public void testNoLocalMessagesNotDeliveredAfterReconnection() throws Exception
+ {
+ Connection connection = getConnection();
+
+ Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic topic = consumerSession.createTopic(getTestQueueName());
+ MessageProducer producer = producerSession.createProducer(topic);
+
+ TopicSubscriber subscriber = null;
+ try
+ {
+ subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true);
+ connection.start();
+
+ producer.send(createNextMessage(producerSession, 1));
+
+ Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNull("Unexpected message received", m);
+
+ connection.close();
+
+ connection = getConnection();
+
+ consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true);
+ connection.start();
+ m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNull("Message should not be received on a new connection", m);
+ }
+ finally
+ {
+ consumerSession.unsubscribe(getTestName());
+ }
+ }
+
+ /**
+ * Tests that messages are delivered normally to a subscriber on a separate connection despite
+ * the use of durable subscriber with no-local on the first connection.
+ */
+ public void testNoLocalSubscriberAndSubscriberOnSeparateConnection() throws Exception
+ {
+ Connection noLocalConnection = getConnection();
+ Connection connection = getConnection();
+
+ String noLocalSubId1 = getTestName() + "subId1";
+ String subId = getTestName() + "subId2";
+
+ Session noLocalSession = noLocalConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic noLocalTopic = noLocalSession.createTopic(getTestQueueName());
+
+ Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic topic = consumerSession.createTopic(getTestQueueName());
+
+ TopicSubscriber noLocalSubscriber = null;
+ TopicSubscriber subscriber = null;
+ try
+ {
+ MessageProducer producer = noLocalSession.createProducer(noLocalTopic);
+ noLocalSubscriber = noLocalSession.createDurableSubscriber(noLocalTopic, noLocalSubId1, null, true);
+ subscriber = consumerSession.createDurableSubscriber(topic, subId, null, true);
+ noLocalConnection.start();
+ connection.start();
+
+ producer.send(createNextMessage(noLocalSession, 1));
+
+ Message m1 = noLocalSubscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNull("Subscriber on nolocal connection should not receive message", m1);
+
+ Message m2 = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Subscriber on non-nolocal connection should receive message", m2);
+ }
+ finally
+ {
+ noLocalSession.unsubscribe(noLocalSubId1);
+ consumerSession.unsubscribe(subId);
+ }
+ }
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
index bc2cbe714f..b8b5a29a43 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
@@ -22,10 +22,13 @@ package org.apache.qpid.test.unit.transacted;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.configuration.ClientProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.*;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -36,17 +39,16 @@ import java.util.concurrent.TimeUnit;
*/
public class CommitRollbackTest extends QpidBrokerTestCase
{
- protected AMQConnection conn;
- protected String queue = "direct://amq.direct//Qpid.Client.Transacted.CommitRollback.queue";
- protected static int testMethod = 0;
- protected String payload = "xyzzy";
+ private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class);
+ private static final int POSIITIVE_TIMEOUT = 2000;
+
+ protected AMQConnection _conn;
private Session _session;
private MessageProducer _publisher;
private Session _pubSession;
private MessageConsumer _consumer;
- Queue _jmsQueue;
+ private Queue _jmsQueue;
- private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class);
private boolean _gotone = false;
private boolean _gottwo = false;
private boolean _gottwoRedelivered = false;
@@ -54,31 +56,24 @@ public class CommitRollbackTest extends QpidBrokerTestCase
protected void setUp() throws Exception
{
super.setUp();
- testMethod++;
- queue += testMethod;
- newConnection();
}
private void newConnection() throws Exception
{
- conn = (AMQConnection) getConnection("guest", "guest");
+ _logger.debug("calling newConnection()");
+ _conn = (AMQConnection) getConnection();
- _session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
+ _session = _conn.createSession(true, Session.SESSION_TRANSACTED);
- _jmsQueue = _session.createQueue(queue);
+ final String queueName = getTestQueueName();
+ _jmsQueue = _session.createQueue(queueName);
_consumer = _session.createConsumer(_jmsQueue);
- _pubSession = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
+ _pubSession = _conn.createSession(true, Session.SESSION_TRANSACTED);
- _publisher = _pubSession.createProducer(_pubSession.createQueue(queue));
+ _publisher = _pubSession.createProducer(_pubSession.createQueue(queueName));
- conn.start();
- }
-
- protected void tearDown() throws Exception
- {
- conn.close();
- super.tearDown();
+ _conn.start();
}
/**
@@ -88,6 +83,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testPutThenDisconnect() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -96,7 +93,7 @@ public class CommitRollbackTest extends QpidBrokerTestCase
_publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
_logger.info("reconnecting without commit");
- conn.close();
+ _conn.close();
newConnection();
@@ -116,6 +113,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testPutThenCloseDisconnect() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -127,7 +126,7 @@ public class CommitRollbackTest extends QpidBrokerTestCase
_publisher.close();
_logger.info("reconnecting without commit");
- conn.close();
+ _conn.close();
newConnection();
@@ -148,6 +147,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testPutThenRollback() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -171,6 +172,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testGetThenDisconnect() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -186,7 +189,7 @@ public class CommitRollbackTest extends QpidBrokerTestCase
assertNotNull("retrieved message is null", msg);
_logger.info("closing connection");
- conn.close();
+ _conn.close();
newConnection();
@@ -207,6 +210,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testGetThenCloseDisconnect() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -224,7 +229,7 @@ public class CommitRollbackTest extends QpidBrokerTestCase
_logger.info("reconnecting without commit");
_consumer.close();
- conn.close();
+ _conn.close();
newConnection();
@@ -245,6 +250,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testGetThenRollback() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -283,6 +290,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testGetThenCloseRollback() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -324,6 +333,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testSend2ThenRollback() throws Exception
{
+ newConnection();
+
int run = 0;
while (run < 10)
{
@@ -424,6 +435,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
*/
public void testSend2ThenCloseAfter1andTryAgain() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -470,6 +483,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
public void testPutThenRollbackThenGet() throws Exception
{
+ newConnection();
+
assertTrue("session is not transacted", _session.getTransacted());
assertTrue("session is not transacted", _pubSession.getTransacted());
@@ -501,13 +516,15 @@ public class CommitRollbackTest extends QpidBrokerTestCase
/**
* Qpid-1163
- * Check that when commt is called inside onMessage then
+ * Check that when commit is called inside onMessage then
* the last message is nor redelivered.
*
* @throws Exception
*/
- public void testCommitWhithinOnMessage() throws Exception
+ public void testCommitWithinOnMessage() throws Exception
{
+ newConnection();
+
Queue queue = (Queue) getInitialContext().lookup("queue");
// create a consumer
MessageConsumer cons = _session.createConsumer(queue);
@@ -518,8 +535,8 @@ public class CommitRollbackTest extends QpidBrokerTestCase
_session.commit();
_logger.info("Sent message to queue");
CountDownLatch cd = new CountDownLatch(1);
- cons.setMessageListener(new CommitWhithinOnMessageListener(cd));
- conn.start();
+ cons.setMessageListener(new CommitWithinOnMessageListener(cd));
+ _conn.start();
cd.await(30, TimeUnit.SECONDS);
if( cd.getCount() > 0 )
{
@@ -527,10 +544,10 @@ public class CommitRollbackTest extends QpidBrokerTestCase
}
// Check that the message has been dequeued
_session.close();
- conn.close();
- conn = (AMQConnection) getConnection("guest", "guest");
- conn.start();
- Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ _conn.close();
+ _conn = (AMQConnection) getConnection();
+ _conn.start();
+ Session session = _conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
cons = session.createConsumer(queue);
message = cons.receiveNoWait();
if(message != null)
@@ -546,10 +563,55 @@ public class CommitRollbackTest extends QpidBrokerTestCase
}
}
- private class CommitWhithinOnMessageListener implements MessageListener
+ /**
+ * This test ensures that after exhausting credit (prefetch), a {@link Session#rollback()} successfully
+ * restores credit and allows the same messages to be re-received.
+ */
+ public void testRollbackSessionAfterCreditExhausted() throws Exception
+ {
+ final int maxPrefetch= 5;
+
+ // We send more messages than prefetch size. This ensure that if the 0-10 client were to
+ // complete the message commands before the rollback command is sent, the broker would
+ // send additional messages utilising the release credit. This problem would manifest itself
+ // as an incorrect message (or no message at all) being received at the end of the test.
+
+ final int numMessages = maxPrefetch * 2;
+
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch));
+
+ newConnection();
+
+ assertEquals("Prefetch not reset", maxPrefetch, ((AMQSession<?, ?>)_session).getDefaultPrefetch());
+
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ sendMessage(_pubSession, _publisher.getDestination(), numMessages);
+ _pubSession.commit();
+
+ for (int i=0 ;i< maxPrefetch; i++)
+ {
+ final Message message = _consumer.receive(POSIITIVE_TIMEOUT);
+ assertNotNull("Received:" + i, message);
+ assertEquals("Unexpected message received", i, message.getIntProperty(INDEX));
+ }
+
+ _logger.info("Rolling back");
+ _session.rollback();
+
+ _logger.info("Receiving messages");
+
+ Message result = _consumer.receive(POSIITIVE_TIMEOUT);;
+ assertNotNull("Message expected", result);
+ // Expect the first message
+ assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX));
+ }
+
+ private class CommitWithinOnMessageListener implements MessageListener
{
private CountDownLatch _cd;
- private CommitWhithinOnMessageListener(CountDownLatch cd)
+ private CommitWithinOnMessageListener(CountDownLatch cd)
{
_cd = cd;
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
index 045deab052..653ab8f733 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
@@ -135,197 +135,172 @@ public class TransactedTest extends QpidBrokerTestCase
public void testCommit() throws Exception
{
- try
- {
-// add some messages
- _logger.info("Send prep A");
- prepProducer1.send(prepSession.createTextMessage("A"));
- _logger.info("Send prep B");
- prepProducer1.send(prepSession.createTextMessage("B"));
- _logger.info("Send prep C");
- prepProducer1.send(prepSession.createTextMessage("C"));
-
- // send and receive some messages
- _logger.info("Send X to Q2");
- producer2.send(session.createTextMessage("X"));
- _logger.info("Send Y to Q2");
- producer2.send(session.createTextMessage("Y"));
- _logger.info("Send Z to Q2");
- producer2.send(session.createTextMessage("Z"));
-
- _logger.info("Read A from Q1");
- expect("A", consumer1.receive(1000));
- _logger.info("Read B from Q1");
- expect("B", consumer1.receive(1000));
- _logger.info("Read C from Q1");
- expect("C", consumer1.receive(1000));
-
- // commit
- _logger.info("session commit");
- session.commit();
- _logger.info("Start test Connection");
- testCon.start();
-
- // ensure sent messages can be received and received messages are gone
- _logger.info("Read X from Q2");
- expect("X", testConsumer2.receive(1000));
- _logger.info("Read Y from Q2");
- expect("Y", testConsumer2.receive(1000));
- _logger.info("Read Z from Q2");
- expect("Z", testConsumer2.receive(1000));
-
- _logger.info("create test session on Q1");
- testConsumer1 = testSession.createConsumer(queue1);
- _logger.info("Read null from Q1");
- assertTrue(null == testConsumer1.receive(1000));
- _logger.info("Read null from Q2");
- assertTrue(null == testConsumer2.receive(1000));
- }
- catch (Throwable e)
- {
- e.printStackTrace();
- fail(e.getMessage());
- }
+ _logger.info("Send prep A");
+ prepProducer1.send(prepSession.createTextMessage("A"));
+ _logger.info("Send prep B");
+ prepProducer1.send(prepSession.createTextMessage("B"));
+ _logger.info("Send prep C");
+ prepProducer1.send(prepSession.createTextMessage("C"));
+
+ // send and receive some messages
+ _logger.info("Send X to Q2");
+ producer2.send(session.createTextMessage("X"));
+ _logger.info("Send Y to Q2");
+ producer2.send(session.createTextMessage("Y"));
+ _logger.info("Send Z to Q2");
+ producer2.send(session.createTextMessage("Z"));
+
+ _logger.info("Read A from Q1");
+ expect("A", consumer1.receive(1000));
+ _logger.info("Read B from Q1");
+ expect("B", consumer1.receive(1000));
+ _logger.info("Read C from Q1");
+ expect("C", consumer1.receive(1000));
+
+ // commit
+ _logger.info("session commit");
+ session.commit();
+ _logger.info("Start test Connection");
+ testCon.start();
+
+ // ensure sent messages can be received and received messages are gone
+ _logger.info("Read X from Q2");
+ expect("X", testConsumer2.receive(1000));
+ _logger.info("Read Y from Q2");
+ expect("Y", testConsumer2.receive(1000));
+ _logger.info("Read Z from Q2");
+ expect("Z", testConsumer2.receive(1000));
+
+ _logger.info("create test session on Q1");
+ testConsumer1 = testSession.createConsumer(queue1);
+ _logger.info("Read null from Q1");
+ assertTrue(null == testConsumer1.receive(1000));
+ _logger.info("Read null from Q2");
+ assertTrue(null == testConsumer2.receive(1000));
}
public void testRollback() throws Exception
{
- try
- {
-// add some messages
- _logger.info("Send prep RB_A");
- prepProducer1.send(prepSession.createTextMessage("RB_A"));
- _logger.info("Send prep RB_B");
- prepProducer1.send(prepSession.createTextMessage("RB_B"));
- _logger.info("Send prep RB_C");
- prepProducer1.send(prepSession.createTextMessage("RB_C"));
-
- _logger.info("Sending RB_X RB_Y RB_Z");
- producer2.send(session.createTextMessage("RB_X"));
- producer2.send(session.createTextMessage("RB_Y"));
- producer2.send(session.createTextMessage("RB_Z"));
- _logger.info("Receiving RB_A RB_B");
- expect("RB_A", consumer1.receive(1000));
- expect("RB_B", consumer1.receive(1000));
- // Don't consume 'RB_C' leave it in the prefetch cache to ensure rollback removes it.
- // Quick sleep to ensure 'RB_C' gets pre-fetched
- Thread.sleep(500);
-
- // rollback
- _logger.info("rollback");
- session.rollback();
-
- _logger.info("Receiving RB_A RB_B RB_C");
- // ensure sent messages are not visible and received messages are requeued
- expect("RB_A", consumer1.receive(1000), true);
- expect("RB_B", consumer1.receive(1000), true);
- expect("RB_C", consumer1.receive(1000), true);
- _logger.info("Starting new connection");
- testCon.start();
- testConsumer1 = testSession.createConsumer(queue1);
- _logger.info("Testing we have no messages left");
- assertTrue(null == testConsumer1.receive(1000));
- assertTrue(null == testConsumer2.receive(1000));
-
- session.commit();
-
- _logger.info("Testing we have no messages left after commit");
- assertTrue(null == testConsumer1.receive(1000));
- assertTrue(null == testConsumer2.receive(1000));
- }
- catch (Throwable e)
- {
- e.printStackTrace();
- fail(e.getMessage());
- }
+ // add some messages
+ _logger.info("Send prep RB_A");
+ prepProducer1.send(prepSession.createTextMessage("RB_A"));
+ _logger.info("Send prep RB_B");
+ prepProducer1.send(prepSession.createTextMessage("RB_B"));
+ _logger.info("Send prep RB_C");
+ prepProducer1.send(prepSession.createTextMessage("RB_C"));
+
+ _logger.info("Sending RB_X RB_Y RB_Z");
+ producer2.send(session.createTextMessage("RB_X"));
+ producer2.send(session.createTextMessage("RB_Y"));
+ producer2.send(session.createTextMessage("RB_Z"));
+ _logger.info("Receiving RB_A RB_B");
+ expect("RB_A", consumer1.receive(1000));
+ expect("RB_B", consumer1.receive(1000));
+ // Don't consume 'RB_C' leave it in the prefetch cache to ensure rollback removes it.
+ // Quick sleep to ensure 'RB_C' gets pre-fetched
+ Thread.sleep(500);
+
+ // rollback
+ _logger.info("rollback");
+ session.rollback();
+
+ _logger.info("Receiving RB_A RB_B RB_C");
+ // ensure sent messages are not visible and received messages are requeued
+ expect("RB_A", consumer1.receive(1000), true);
+ expect("RB_B", consumer1.receive(1000), true);
+ expect("RB_C", consumer1.receive(1000), isBroker010()?false:true);
+ _logger.info("Starting new connection");
+ testCon.start();
+ testConsumer1 = testSession.createConsumer(queue1);
+ _logger.info("Testing we have no messages left");
+ assertTrue(null == testConsumer1.receive(1000));
+ assertTrue(null == testConsumer2.receive(1000));
+
+ session.commit();
+
+ _logger.info("Testing we have no messages left after commit");
+ assertTrue(null == testConsumer1.receive(1000));
+ assertTrue(null == testConsumer2.receive(1000));
}
public void testResendsMsgsAfterSessionClose() throws Exception
{
- try
- {
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ AMQConnection con = (AMQConnection) getConnection("guest", "guest");
- Session consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
- AMQQueue queue3 = new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), false);
- MessageConsumer consumer = consumerSession.createConsumer(queue3);
+ Session consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
+ AMQQueue queue3 = new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), false);
+ MessageConsumer consumer = consumerSession.createConsumer(queue3);
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(true, Session.SESSION_TRANSACTED);
- MessageProducer producer = producerSession.createProducer(queue3);
+ AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
+ Session producerSession = con2.createSession(true, Session.SESSION_TRANSACTED);
+ MessageProducer producer = producerSession.createProducer(queue3);
- _logger.info("Sending four messages");
- producer.send(producerSession.createTextMessage("msg1"));
- producer.send(producerSession.createTextMessage("msg2"));
- producer.send(producerSession.createTextMessage("msg3"));
- producer.send(producerSession.createTextMessage("msg4"));
+ _logger.info("Sending four messages");
+ producer.send(producerSession.createTextMessage("msg1"));
+ producer.send(producerSession.createTextMessage("msg2"));
+ producer.send(producerSession.createTextMessage("msg3"));
+ producer.send(producerSession.createTextMessage("msg4"));
- producerSession.commit();
+ producerSession.commit();
- _logger.info("Starting connection");
- con.start();
- TextMessage tm = (TextMessage) consumer.receive();
- assertNotNull(tm);
- assertEquals("msg1", tm.getText());
+ _logger.info("Starting connection");
+ con.start();
+ TextMessage tm = (TextMessage) consumer.receive();
+ assertNotNull(tm);
+ assertEquals("msg1", tm.getText());
- consumerSession.commit();
+ consumerSession.commit();
- _logger.info("Received and committed first message");
- tm = (TextMessage) consumer.receive(1000);
- assertNotNull(tm);
- assertEquals("msg2", tm.getText());
+ _logger.info("Received and committed first message");
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg2", tm.getText());
- tm = (TextMessage) consumer.receive(1000);
- assertNotNull(tm);
- assertEquals("msg3", tm.getText());
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg3", tm.getText());
- tm = (TextMessage) consumer.receive(1000);
- assertNotNull(tm);
- assertEquals("msg4", tm.getText());
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg4", tm.getText());
- _logger.info("Received all four messages. Closing connection with three outstanding messages");
+ _logger.info("Received all four messages. Closing connection with three outstanding messages");
- consumerSession.close();
+ consumerSession.close();
- consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
+ consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
- consumer = consumerSession.createConsumer(queue3);
+ consumer = consumerSession.createConsumer(queue3);
- // no ack for last three messages so when I call recover I expect to get three messages back
- tm = (TextMessage) consumer.receive(3000);
- assertNotNull(tm);
- assertEquals("msg2", tm.getText());
- assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+ // no ack for last three messages so when I call recover I expect to get three messages back
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg2", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
- tm = (TextMessage) consumer.receive(3000);
- assertNotNull(tm);
- assertEquals("msg3", tm.getText());
- assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg3", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
- tm = (TextMessage) consumer.receive(3000);
- assertNotNull(tm);
- assertEquals("msg4", tm.getText());
- assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg4", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
- _logger.info("Received redelivery of three messages. Committing");
+ _logger.info("Received redelivery of three messages. Committing");
- consumerSession.commit();
+ consumerSession.commit();
- _logger.info("Called commit");
+ _logger.info("Called commit");
- tm = (TextMessage) consumer.receive(1000);
- assertNull(tm);
+ tm = (TextMessage) consumer.receive(1000);
+ assertNull(tm);
- _logger.info("No messages redelivered as is expected");
+ _logger.info("No messages redelivered as is expected");
- con.close();
- con2.close();
- }
- catch (Throwable e)
- {
- e.printStackTrace();
- fail(e.getMessage());
- }
+ con.close();
+ con2.close();
}
private void expect(String text, Message msg) throws JMSException
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
index 1fde6c7c73..3a1710671c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -51,18 +51,26 @@ import org.apache.qpid.management.common.mbeans.UserManagement;
*/
public class JMXTestUtils
{
- QpidBrokerTestCase _test;
- MBeanServerConnection _mbsc;
- JMXConnector _jmxc;
+ private static final String DEFAULT_PASSWORD = "admin";
+ private static final String DEFAULT_USERID = "admin";
- private String USER;
- private String PASSWORD;
+ private MBeanServerConnection _mbsc;
+ private JMXConnector _jmxc;
+
+ private final String _user;
+ private final String _password;
+ private final QpidBrokerTestCase _test;
public JMXTestUtils(QpidBrokerTestCase test, String user, String password)
{
_test = test;
- USER = user;
- PASSWORD = password;
+ _user = user;
+ _password = password;
+ }
+
+ public JMXTestUtils(QpidBrokerTestCase test)
+ {
+ this(test, DEFAULT_USERID, DEFAULT_PASSWORD);
}
public void setUp() throws IOException, ConfigurationException, Exception
@@ -73,7 +81,7 @@ public class JMXTestUtils
public void open() throws Exception
{
_jmxc = JMXConnnectionFactory.getJMXConnection(5000, "127.0.0.1",
- _test.getManagementPort(_test.getPort()), USER, PASSWORD);
+ _test.getManagementPort(_test.getPort()), _user, _password);
_mbsc = _jmxc.getMBeanServerConnection();
}
@@ -319,6 +327,12 @@ public class JMXTestUtils
return getManagedObject(managedClass, objectName);
}
+ public boolean isManagedObjectExist(String query)
+ {
+ return !queryObjects(query).isEmpty();
+
+ }
+
public <T> T getManagedObject(Class<T> managedClass, ObjectName objectName)
{
return MBeanServerInvocationHandler.newProxyInstance(_mbsc, objectName, managedClass, false);
@@ -370,7 +384,7 @@ public class JMXTestUtils
}
/**
- * Retrive {@link ServerInformation} JMX MBean.
+ * Retrieve {@link ServerInformation} JMX MBean.
*/
public ServerInformation getServerInformation()
{
@@ -387,7 +401,7 @@ public class JMXTestUtils
}
/**
- * Retrive all {@link ManagedConnection} objects.
+ * Retrieve all {@link ManagedConnection} objects.
*/
public List<ManagedConnection> getAllManagedConnections()
{
@@ -402,7 +416,7 @@ public class JMXTestUtils
}
/**
- * Retrive all {@link ManagedConnection} objects for a particular virtual host.
+ * Retrieve all {@link ManagedConnection} objects for a particular virtual host.
*/
public List<ManagedConnection> getManagedConnections(String vhost)
{
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
index bb44aea659..f680a20288 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
@@ -823,7 +823,7 @@ public class QpidBrokerTestCase extends QpidTestCase
* @throws ConfigurationException when loading the current config file
* @throws IOException when writing the new config file
*/
- protected void setConfigurationProperty(String property, String value)
+ public void setConfigurationProperty(String property, String value)
throws ConfigurationException, IOException
{
// Choose which file to write the property to based on prefix.
@@ -945,7 +945,7 @@ public class QpidBrokerTestCase extends QpidTestCase
protected boolean isJavaBroker()
{
- return _brokerLanguage.equals("java") || _brokerType.equals("vm");
+ return _brokerLanguage.equals("java");
}
protected boolean isCppBroker()
@@ -955,7 +955,7 @@ public class QpidBrokerTestCase extends QpidTestCase
protected boolean isExternalBroker()
{
- return !_brokerType.equals("vm"); //TODO
+ return !isInternalBroker();
}
protected boolean isInternalBroker()
@@ -1326,7 +1326,7 @@ public class QpidBrokerTestCase extends QpidTestCase
*/
public void reloadBrokerSecurityConfig() throws Exception
{
- JMXTestUtils jmxu = new JMXTestUtils(this, "admin" , "admin");
+ JMXTestUtils jmxu = new JMXTestUtils(this);
jmxu.open();
try
diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes
index 39b4d542db..66a20bcfc1 100755
--- a/qpid/java/test-profiles/CPPExcludes
+++ b/qpid/java/test-profiles/CPPExcludes
@@ -20,6 +20,9 @@
// QPID-3391: the C++ broker does not currently validate the exchange creation arguments
org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testCreateExchangeWithNonsenseArgs
+// QPID-3576: Java client issue. MessageConsumer#close() time-out.
+org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testDeleteOptions
+
//This test requires SSL, but SSL is only enabled for the C++ broker in the cpp.ssl test profile
//which runs *all* the tests with SSL, so this one can be excluded safely enough
org.apache.qpid.test.unit.client.AMQSSLConnectionTest#*
@@ -27,9 +30,6 @@ org.apache.qpid.test.unit.client.AMQSSLConnectionTest#*
org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
org.apache.qpid.client.ResetMessageListenerTest#*
-// This test is not finished
-org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
-
// Those tests are testing 0.8 specific semantics
org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P
org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P
@@ -54,6 +54,12 @@ org.apache.qpid.server.queue.AMQPriorityQueueTest#*
// the 0-10 c++ broker does not implement the extended LVQ semantics which the Java Broker does
org.apache.qpid.server.queue.ConflationQueueTest#*
+// the 0-10 c++ broker does not implement sorted queues
+org.apache.qpid.server.queue.SortedQueueTest#*
+
+// the 0-10 c++ broker does not implement DLQ
+org.apache.qpid.test.unit.client.MaxDeliveryCountTest#*
+
//this test checks explicitly for 0-8 flow control semantics
org.apache.qpid.test.client.FlowControlTest#*
@@ -83,9 +89,6 @@ org.apache.qpid.test.client.QueueBrowsingFlowToDiskTest#*
// This test currently does not pick up the runtime location of the nonVm queueBacking store.
org.apache.qpid.test.unit.close.FlowToDiskBackingQueueDeleteTest#*
-// This test may use QpidTestCase but it is not using the getConnection and is hardwired to InVM
-org.apache.qpid.test.unit.client.connection.CloseAfterConnectionFailureTest#*
-
//QPID-1818 : 0-10 Client code path does not correctly restore a transacted session after failover.
org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
@@ -134,13 +137,6 @@ org.apache.qpid.test.client.message.SelectorTest#testRuntimeSelectorError
//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
org.apache.qpid.server.queue.ProducerFlowControlTest#*
-//QPID-1950 : Commit to test this failure. This is a MINA only failure so it cannot be tested when using 010.
-org.apache.qpid.server.failover.MessageDisappearWithIOExceptionTest#*
-
-// These are recent test additions that are failing with the c++ broker
-// Temporarily disabling until properly investigated.
-org.apache.qpid.test.unit.ack.FailoverBeforeConsumingRecoverTest#*
-
org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage#*
//Excluded due to QPID-1447 : CPP broker does not have SlowConsumer Disconnection
@@ -176,14 +172,3 @@ org.apache.qpid.server.management.AMQUserManagementMBeanTest#*
// QPID-3133: On 0-10, the exception listener is currently not invoked when reconnection fails to occurs.
org.apache.qpid.server.failover.FailoverMethodTest#*
-//QPID-3468: exclude QueueBrowser related failover tests
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
diff --git a/qpid/java/test-profiles/CPPNoPrefetchExcludes b/qpid/java/test-profiles/CPPNoPrefetchExcludes
index ebcd430161..e10b2fa659 100644
--- a/qpid/java/test-profiles/CPPNoPrefetchExcludes
+++ b/qpid/java/test-profiles/CPPNoPrefetchExcludes
@@ -19,13 +19,6 @@
org.apache.qpid.test.unit.transacted.TransactedTest#testRollback
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-
org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurabilityNOACK
org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurabilityNOACKSessionPerConnection
org.apache.qpid.test.unit.xa.TopicTest#testMigrateDurableSubscriber
diff --git a/qpid/java/test-profiles/Excludes b/qpid/java/test-profiles/Excludes
index b1edd07f87..8cad91ef2d 100644
--- a/qpid/java/test-profiles/Excludes
+++ b/qpid/java/test-profiles/Excludes
@@ -29,18 +29,6 @@ org.apache.qpid.server.logging.MemoryMessageStoreLoggingTest#testMessageStoreClo
// QPID-3424 : Test fails to start external broker due to Derby Exception.
org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#*
-// QPID-1816 : Client Ack has not been addressed
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testDirtyClientAck
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testClientAck
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testDirtyClientAck
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testClientAck
-
-
-// QPID-143 : Failover can occur between receive and ack but we don't stop the ack.
-// Just fully disable both tests as they are highlighting to many Java Client race conditions
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#*
-org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#*
-
// QPID-2418 : The queue backing the dur sub is not currently deleted at subscription change, so the test will fail.
org.apache.qpid.test.unit.ct.DurableSubscriberTest#testResubscribeWithChangedSelectorAndRestart
diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes
index e7718b982d..59cb5066f1 100755
--- a/qpid/java/test-profiles/Java010Excludes
+++ b/qpid/java/test-profiles/Java010Excludes
@@ -42,19 +42,12 @@ org.apache.qpid.server.logging.ChannelLoggingTest#testChannelStartsFlowStopped
org.apache.qpid.server.logging.ChannelLoggingTest#testChannelStartConsumerFlowStarted
org.apache.qpid.server.logging.SubscriptionLoggingTest#testSubscriptionSuspend
-// 0-10 Broker does not have a JMX connection MBean
-org.apache.qpid.management.jmx.ManagementActorLoggingTest#testConnectionCloseViaManagement
-org.apache.qpid.management.jmx.MessageConnectionStatisticsTest#*
-
// 0-10 is not supported by the MethodRegistry
org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#*
//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
org.apache.qpid.server.queue.ProducerFlowControlTest#*
-//QPID-1950 : Commit to test this failure. This is a MINA only failure so it cannot be tested when using 010.
-org.apache.qpid.server.failover.MessageDisappearWithIOExceptionTest#*
-
//QPID-1864: rollback with subscriptions does not work in 0-10 yet
org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage
@@ -71,22 +64,7 @@ org.apache.qpid.server.failover.FailoverMethodTest#*
org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testCreateExchangeWithArgs
org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testSessionCreateTopicWithExchangeArgs
-// QPID-1935: the following tests are failing on 0.10 profiles
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-
// QPID-3432: These tests test the behaviour of 0-8..-0-9-1 specific system property (amqj.default_syncwrite_timeout)
org.apache.qpid.test.client.timeouts.SyncWaitTimeoutDelayTest#*
org.apache.qpid.test.client.timeouts.SyncWaitDelayTest#*
-//QPID-3468: exclude QueueBrowser related failover tests
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
diff --git a/qpid/java/test-profiles/JavaExcludes b/qpid/java/test-profiles/JavaExcludes
index 8de36cbd9a..08e16ff216 100644
--- a/qpid/java/test-profiles/JavaExcludes
+++ b/qpid/java/test-profiles/JavaExcludes
@@ -28,13 +28,6 @@ org.apache.qpid.test.client.queue.QueuePolicyTest#testRejectPolicy
//Moved from JavaStandaloneExcludes when it was removed
///////////////////////////////////////////////////////
-// QPID-3426: The following test is broken.
-// This is a long running test so should exclude from normal runs
-org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
-
-// This test may use QpidTestCase but it is not using the getConnection and is hardwired to InVM
-org.apache.qpid.test.unit.client.connection.CloseAfterConnectionFailureTest#*
-
//QPID-1818, QPID-1821 : Client code path does not correctly restore a transacted session after failover.
org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
@@ -43,3 +36,6 @@ org.apache.qpid.jms.xa.XAResourceTest#*
//The Java broker doesnt support client auth
org.apache.qpid.client.ssl.SSLTest#testMultipleCertsInSingleStore
+
+//QPID-3605 Durable subscriber with no-local true receives messages on re-connection
+org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testNoLocalMessagesNotDeliveredAfterReconnection
diff --git a/qpid/java/test-profiles/JavaPre010Excludes b/qpid/java/test-profiles/JavaPre010Excludes
index 68feaf1e2b..057d7c2c44 100644
--- a/qpid/java/test-profiles/JavaPre010Excludes
+++ b/qpid/java/test-profiles/JavaPre010Excludes
@@ -33,6 +33,7 @@ org.apache.qpid.test.client.destination.AddressBasedDestinationTest#*
org.apache.qpid.test.client.queue.QueuePolicyTest#testRingPolicy
org.apache.qpid.test.client.queue.QueuePolicyTest#testRejectPolicy
org.apache.qpid.test.unit.message.JMSPropertiesTest#testApplicationProperties
+org.apache.qpid.server.queue.AddressBasedSortedQueueTest#*
// Those tests are written against the 0.10 path
org.apache.qpid.test.unit.message.UTF8Test#*
diff --git a/qpid/java/test-profiles/python_tests/Java010PythonExcludes b/qpid/java/test-profiles/python_tests/Java010PythonExcludes
index 10e6298634..069003b0b8 100644
--- a/qpid/java/test-profiles/python_tests/Java010PythonExcludes
+++ b/qpid/java/test-profiles/python_tests/Java010PythonExcludes
@@ -66,19 +66,8 @@ qpid.tests.messaging.endpoints.SessionTests.testDoubleCommit
qpid_tests.broker_0_10.message.MessageTests.test_credit_flow_bytes
qpid_tests.broker_0_10.message.MessageTests.test_window_flow_bytes
-#QPID-3592 Fails to receive more messages after restart
-qpid_tests.broker_0_10.message.MessageTests.test_window_stop
-
-#QPID-3539 Tests fail because is incorrectly being done per session and not connection
-qpid_tests.broker_0_10.message.MessageTests.test_no_local
+#QPID-3605 Durable subscriber with no-local true receives messages on re-connection
qpid_tests.broker_0_10.message.MessageTests.test_no_local_awkward
-qpid_tests.broker_0_10.message.MessageTests.test_no_local_exclusive_subscribe
-
-#QPID-3593 Priority Queue test failures
-qpid_tests.broker_0_10.priority.PriorityTests.test_browsing
-qpid_tests.broker_0_10.priority.PriorityTests.test_prioritised_delivery_1
-qpid_tests.broker_0_10.priority.PriorityTests.test_prioritised_delivery_2
-qpid_tests.broker_0_10.priority.PriorityTests.test_requeue
#QPID-3594 exclusive queues problem
qpid_tests.broker_0_10.queue.QueueTests.test_declare_exclusive
diff --git a/qpid/java/test-profiles/test_resources/ssl/java_broker_keystore.jks b/qpid/java/test-profiles/test_resources/ssl/java_broker_keystore.jks
index 4c4449e20d..86670fa34b 100644
--- a/qpid/java/test-profiles/test_resources/ssl/java_broker_keystore.jks
+++ b/qpid/java/test-profiles/test_resources/ssl/java_broker_keystore.jks
Binary files differ
diff --git a/qpid/java/tools/etc/perf-report.gnu b/qpid/java/tools/etc/perf-report.gnu
index 6d5020efb5..b7662b0bfe 100644
--- a/qpid/java/tools/etc/perf-report.gnu
+++ b/qpid/java/tools/etc/perf-report.gnu
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
set terminal png
set datafile separator ","
diff --git a/qpid/java/tools/src/main/java/org/apache/qpid/tools/Clock.java b/qpid/java/tools/src/main/java/org/apache/qpid/tools/Clock.java
index 37369959a8..979d2ef76f 100644
--- a/qpid/java/tools/src/main/java/org/apache/qpid/tools/Clock.java
+++ b/qpid/java/tools/src/main/java/org/apache/qpid/tools/Clock.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tools;
/**
diff --git a/qpid/java/tools/src/main/java/org/apache/qpid/tools/PerfTestController.java b/qpid/java/tools/src/main/java/org/apache/qpid/tools/PerfTestController.java
index 5c98c645f4..5fca1fa4bd 100644
--- a/qpid/java/tools/src/main/java/org/apache/qpid/tools/PerfTestController.java
+++ b/qpid/java/tools/src/main/java/org/apache/qpid/tools/PerfTestController.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tools;
import java.io.FileWriter;