summaryrefslogtreecommitdiff
path: root/qpid/java
diff options
context:
space:
mode:
authorMartin Ritchie <ritchiem@apache.org>2007-02-06 09:57:35 +0000
committerMartin Ritchie <ritchiem@apache.org>2007-02-06 09:57:35 +0000
commit1f4e634e6b86a4aff2b2553d5b44b1a1d5855779 (patch)
tree0550dd09b25591d0e0a76ce13bc0f98d36903e4e /qpid/java
parent886ab23a9dfca81951ebe12ff1ccaabf05f61d8d (diff)
downloadqpid-python-1f4e634e6b86a4aff2b2553d5b44b1a1d5855779.tar.gz
Merged revisions 501413-503717 via svnmerge from
https://svn.apache.org/repos/asf/incubator/qpid/trunk ........ r501448 | kpvdr | 2007-01-30 16:27:47 +0000 (Tue, 30 Jan 2007) | 1 line Fixed codegen bug in which fields added by second XML file duplicate ordinal values. ........ r501455 | rgreig | 2007-01-30 16:40:20 +0000 (Tue, 30 Jan 2007) | 1 line (Submitted by Rupert Smith) Ping tests refactored. Unused ping test classes removed. JUnit-toolkit 0.5-SNAPSHOT added to the build. ........ r501457 | rgreig | 2007-01-30 16:42:37 +0000 (Tue, 30 Jan 2007) | 1 line (Submitted by Rupert Smith) Added PingClient.java which was forgotten from last commit. ........ r501465 | rgreig | 2007-01-30 16:53:41 +0000 (Tue, 30 Jan 2007) | 1 line (Submitted by Rupert Smith) Updated the README.txt to give a fuller explanation for the creation of the temporary local maven repository. ........ r501472 | kpvdr | 2007-01-30 16:59:38 +0000 (Tue, 30 Jan 2007) | 1 line Small codegen code tidy-up ........ r501804 | rgreig | 2007-01-31 11:29:33 +0000 (Wed, 31 Jan 2007) | 3 lines (Patch submitted by Rupert Smith) Added a ping latency test. Uploaded new junit-toolkit snapshot for self timed tests. ........ r501914 | ritchiem | 2007-01-31 17:25:42 +0000 (Wed, 31 Jan 2007) | 3 lines QPID-334 WeakReferenceMessageHandle uses a singleton so when body is purged by gc it cannot be reset Changed to use an Arraylist of size 1 as per JIRA entry. ........ r501917 | ritchiem | 2007-01-31 17:31:04 +0000 (Wed, 31 Jan 2007) | 6 lines QPID-333 Message Properties on non Qpid Messages are not preserved Updated MessageConverter to have a constructor that takes a Message type. Updated MessageConverterTest to use the new NonQpidMessage to test it out. JMSHeaderAdapter.java - whitespace changes and comment noting that null return is required. ........ r501920 | ritchiem | 2007-01-31 17:43:45 +0000 (Wed, 31 Jan 2007) | 1 line Unused so removing ........ r501945 | vinoski | 2007-01-31 19:00:26 +0000 (Wed, 31 Jan 2007) | 1 line patch from Jonathan Anstey for QPID-332 ........ r502172 | ritchiem | 2007-02-01 09:37:39 +0000 (Thu, 01 Feb 2007) | 3 lines QPID-333 Committed test class rename to stop it being picked up by Surefire AMQTopic.java - whitespace ........ r502178 | bhupendrab | 2007-02-01 10:01:32 +0000 (Thu, 01 Feb 2007) | 1 line virtual host string corrected ........ r502179 | rgreig | 2007-02-01 10:13:21 +0000 (Thu, 01 Feb 2007) | 1 line (Submitted by Rupert Smith) Added comments as a reminder of improvements to be made to the tests. ........ r502180 | bhupendrab | 2007-02-01 10:13:55 +0000 (Thu, 01 Feb 2007) | 2 lines QPID-331 and setting operation parameters to default values after executing the operation once. ........ r502182 | rgreig | 2007-02-01 10:18:36 +0000 (Thu, 01 Feb 2007) | 1 line (Submitted by Rupert Smith) Added comments as a reminder of improvements to be made to the tests. ........ r502248 | ritchiem | 2007-02-01 15:47:17 +0000 (Thu, 01 Feb 2007) | 7 lines QPID-339 Java client hangs when starting up (intermittently) Patched the problem where the dispatcher would hang. The previous logic was flawed. Patch worked on by Robert Godfrey and Martin Ritchie. Added test to ensure that the connection is not automatically started. ........ r502249 | ritchiem | 2007-02-01 15:50:52 +0000 (Thu, 01 Feb 2007) | 3 lines QPID-330 Clients occasionally fail to notice connect The AMQConnection.java constructor now deals with the full connection process. The failover thread should not be started. This allows the connection method to be simplified and not Thread.sleep waiting for the connection. ........ r502253 | ritchiem | 2007-02-01 16:01:14 +0000 (Thu, 01 Feb 2007) | 11 lines QPID-339 Java client hangs when starting up (intermittently) Patched the problem where the dispatcher would hang. The previous logic was flawed. Patch worked on by Robert Godfrey and Martin Ritchie. Added test to ensure that the connection is not automatically started. (Only added the test last time by mistake. This is the actual fix) With a test for the DispatcherTest ........ r502261 | ritchiem | 2007-02-01 16:25:57 +0000 (Thu, 01 Feb 2007) | 2 lines QPID-339 DispatcherTest.java was broker now it actually tests correctly. Added test to Check changing message listeners ........ r502268 | ritchiem | 2007-02-01 16:32:56 +0000 (Thu, 01 Feb 2007) | 1 line Increased logging on a failure to attain state ........ r502269 | bhupendrab | 2007-02-01 16:34:21 +0000 (Thu, 01 Feb 2007) | 1 line some part commented, so that it lets users copy paste the host details on the new connection window ........ r502271 | ritchiem | 2007-02-01 16:36:54 +0000 (Thu, 01 Feb 2007) | 3 lines QPID-341 When using Queues and Topics defined via JNDI settings are not preserved. Removed extraction of destination/queue name and used BindingURL directly to create Destination. ........ r502273 | ritchiem | 2007-02-01 16:38:45 +0000 (Thu, 01 Feb 2007) | 2 lines Added more intelij files to the ignore list ........ r502576 | ritchiem | 2007-02-02 11:13:13 +0000 (Fri, 02 Feb 2007) | 4 lines QPID-343 Performance test suite doesn't output missing message count on failure. Updated PingAsyncTestPerf to output missing messsage count. Updated PingPongProducer so it doesn't use AMQShortStringx. ........ r502610 | bhupendrab | 2007-02-02 14:26:32 +0000 (Fri, 02 Feb 2007) | 2 lines QPID-84 tests for FSContextFactory deleted.fscontext.jar is not part of apache svn. ........ r502620 | rgreig | 2007-02-02 15:09:08 +0000 (Fri, 02 Feb 2007) | 3 lines (Submitted by Rupert Smith) Perftests improved with better timeout handling. Shared/unique destinations to ping now an option. TestRunner now runs all per-thread setups, synchs all threads, then runs tests, synchas all threads, then runs tear downs. ........ r502627 | rgreig | 2007-02-02 15:31:30 +0000 (Fri, 02 Feb 2007) | 2 lines (Submitted by Rupert Smith) Fixed problem with losing message results. Was not passing in self generated message correlation id in the async test, to match up replies with. ........ r502655 | rgreig | 2007-02-02 16:59:14 +0000 (Fri, 02 Feb 2007) | 1 line (Submitted by Rupert Smith) Options moved to top of contructor. Were at bottom and not being used! ........ r503593 | ritchiem | 2007-02-05 08:58:30 +0000 (Mon, 05 Feb 2007) | 1 line Fixed bug in stop(). If a connection is opened not start()ed then closed a NullPointerException will be thrown as the Dispatcher has not been created. ........ r503604 | rgreig | 2007-02-05 09:40:04 +0000 (Mon, 05 Feb 2007) | 1 line QPID-326 : Patch supplied by Rob Godfrey - add oldest message on queue notification, and log notifications in log file ........ r503609 | ritchiem | 2007-02-05 09:49:59 +0000 (Mon, 05 Feb 2007) | 1 line Update to performance testing to allow the use of shared destinations. This allows topics to have multiple consumers and the total message counts updated correctly. ........ r503637 | rgreig | 2007-02-05 11:17:08 +0000 (Mon, 05 Feb 2007) | 2 lines (Submitted by Rupert Smith) Junit-toolkit has now fully migrated onto sourceforge. Snapshot repository location updated. ........ r503646 | rgreig | 2007-02-05 11:28:57 +0000 (Mon, 05 Feb 2007) | 2 lines (Submitted by Rupert Smith) This local repository is no longer needed. JUnit-Toolkit snapshot repository is now hosted on sourceforge: http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/. A release is also in progress to the central maven repository. ........ r503706 | bhupendrab | 2007-02-05 14:45:18 +0000 (Mon, 05 Feb 2007) | 2 lines QPID-213 Also the parameter selection of boolean type is made as check-boxes instead of a drop-down. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/perftesting_persistent@504056 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
-rw-r--r--qpid/java/broker/etc/virtualhosts.xml79
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java203
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java76
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java44
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java9
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java135
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java (renamed from qpid/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java)65
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java60
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java49
-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/AMQSession.java163
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java10
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java14
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java22
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java13
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java1
-rw-r--r--qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java6
-rw-r--r--qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Bind.java250
-rw-r--r--qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/JNDIReferenceableTest.java102
-rw-r--r--qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Lookup.java167
-rw-r--r--qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Unbind.java173
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java258
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java271
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java (renamed from qpid/java/client/src/test/java/org/apache/qpid/client/message/TestNonQpidTextMessage.java)4
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java165
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java4
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java92
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java410
-rw-r--r--qpid/java/distribution/src/main/assembly/src.xml21
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java15
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java34
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java27
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java4
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java36
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java21
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java61
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java11
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java144
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java35
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java148
-rwxr-xr-xqpid/java/perftests/bin/run_many.sh30
-rwxr-xr-xqpid/java/perftests/bin/serviceProvidingClient.sh33
-rwxr-xr-xqpid/java/perftests/bin/serviceRequestReply-MultipleClients.sh53
-rwxr-xr-xqpid/java/perftests/bin/serviceRequestReply-QuickTest.sh43
-rwxr-xr-xqpid/java/perftests/bin/serviceRequestingClient-createLogFile.sh38
-rwxr-xr-xqpid/java/perftests/bin/serviceRequestingClient.sh34
-rwxr-xr-xqpid/java/perftests/bin/setupclasspath.sh12
-rwxr-xr-xqpid/java/perftests/bin/testPingClient.sh33
-rwxr-xr-xqpid/java/perftests/bin/testPingProducer.sh33
-rwxr-xr-xqpid/java/perftests/bin/testPingPublisher.sh33
-rwxr-xr-xqpid/java/perftests/bin/testPingSubscriber.sh33
-rwxr-xr-xqpid/java/perftests/bin/topic-QuickTest.sh55
-rwxr-xr-xqpid/java/perftests/bin/topicListener.sh26
-rwxr-xr-xqpid/java/perftests/bin/topicPublisher.sh23
-rw-r--r--qpid/java/perftests/pom.xml262
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java204
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java524
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java108
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java192
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java223
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java249
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java197
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java134
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java67
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java206
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java1297
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java235
-rw-r--r--qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java428
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java559
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingLatencyTestPerf.java317
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingTestPerf.java344
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/ping/ThrottleTestPerf.java63
-rw-r--r--qpid/java/perftests/src/test/java/org/apache/qpid/requestreply/PingPongTestPerf.java303
-rw-r--r--qpid/java/pom.xml9
83 files changed, 4360 insertions, 5500 deletions
diff --git a/qpid/java/broker/etc/virtualhosts.xml b/qpid/java/broker/etc/virtualhosts.xml
index 50cddb5661..2a573535de 100644
--- a/qpid/java/broker/etc/virtualhosts.xml
+++ b/qpid/java/broker/etc/virtualhosts.xml
@@ -21,18 +21,79 @@
-->
<virtualhosts>
<virtualhost>
- <path>localhost</path>
- <bind>direct://amq.direct//queue</bind>
- <bind>direct://amq.direct//ping</bind>
+ <name>localhost</name>
+
+ <localhost>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>5000</maximumMessageCount>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </ping>
+ </queue>
+ </localhost>
</virtualhost>
<virtualhost>
- <path>development</path>
- <bind>direct://amq.direct//queue</bind>
- <bind>direct://amq.direct//ping</bind>
+ <name>development</name>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>5000</maximumMessageCount>
+ <development>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </ping>
+ </queue>
+ </development>
</virtualhost>
<virtualhost>
- <path>test</path>
- <bind>direct://amq.direct//queue</bind>
- <bind>direct://amq.direct//ping</bind>
+ <name>test</name>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>5000</maximumMessageCount>
+ <test>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
+ </ping>
+ </queue>
+ </test>
</virtualhost>
</virtualhosts>
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index 204b5674ce..0b8aac67b6 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
@@ -153,7 +153,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
try
{
- queue = new AMQQueue(new AMQShortString(queueName), durable, new AMQShortString(owner), autoDelete, getVirtualHost());
+ AMQShortString ownerShortString = null;
+ if (owner != null)
+ {
+ ownerShortString = new AMQShortString(owner);
+ }
+ queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, autoDelete, getVirtualHost());
if (queue.isDurable() && !queue.isAutoDelete())
{
_messageStore.createQueue(queue);
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 361a21b284..c191bef447 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
@@ -34,9 +34,13 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.log4j.Logger;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.CompositeConfiguration;
import java.util.Collection;
+import java.util.List;
+import java.util.Collections;
public class VirtualHostConfiguration
{
@@ -44,11 +48,7 @@ public class VirtualHostConfiguration
XMLConfiguration _config;
- private static final String XML_VIRTUALHOST = "virtualhost";
- private static final String XML_PATH = "path";
- private static final String XML_BIND = "bind";
- private static final String XML_VIRTUALHOST_PATH = "virtualhost.path";
- private static final String XML_VIRTUALHOST_BIND = "virtualhost.bind";
+ private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost.";
public VirtualHostConfiguration(String configFile) throws ConfigurationException
@@ -57,137 +57,66 @@ public class VirtualHostConfiguration
_config = new XMLConfiguration(configFile);
- if (_config.getProperty(XML_VIRTUALHOST_PATH) == null)
- {
- throw new ConfigurationException(
- "Virtualhost Configuration document does not contain a valid virtualhost.");
- }
}
- public void performBindings() throws AMQException, ConfigurationException, URLSyntaxException
- {
- Object prop = _config.getProperty(XML_VIRTUALHOST_PATH);
-
- if (prop instanceof Collection)
- {
- _logger.debug("Number of VirtualHosts: " + ((Collection) prop).size());
- int virtualhosts = ((Collection) prop).size();
- for (int vhost = 0; vhost < virtualhosts; vhost++)
- {
- loadVirtualHost(vhost);
- }
- }
- else
- {
- loadVirtualHost(-1);
- }
- }
- private void loadVirtualHost(int index) throws AMQException, ConfigurationException, URLSyntaxException
+ private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException
{
- String path = XML_VIRTUALHOST;
-
- if (index != -1)
- {
- path = path + "(" + index + ")";
- }
-
- Object prop = _config.getProperty(path + "." + XML_PATH);
-
- if (prop == null)
- {
- prop = _config.getProperty(path + "." + XML_BIND);
- String error = "Virtual Host not defined for binding";
-
- if (prop != null)
- {
- if (prop instanceof Collection)
- {
- error += "s";
- }
+ _logger.debug("Loding configuration for virtaulhost: "+virtualHostName);
- error += ": " + prop;
- }
- throw new ConfigurationException(error);
- }
+ VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName);
- _logger.info("VirtualHost:'" + prop + "'");
- String virtualHost = prop.toString();
- prop = _config.getProperty(path + "." + XML_BIND);
- if (prop instanceof Collection)
- {
- int bindings = ((Collection) prop).size();
- _logger.debug("Number of Bindings: " + bindings);
- for (int dest = 0; dest < bindings; dest++)
- {
- loadBinding(virtualHost, path, dest);
- }
- }
- else
- {
- loadBinding(virtualHost,path, -1);
- }
- }
- private void loadBinding(String virtualHost, String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException
- {
- String path = rootpath + "." + XML_BIND;
- if (index != -1)
+ if(virtualHost == null)
{
- path = path + "(" + index + ")";
+ throw new ConfigurationException("Unknown virtual host: " + virtualHostName);
}
- String bindingString = _config.getString(path);
-
- AMQBindingURL binding = new AMQBindingURL(bindingString);
+ List queueNames = configuration.getList("queue.name");
- _logger.debug("Loaded Binding:" + binding);
-
- try
- {
- bind(virtualHost, binding);
- }
- catch (AMQException amqe)
+ for(Object queueNameObj : queueNames)
{
- _logger.info("Unable to bind url: " + binding);
- throw amqe;
+ String queueName = String.valueOf(queueNameObj);
+ configureQueue(virtualHost, queueName, configuration);
}
+
}
- private void bind(String virtualHostName, AMQBindingURL binding) throws AMQException, ConfigurationException
+ private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException
{
+ CompositeConfiguration queueConfiguration = new CompositeConfiguration();
- AMQShortString queueName = binding.getQueueName();
+ queueConfiguration.addConfiguration(configuration.subset("queue."+ queueNameString));
+ queueConfiguration.addConfiguration(configuration);
- // This will occur if the URL is a Topic
- if (queueName == null)
- {
- //todo register valid topic
- ///queueName = binding.getDestinationName();
- throw new AMQException("Topics cannot be bound. TODO Register valid topic");
- }
-
- //Get references to Broker Registries
- VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName);
QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
MessageStore messageStore = virtualHost.getMessageStore();
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+
+ AMQShortString queueName = new AMQShortString(queueNameString);
+
+ AMQQueue queue;
+
synchronized (queueRegistry)
{
- AMQQueue queue = queueRegistry.getQueue(queueName);
+ queue = queueRegistry.getQueue(queueName);
if (queue == null)
{
- _logger.info("Queue '" + binding.getQueueName() + "' does not exists. Creating.");
+ _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName());
+
+ boolean durable = queueConfiguration.getBoolean("durable" ,false);
+ boolean autodelete = queueConfiguration.getBoolean("autodelete", false);
+ String owner = queueConfiguration.getString("owner", null);
queue = new AMQQueue(queueName,
- Boolean.parseBoolean(binding.getOption(AMQBindingURL.OPTION_DURABLE)),
- null /* These queues will have no owner */,
- false /* Therefore autodelete makes no sence */, virtualHost);
+ durable,
+ owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */,
+ autodelete /* Therefore autodelete makes no sence */, virtualHost);
if (queue.isDurable())
{
@@ -198,27 +127,69 @@ public class VirtualHostConfiguration
}
else
{
- _logger.info("Queue '" + binding.getQueueName() + "' already exists not creating.");
+ _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating.");
}
- Exchange defaultExchange = exchangeRegistry.getExchange(binding.getExchangeName());
- synchronized (defaultExchange)
+ String exchangeName = queueConfiguration.getString("exchange", null);
+
+ Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName));
+
+ if(exchange == null)
{
- if (defaultExchange == null)
- {
- throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + binding);
- }
+ exchange = virtualHost.getExchangeRegistry().getDefaultExchange();
+ }
- defaultExchange.registerQueue(queue.getName(), queue, null);
+ if (exchange == null)
+ {
+ throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName);
+ }
- if (binding.getRoutingKey() == null || binding.getRoutingKey().equals(""))
+ synchronized (exchange)
+ {
+ List routingKeys = queueConfiguration.getList("routingKey");
+ if(routingKeys == null || routingKeys.isEmpty())
{
- throw new ConfigurationException("Unknown binding not specified on url:" + binding);
+ routingKeys = Collections.singletonList(queue.getName());
}
- queue.bind(binding.getRoutingKey(), defaultExchange);
+ for(Object routingKeyNameObj : routingKeys)
+ {
+ AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj));
+ exchange.registerQueue(routingKey, queue, null);
+
+ queue.bind(routingKey, exchange);
+
+ _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'");
+ }
}
- _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + binding.getExchangeName() + " RK:'" + binding.getRoutingKey() + "'");
+
}
+
+
+
+ Configurator.configure(queue, queueConfiguration);
}
+
+
+ public void performBindings() throws AMQException, ConfigurationException
+ {
+ List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name");
+
+ _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames);
+
+ for(Object nameObject : virtualHostNames)
+ {
+ String name = String.valueOf(nameObject);
+ configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name));
+ }
+
+ if (virtualHostNames == null || virtualHostNames.isEmpty())
+ {
+ throw new ConfigurationException(
+ "Virtualhost Configuration document does not contain a valid virtualhost.");
+ }
+ }
+
+
+
}
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 374772bc4a..cb3b1eafa6 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
@@ -67,6 +67,11 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
_defaultExchange = exchange;
}
+ public Exchange getDefaultExchange()
+ {
+ return _defaultExchange;
+ }
+
public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException
{
// TODO: check inUse argument
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
index 24884d20d7..a022b86299 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
@@ -40,4 +40,6 @@ public interface ExchangeRegistry extends MessageRouter
Exchange getExchange(AMQShortString name);
void setDefaultExchange(Exchange exchange);
+
+ Exchange getDefaultExchange();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
index 7a16901796..71fecc45fa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
@@ -509,6 +509,12 @@ public class AMQMessage
_messageHandle.setRedelivered(redelivered);
}
+ public long getArrivalTime()
+ {
+ return _messageHandle.getArrivalTime();
+ }
+
+
/**
* Called when this message is delivered to a consumer. (used to
* implement the 'immediate' flag functionality).
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
index d788d1b9e2..f07706c2e6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
@@ -74,4 +74,6 @@ public interface AMQMessageHandle
void enqueue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException;
void dequeue(StoreContext storeContext, Long messageId, AMQQueue queue) throws AMQException;
+
+ long getArrivalTime();
} \ No newline at end of file
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 ab7bbefe92..aa372a3b99 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
@@ -22,6 +22,7 @@ package org.apache.qpid.server.queue;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.configuration.Configured;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.exchange.Exchange;
@@ -35,7 +36,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
import javax.management.JMException;
import java.text.MessageFormat;
import java.util.List;
-import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -130,22 +130,36 @@ public class AMQQueue implements Managable, Comparable
/**
* max allowed size(KB) of a single message
*/
- private long _maxMessageSize = 10000;
+ private long _maximumMessageSize = 10000;
/**
* max allowed number of messages on a queue.
*/
- private Integer _maxMessageCount = 10000;
+ @Configured(path = "maximumMessageCount", defaultValue = "0")
+ public int _maximumMessageCount;
/**
- * max queue depth(KB) for the queue
+ * max queue depth for the queue
*/
- private long _maxQueueDepth = 10000000;
+ @Configured(path = "maximumQueueDepth", defaultValue = "0")
+ public long _maximumQueueDepth = 10000000;
+
+/*
+ * maximum message age before alerts occur
+ */
+ @Configured(path = "maximumMessageAge", defaultValue = "0")
+ public long _maximumMessageAge = 30000; //0
+
+ /*
+ * the minimum interval between sending out consequetive alerts of the same type
+ */
+ @Configured(path = "minimumAlertRepeatGap", defaultValue = "0")
+ public long _minimumAlertRepeatGap = 30000;
/**
* total messages received by the queue since startup.
*/
- private long _totalMessagesReceived = 0;
+ public long _totalMessagesReceived = 0;
public int compareTo(Object o)
{
@@ -286,50 +300,56 @@ public class AMQQueue implements Managable, Comparable
return _managedObject;
}
- public Long getMaximumMessageSize()
+ public long getMaximumMessageSize()
{
- return _maxMessageSize;
+ return _maximumMessageSize;
}
- public void setMaximumMessageSize(Long value)
+ public void setMaximumMessageSize(long value)
{
- _maxMessageSize = value;
+ _maximumMessageSize = value;
}
- public Integer getConsumerCount()
+ public int getConsumerCount()
{
return _subscribers.size();
}
- public Integer getActiveConsumerCount()
+ public int getActiveConsumerCount()
{
return _subscribers.getWeight();
}
- public Long getReceivedMessageCount()
+ public long getReceivedMessageCount()
{
return _totalMessagesReceived;
}
- public Integer getMaximumMessageCount()
+ public int getMaximumMessageCount()
{
- return _maxMessageCount;
+ return _maximumMessageCount;
}
- public void setMaximumMessageCount(Integer value)
+ public void setMaximumMessageCount(int value)
{
- _maxMessageCount = value;
+ _maximumMessageCount = value;
}
public long getMaximumQueueDepth()
{
- return _maxQueueDepth;
+ return _maximumQueueDepth;
}
// Sets the queue depth, the max queue size
public void setMaximumQueueDepth(long value)
{
- _maxQueueDepth = value;
+ _maximumQueueDepth = value;
+ }
+
+ public long getOldestMessageArrivalTime()
+ {
+ return _deliveryMgr.getOldestMessageArrival();
+
}
/**
@@ -631,6 +651,24 @@ public class AMQQueue implements Managable, Comparable
_deleteTaskList.add(task);
}
+ public long getMinimumAlertRepeatGap()
+ {
+ return _minimumAlertRepeatGap;
+ }
+
+ public void setMinimumAlertRepeatGap(long minimumAlertRepeatGap)
+ {
+ _minimumAlertRepeatGap = minimumAlertRepeatGap;
+ }
+ public long getMaximumMessageAge()
+ {
+ return _maximumMessageAge;
+ }
+
+ public void setMaximumMessageAge(long maximumMessageAge)
+ {
+ _maximumMessageAge = maximumMessageAge;
+ }
}
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 e15dc648f7..bee2e3950c 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
@@ -22,12 +22,12 @@ import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.MBeanConstructor;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.Main;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.mina.common.ByteBuffer;
+import org.apache.log4j.Logger;
import javax.management.openmbean.*;
import javax.management.*;
@@ -41,8 +41,11 @@ import java.util.Iterator;
* for an AMQQueue.
*/
@MBeanDescription("Management Interface for AMQQueue")
-public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue
+public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener
{
+
+ private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class);
+
/**
* Since the MBean is not associated with a real channel we can safely create our own store context
* for use in the few methods that require one.
@@ -63,6 +66,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue
private final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"};
private static OpenType[] _msgContentAttributeTypes = new OpenType[4];
+
+ private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length];
+
@MBeanConstructor("Creates an MBean exposing an AMQQueue")
public AMQQueueMBean(AMQQueue queue) throws JMException
{
@@ -213,38 +219,38 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue
return msg.getContentHeaderBody().bodySize;
}
+
+
/**
* Checks if there is any notification to be send to the listeners
*/
public void checkForNotification(AMQMessage msg) throws AMQException, JMException
{
- // Check for threshold message count
- Integer msgCount = getMessageCount();
- if (msgCount >= getMaximumMessageCount())
- {
- notifyClients("Message count(" + msgCount + ") has reached or exceeded the threshold high value");
- }
- // Check for threshold message size
- long messageSize = getMessageSize(msg);
- if (messageSize >= _queue.getMaximumMessageSize())
- {
- notifyClients("Message size(ID=" + msg.getMessageId() + ", size=" + messageSize + " bytes) is higher than the threshold value");
- }
+ final long currentTime = System.currentTimeMillis();
+ final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap();
- // Check for threshold queue depth in bytes
- long queueDepth = getQueueDepthKb();
- if (queueDepth >= _queue.getMaximumQueueDepth())
+ for(NotificationCheck check : NotificationCheck.values())
{
- notifyClients("Queue depth(" + queueDepth + "), Queue size has reached the threshold high value");
+ if(check.isMessageSpecific() || _lastNotificationTimes[check.ordinal()]<thresholdTime)
+ {
+ if(check.notifyIfNecessary(msg, _queue, this))
+ {
+ _lastNotificationTimes[check.ordinal()] = currentTime;
+ }
+ }
}
+
}
/**
* Sends the notification to the listeners
*/
- private void notifyClients(String notificationMsg)
+ public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg)
{
+ // important : add log to the log file - monitoring tools may be looking for this
+ _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg);
+
Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this,
++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java
index 2103d79310..3a9ce64c57 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java
@@ -160,6 +160,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager
return _totalMessageSize.get();
}
+ public long getOldestMessageArrival()
+ {
+ AMQMessage msg = _messages.peek();
+ return msg == null ? Long.MAX_VALUE : msg.getArrivalTime();
+ }
+
public synchronized List<AMQMessage> getMessages()
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java
index 7d7ede0732..f7820e1465 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java
@@ -83,4 +83,6 @@ interface DeliveryManager
boolean performGet(AMQProtocolSession session, AMQChannel channel, boolean acks) throws AMQException;
long getTotalMessageSize();
+
+ long getOldestMessageArrival();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
index 186a5c8753..4f7dc21598 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
@@ -43,6 +43,8 @@ public class InMemoryMessageHandle implements AMQMessageHandle
private boolean _redelivered;
+ private long _arrivalTime;
+
public InMemoryMessageHandle()
{
}
@@ -114,6 +116,7 @@ public class InMemoryMessageHandle implements AMQMessageHandle
{
_publishBody = publishBody;
_contentHeaderBody = contentHeaderBody;
+ _arrivalTime = System.currentTimeMillis();
}
public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
@@ -130,4 +133,10 @@ public class InMemoryMessageHandle implements AMQMessageHandle
{
// NO OP
}
+
+ public long getArrivalTime()
+ {
+ return _arrivalTime;
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java
index deed18c188..a66a85e54d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java
@@ -31,11 +31,19 @@ public class MessageMetaData
private int _contentChunkCount;
+ private long _arrivalTime;
+
public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount)
{
+ this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis());
+ }
+
+ public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime)
+ {
_contentHeaderBody = contentHeaderBody;
_publishBody = publishBody;
_contentChunkCount = contentChunkCount;
+ _arrivalTime = arrivalTime;
}
public int getContentChunkCount()
@@ -67,4 +75,14 @@ public class MessageMetaData
{
_publishBody = publishBody;
}
+
+ public long getArrivalTime()
+ {
+ return _arrivalTime;
+ }
+
+ public void setArrivalTime(long arrivalTime)
+ {
+ _arrivalTime = arrivalTime;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
new file mode 100644
index 0000000000..bc8e1232a7
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
@@ -0,0 +1,135 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+
+public enum NotificationCheck
+{
+
+ MESSAGE_COUNT_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ int msgCount = queue.getMessageCount();
+ final int maximumMessageCount = queue.getMaximumMessageCount();
+ if (maximumMessageCount!= 0 && msgCount >= maximumMessageCount)
+ {
+ listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached.");
+ return true;
+ }
+ return false;
+ }
+ },
+ MESSAGE_SIZE_ALERT(true)
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ final long maximumMessageSize = queue.getMaximumMessageSize();
+ if(maximumMessageSize != 0)
+ {
+ // Check for threshold message size
+ long messageSize;
+ try
+ {
+ messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize;
+ }
+ catch (AMQException e)
+ {
+ messageSize = 0;
+ }
+
+
+ if (messageSize >= maximumMessageSize)
+ {
+ listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ },
+ QUEUE_DEPTH_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+ // Check for threshold queue depth in bytes
+ final long maximumQueueDepth = queue.getMaximumQueueDepth();
+
+ if(maximumQueueDepth != 0)
+ {
+ final long queueDepth = queue.getQueueDepth();
+
+ if (queueDepth >= maximumQueueDepth)
+ {
+ listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached.");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ },
+ MESSAGE_AGE_ALERT
+ {
+ boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ {
+
+ final long maxMessageAge = queue.getMaximumMessageAge();
+ if(maxMessageAge != 0)
+ {
+ final long currentTime = System.currentTimeMillis();
+ final long thresholdTime = currentTime - maxMessageAge;
+ final long firstArrivalTime = queue.getOldestMessageArrivalTime();
+
+ if(firstArrivalTime < thresholdTime)
+ {
+ long oldestAge = currentTime - firstArrivalTime;
+ listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached.");
+
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ }
+ ;
+
+ private final boolean _messageSpecific;
+
+ NotificationCheck()
+ {
+ this(false);
+ }
+
+ NotificationCheck(boolean messageSpecific)
+ {
+ _messageSpecific = messageSpecific;
+ }
+
+ public boolean isMessageSpecific()
+ {
+ return _messageSpecific;
+ }
+
+ abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener);
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java
index 70a5f2dc5e..9554d34f00 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java
@@ -1,42 +1,23 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.util.concurrent;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Apache Software Foundation
- */
-public class BooleanLatch extends CountDownLatch
-{
- public BooleanLatch()
- {
- super(1);
- }
-
- public void signal()
- {
- countDown();
- }
-
- public void await(long nanos) throws InterruptedException
- {
- await(nanos, TimeUnit.NANOSECONDS);
- }
-}
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+public interface QueueNotificationListener
+{
+ void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg);
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
index 50051fdc34..8675a7249a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
@@ -49,6 +49,8 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
private final MessageStore _messageStore;
+ private long _arrivalTime;
+
public WeakReferenceMessageHandle(MessageStore messageStore)
{
@@ -57,17 +59,30 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
public ContentHeaderBody getContentHeaderBody(Long messageId) throws AMQException
{
- ContentHeaderBody chb = (_contentHeaderBody != null?_contentHeaderBody.get():null);
+ ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null);
if (chb == null)
{
- MessageMetaData mmd = _messageStore.getMessageMetaData(messageId);
+ MessageMetaData mmd = loadMessageMetaData(messageId);
chb = mmd.getContentHeaderBody();
- _contentHeaderBody = new WeakReference<ContentHeaderBody>(chb);
- _publishBody = new WeakReference<BasicPublishBody>(mmd.getPublishBody());
}
return chb;
}
+ private MessageMetaData loadMessageMetaData(Long messageId)
+ throws AMQException
+ {
+ MessageMetaData mmd = _messageStore.getMessageMetaData(messageId);
+ populateFromMessageMetaData(mmd);
+ return mmd;
+ }
+
+ private void populateFromMessageMetaData(MessageMetaData mmd)
+ {
+ _arrivalTime = mmd.getArrivalTime();
+ _contentHeaderBody = new WeakReference<ContentHeaderBody>(mmd.getContentHeaderBody());
+ _publishBody = new WeakReference<BasicPublishBody>(mmd.getPublishBody());
+ }
+
public int getBodyCount(Long messageId) throws AMQException
{
if (_contentBodies == null)
@@ -107,6 +122,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
/**
* Content bodies are set <i>before</i> the publish and header frames
+ *
* @param storeContext
* @param messageId
* @param contentBody
@@ -115,10 +131,9 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
*/
public void addContentBodyFrame(StoreContext storeContext, Long messageId, ContentBody contentBody, boolean isLastContentBody) throws AMQException
{
- if(_contentBodies == null && isLastContentBody)
+ if (_contentBodies == null && isLastContentBody)
{
- _contentBodies = Collections.singletonList(new WeakReference<ContentBody>(contentBody));
-
+ _contentBodies = new ArrayList<WeakReference<ContentBody>>(1);
}
else
{
@@ -126,22 +141,19 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
{
_contentBodies = new LinkedList<WeakReference<ContentBody>>();
}
-
-
- _contentBodies.add(new WeakReference<ContentBody>(contentBody));
}
+ _contentBodies.add(new WeakReference<ContentBody>(contentBody));
_messageStore.storeContentBodyChunk(storeContext, messageId, _contentBodies.size() - 1, contentBody, isLastContentBody);
}
public BasicPublishBody getPublishBody(Long messageId) throws AMQException
{
- BasicPublishBody bpb = (_publishBody != null?_publishBody.get():null);
+ BasicPublishBody bpb = (_publishBody != null ? _publishBody.get() : null);
if (bpb == null)
{
- MessageMetaData mmd = _messageStore.getMessageMetaData(messageId);
+ MessageMetaData mmd = loadMessageMetaData(messageId);
+
bpb = mmd.getPublishBody();
- _publishBody = new WeakReference<BasicPublishBody>(bpb);
- _contentHeaderBody = new WeakReference<ContentHeaderBody>(mmd.getContentHeaderBody());
}
return bpb;
}
@@ -166,6 +178,7 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
/**
* This is called when all the content has been received.
+ *
* @param publishBody
* @param contentHeaderBody
* @throws AMQException
@@ -180,10 +193,15 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
{
_contentBodies = new LinkedList<WeakReference<ContentBody>>();
}
- _messageStore.storeMessageMetaData(storeContext, messageId, new MessageMetaData(publishBody, contentHeaderBody,
- _contentBodies.size()));
- _publishBody = new WeakReference<BasicPublishBody>(publishBody);
- _contentHeaderBody = new WeakReference<ContentHeaderBody>(contentHeaderBody);
+
+ final long arrivalTime = System.currentTimeMillis();
+
+
+ MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime);
+
+ _messageStore.storeMessageMetaData(storeContext, messageId, mmd);
+
+ populateFromMessageMetaData(mmd);
}
public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
@@ -200,4 +218,10 @@ public class WeakReferenceMessageHandle implements AMQMessageHandle
{
_messageStore.dequeueMessage(storeContext, queue.getName(), messageId);
}
+
+ public long getArrivalTime()
+ {
+ return _arrivalTime;
+ }
+
}
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 cc052f81df..50299fa9d5 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
@@ -215,12 +215,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
Exception lastException = new Exception();
lastException.initCause(new ConnectException());
- while (lastException != null && checkException(lastException) && _failoverPolicy.failoverAllowed())
+ while (!_connected && _failoverPolicy.failoverAllowed())
{
try
{
makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
lastException = null;
+ _connected = true;
}
catch (Exception e)
{
@@ -232,34 +233,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
_logger.debug("Are we connected:" + _connected);
- // Then the Failover Thread will handle conneciton
- if (_failoverPolicy.failoverAllowed())
- {
- //TODO this needs to be redone so that we are not spinning.
- // A suitable object should be set that is then waited on
- // and only notified when a connection is made or when
- // the AMQConnection gets closed.
- while (!_connected && !_closed.get())
- {
- try
- {
- _logger.debug("Sleeping.");
- Thread.sleep(100);
- }
- catch (InterruptedException ie)
- {
- _logger.debug("Woken up.");
- }
- }
- if (!_failoverPolicy.failoverAllowed() || _failoverPolicy.getCurrentBrokerDetails() == null)
- {
- if (_lastAMQException != null)
- {
- throw _lastAMQException;
- }
- }
- }
- else
+ if (!_connected)
{
String message = null;
@@ -318,7 +292,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
private void setVirtualHost(String virtualHost)
{
- if(virtualHost.startsWith("/"))
+ if (virtualHost.startsWith("/"))
{
virtualHost = virtualHost.substring(1);
}
@@ -403,7 +377,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public boolean failoverAllowed()
{
- return _failoverPolicy.failoverAllowed();
+ if (!_connected)
+ {
+ return false;
+ }
+ else
+ {
+ return _failoverPolicy.failoverAllowed();
+ }
}
public Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
@@ -815,6 +796,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
return _protocolHandler;
}
+ public boolean started()
+ {
+ return _started;
+ }
+
public void bytesSent(long writtenBytes)
{
if (_connectionListener != null)
@@ -1031,4 +1017,5 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
AMQConnectionFactory.class.getName(),
null); // factory location
}
+
}
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 b2d2d2bec3..17af3702a4 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
@@ -62,7 +62,7 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
String clientName, String virtualHost) throws URLSyntaxException
{
this(new AMQConnectionURL(ConnectionURL.AMQ_PROTOCOL + "://" +
- username + ":" + password + "@" + clientName +
+ username + ":" + password + "@" + clientName + "/" +
virtualHost + "?brokerlist='" + broker + "'"));
}
@@ -334,7 +334,7 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
if (addr != null)
{
- return new AMQQueue(new AMQBindingURL((String) addr.getContent()).getQueueName());
+ return new AMQQueue(new AMQBindingURL((String) addr.getContent()));
}
}
@@ -344,7 +344,7 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
if (addr != null)
{
- return new AMQTopic(new AMQBindingURL((String) addr.getContent()).getDestinationName());
+ return new AMQTopic(new AMQBindingURL((String) addr.getContent()));
}
}
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 b6429972df..35530b39c9 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
@@ -93,8 +93,6 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
*/
private final FlowControllingBlockingQueue _queue;
- private final java.util.Queue<MessageConsumerPair> _reprocessQueue;
-
private Dispatcher _dispatcher;
private MessageFactoryRegistry _messageFactoryRegistry;
@@ -136,20 +134,6 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
*/
private long _nextProducerId;
- /**
- * Track the 'stopped' state of the dispatcher, a session starts in the stopped state.
- */
- private volatile AtomicBoolean _stopped = new AtomicBoolean(true);
-
- /**
- * Used to signal 'pausing' the dispatcher when setting a message listener on a consumer
- */
- private final AtomicBoolean _pausingDispatcher = new AtomicBoolean(false);
-
- /**
- * Used to signal 'pausing' the dispatcher when setting a message listener on a consumer
- */
- private final AtomicBoolean _pausedDispatcher = new AtomicBoolean(false);
/**
* Set when recover is called. This is to handle the case where recover() is called by application code
@@ -157,14 +141,24 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
*/
private boolean _inRecovery;
+ private boolean _connectionStopped;
+
private boolean _hasMessageListeners;
/**
* Responsible for decoding a message fragment and passing it to the appropriate message consumer.
*/
-
+
private class Dispatcher extends Thread
{
+
+ /**
+ * Track the 'stopped' state of the dispatcher, a session starts in the stopped state.
+ */
+ private final AtomicBoolean _closed = new AtomicBoolean(false);
+
+ private final Object _lock = new Object();
+
public Dispatcher()
{
super("Dispatcher-Channel-" + _channelId);
@@ -173,12 +167,28 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
public void run()
{
UnprocessedMessage message;
- _stopped.set(false);
+
try
{
- while (!_stopped.get() && (message = (UnprocessedMessage) _queue.take()) != null)
+ while (!_closed.get() && (message = (UnprocessedMessage) _queue.take()) != null)
{
- dispatchMessage(message);
+ synchronized (_lock)
+ {
+
+ while (connectionStopped())
+ {
+ _lock.wait();
+ }
+
+ dispatchMessage(message);
+
+ while (connectionStopped())
+ {
+ _lock.wait();
+ }
+
+ }
+
}
}
catch (InterruptedException e)
@@ -189,6 +199,21 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
_logger.info("Dispatcher thread terminating for channel " + _channelId);
}
+ // only call while holding lock
+ final boolean connectionStopped()
+ {
+ return _connectionStopped;
+ }
+
+ void setConnectionStopped(boolean connectionStopped)
+ {
+ synchronized (_lock)
+ {
+ _connectionStopped = connectionStopped;
+ _lock.notify();
+ }
+ }
+
private void dispatchMessage(UnprocessedMessage message)
{
if (message.getDeliverBody() != null)
@@ -246,15 +271,17 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
}
}
- public void stopDispatcher()
+ public void close()
{
- _stopped.set(true);
+ _closed.set(true);
interrupt();
+
+ //fixme awaitTermination
+
}
}
-
AMQSession(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode,
MessageFactoryRegistry messageFactoryRegistry)
{
@@ -285,8 +312,6 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
_defaultPrefetchHighMark = defaultPrefetchHighMark;
_defaultPrefetchLowMark = defaultPrefetchLowMark;
- _reprocessQueue = new ConcurrentLinkedQueue<MessageConsumerPair>();
-
if (_acknowledgeMode == NO_ACKNOWLEDGE)
{
_queue = new FlowControllingBlockingQueue(_defaultPrefetchHighMark, _defaultPrefetchLowMark,
@@ -446,7 +471,7 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
}
}
-
+
public void rollback() throws JMSException
{
checkTransacted();
@@ -654,7 +679,8 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
{
if (_dispatcher != null)
{
- _dispatcher.stopDispatcher();
+ _dispatcher.close();
+ _dispatcher = null;
}
// we need to clone the list of consumers since the close() method updates the _consumers collection
// which would result in a concurrent modification exception
@@ -680,7 +706,8 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
{
if (_dispatcher != null)
{
- _dispatcher.stopDispatcher();
+ _dispatcher.close();
+ _dispatcher = null;
}
// we need to clone the list of consumers since the close() method updates the _consumers collection
// which would result in a concurrent modification exception
@@ -712,8 +739,8 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
}
// TODO: Be aware of possible changes to parameter order as versions change.
getProtocolHandler().writeFrame(BasicRecoverBody.createAMQFrame(_channelId,
- getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor)
- false)); // requeue
+ getProtocolMajorVersion(), getProtocolMinorVersion(), // AMQP version (major, minor)
+ false)); // requeue
}
boolean isInRecovery()
@@ -743,37 +770,36 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
public MessageListener getMessageListener() throws JMSException
{
- checkNotClosed();
+// checkNotClosed();
return _messageListener;
}
public void setMessageListener(MessageListener listener) throws JMSException
{
- checkNotClosed();
-
- if (!isStopped())
- {
- throw new javax.jms.IllegalStateException("Attempt to set listener while session is started.");
- }
-
- // We are stopped
- for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
- {
- BasicMessageConsumer consumer = i.next();
-
- if (consumer.isReceiving())
- {
- throw new javax.jms.IllegalStateException("Another thread is already receiving synchronously.");
- }
- }
-
- _messageListener = listener;
-
- for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
- {
- i.next().setMessageListener(_messageListener);
- }
-
+// checkNotClosed();
+//
+// if (_dispatcher != null && !_dispatcher.connectionStopped())
+// {
+// throw new javax.jms.IllegalStateException("Attempt to set listener while session is started.");
+// }
+//
+// // We are stopped
+// for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
+// {
+// BasicMessageConsumer consumer = i.next();
+//
+// if (consumer.isReceiving())
+// {
+// throw new javax.jms.IllegalStateException("Another thread is already receiving synchronously.");
+// }
+// }
+//
+// _messageListener = listener;
+//
+// for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
+// {
+// i.next().setMessageListener(_messageListener);
+// }
}
@@ -1582,13 +1608,17 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
void start()
{
+ //fixme This should be controlled by _stopped as it pairs with the stop method
+ //fixme or check the FlowControlledBlockingQueue _queue to see if we have flow controlled.
+ //will result in sending Flow messages for each subsequent call to flow.. only need to do this
+ // if we have called stop.
if (_startedAtLeastOnce.getAndSet(true))
{
//then we stopped this and are restarting, so signal server to resume delivery
unsuspendChannel();
}
- if(hasMessageListeners() && _dispatcher == null)
+ if (hasMessageListeners())
{
startDistpatcherIfNecessary();
}
@@ -1606,26 +1636,27 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi
synchronized void startDistpatcherIfNecessary()
{
- if(_dispatcher == null)
+ if (_dispatcher == null)
{
_dispatcher = new Dispatcher();
_dispatcher.setDaemon(true);
_dispatcher.start();
}
+ else
+ {
+ _dispatcher.setConnectionStopped(false);
+ }
}
void stop()
{
//stop the server delivering messages to this session
suspendChannel();
-
- //stop the dispatcher thread
- _stopped.set(true);
- }
-
- boolean isStopped()
- {
- return _stopped.get();
+
+ if (_dispatcher != null)
+ {
+ _dispatcher.setConnectionStopped(true);
+ }
}
/**
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
index f50b0390c5..c82187b2e7 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
@@ -28,12 +28,12 @@ import javax.jms.JMSException;
import javax.jms.Topic;
public class AMQTopic extends AMQDestination implements Topic
- {
+{
/**
- * Constructor for use in creating a topic using a BindingURL.
+ * Constructor for use in creating a topic using a BindingURL.
*
* @param binding The binding url object.
- */
+ */
public AMQTopic(BindingURL binding)
{
super(binding);
@@ -78,7 +78,7 @@ public class AMQTopic extends AMQDestination implements Topic
return super.getDestinationName().toString();
}
- public AMQShortString getRoutingKey()
+ public AMQShortString getRoutingKey()
{
return getDestinationName();
}
@@ -93,7 +93,7 @@ public class AMQTopic extends AMQDestination implements Topic
* Override since the queue is always private and we must ensure it remains null. If not,
* reuse of the topic when registering consumers will make all consumers listen on the same (private) queue rather
* than getting their own (private) queue.
- *
+ * <p/>
* This is relatively nasty but it is difficult to come up with a more elegant solution, given
* the requirement in the case on AMQQueue and possibly other AMQDestination subclasses to
* use the underlying queue name even where it is server generated.
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 4ffec6fb41..832c312634 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
@@ -212,16 +212,15 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer
//i.e. it is only valid to call this method if
//
- // (a) the session is stopped, in which case the dispatcher is not running
+ // (a) the connection is stopped, in which case the dispatcher is not running
// OR
// (b) the listener is null AND we are not receiving synchronously at present
//
- if (_session.isStopped())
+ if (!_session.getAMQConnection().started())
{
_messageListener.set(messageListener);
_session.setHasMessageListeners();
- _session.startDistpatcherIfNecessary();
if (_logger.isDebugEnabled())
{
@@ -248,7 +247,6 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer
synchronized (_session)
{
-
_messageListener.set(messageListener);
_session.setHasMessageListeners();
_session.startDistpatcherIfNecessary();
@@ -329,12 +327,13 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer
public Message receive(long l) throws JMSException
{
- _session.startDistpatcherIfNecessary();
checkPreConditions();
acquireReceiving();
+ _session.startDistpatcherIfNecessary();
+
try
{
if (closeOnAutoClose())
@@ -385,12 +384,12 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer
public Message receiveNoWait() throws JMSException
{
- _session.startDistpatcherIfNecessary();
-
checkPreConditions();
acquireReceiving();
+ _session.startDistpatcherIfNecessary();
+
try
{
if (closeOnAutoClose())
@@ -560,7 +559,6 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer
}
else
{
- //This shouldn't be possible.
_synchronousQueue.put(jmsMessage);
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
index 4426a7deee..f56fc40360 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -388,9 +388,7 @@ public class BasicMessageProducer extends Closeable implements org.apache.qpid.j
}
else
{
- //TODO; Do we really want to create an empty message here ?
- newMessage = (AbstractJMSMessage) _session.createMessage();
- return new MessageConverter(newMessage).getConvertedMessage();
+ newMessage = new MessageConverter(message).getConvertedMessage();
}
if (newMessage != null)
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java
index 3086e5b90a..a1e2640f21 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java
@@ -269,7 +269,7 @@ public final class JMSHeaderAdapter
s = String.valueOf(o);
}
}
- }
+ }//else return s // null;
}
return s;
@@ -508,16 +508,16 @@ public final class JMSHeaderAdapter
// JMS invalid names
if ((propertyName.equals("NULL")
- || propertyName.equals("TRUE")
- || propertyName.equals("FALSE")
- || propertyName.equals("NOT")
- || propertyName.equals("AND")
- || propertyName.equals("OR")
- || propertyName.equals("BETWEEN")
- || propertyName.equals("LIKE")
- || propertyName.equals("IN")
- || propertyName.equals("IS")
- || propertyName.equals("ESCAPE")))
+ || propertyName.equals("TRUE")
+ || propertyName.equals("FALSE")
+ || propertyName.equals("NOT")
+ || propertyName.equals("AND")
+ || propertyName.equals("OR")
+ || propertyName.equals("BETWEEN")
+ || propertyName.equals("LIKE")
+ || propertyName.equals("IN")
+ || propertyName.equals("IS")
+ || propertyName.equals("ESCAPE")))
{
throw new IllegalArgumentException("Identifier '" + propertyName + "' is not allowed in JMS");
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java
index 58089f595b..6bb9b9912b 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java
@@ -25,7 +25,8 @@ import org.apache.log4j.Logger;
import javax.jms.*;
import java.util.Enumeration;
-public class MessageConverter {
+public class MessageConverter
+{
/**
* Log4J logger
@@ -118,6 +119,16 @@ public class MessageConverter {
setMessageProperties(message);
}
+ public MessageConverter(Message message) throws JMSException
+ {
+ //Send a message with just properties.
+ // Throwing away content
+ BytesMessage nativeMessage = new JMSBytesMessage();
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+ }
+
public AbstractJMSMessage getConvertedMessage()
{
return _newMessage;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
index 7f42faccb8..ca9a1b88f3 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
@@ -225,6 +225,7 @@ public class AMQStateManager implements AMQMethodListener
}
if(_currentState != s)
{
+ _logger.warn("State not achieved within permitted time. Current state " + _currentState + ", desired state: " + s);
throw new AMQException("State not achieved within permitted time. Current state " + _currentState + ", desired state: " + s);
}
}
diff --git a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
index cdb00240b6..5ab5722146 100644
--- a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
+++ b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
@@ -123,7 +123,7 @@ public class PropertiesFileInitialContextFactoryTest extends TestCase
try
{
AMQQueue queue = (AMQQueue) ctx.lookup("MyQueue");
- assertEquals("example.MyQueue", queue.getRoutingKey());
+ assertEquals("example.MyQueue", queue.getRoutingKey().toString());
}
catch (NamingException ne)
{
@@ -133,7 +133,7 @@ public class PropertiesFileInitialContextFactoryTest extends TestCase
try
{
AMQTopic topic = (AMQTopic) ctx.lookup("ibmStocks");
- assertEquals("stocks.nyse.ibm", topic.getTopicName());
+ assertEquals("stocks.nyse.ibm", topic.getTopicName().toString());
}
catch (Exception ne)
{
@@ -143,7 +143,7 @@ public class PropertiesFileInitialContextFactoryTest extends TestCase
try
{
AMQQueue direct = (AMQQueue) ctx.lookup("direct");
- assertEquals("directQueue", direct.getRoutingKey());
+ assertEquals("directQueue", direct.getRoutingKey().toString());
}
catch (NamingException ne)
{
diff --git a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Bind.java b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Bind.java
deleted file mode 100644
index db871281bf..0000000000
--- a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Bind.java
+++ /dev/null
@@ -1,250 +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.jndi.referenceabletest;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.url.URLSyntaxException;
-
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-import javax.jms.JMSException;
-import javax.jms.Session;
-import javax.jms.Topic;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NameAlreadyBoundException;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import java.io.File;
-import java.util.Hashtable;
-
-import junit.framework.TestCase;
-
-/**
- * Usage: To run these you need to have the sun JNDI SPI for the FileSystem.
- * This can be downloaded from sun here:
- * http://java.sun.com/products/jndi/downloads/index.html
- * Click : Download JNDI 1.2.1 & More button
- * Download: File System Service Provider, 1.2 Beta 3
- * and add the two jars in the lib dir to your class path.
- * <p/>
- * Also you need to create the directory /temp/qpid-jndi-test
- */
-class Bind extends TestCase
-{
- public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + "/JNDITest" + System.currentTimeMillis();
- public static final String DEFAULT_PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
- public String PROVIDER_URL = DEFAULT_PROVIDER_URL;
-
- String _connectionFactoryString = "";
-
- String _connectionString = "amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'";
- Topic _topic = null;
-
- boolean _bound = false;
-
- public Bind() throws NameAlreadyBoundException, NoInitialContextException
- {
- this(false, DEFAULT_PROVIDER_URL);
- }
-
- public Bind(boolean output) throws NameAlreadyBoundException, NoInitialContextException
- {
- this(output, DEFAULT_PROVIDER_URL);
- }
-
- public Bind(boolean output, String providerURL) throws NameAlreadyBoundException, NoInitialContextException
- {
- PROVIDER_URL = providerURL;
-
- // Set up the environment for creating the initial context
- Hashtable env = new Hashtable(11);
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.fscontext.RefFSContextFactory");
-
-
- env.put(Context.PROVIDER_URL, PROVIDER_URL);
-
-
- File file = new File(PROVIDER_URL.substring(PROVIDER_URL.indexOf("://") + 3));
-
- if (file.exists() && !file.isDirectory())
- {
- System.out.println("Couldn't make directory file already exists");
- return;
- }
- else
- {
- if (!file.exists())
- {
- if (!file.mkdirs())
- {
- System.out.println("Couldn't make directory");
- return;
- }
- }
- }
-
- Connection connection = null;
- try
- {
- // Create the initial context
- Context ctx = new InitialContext(env);
-
- // Create the connection factory to be bound
- ConnectionFactory connectionFactory = null;
- // Create the Connection to be bound
-
-
- try
- {
- connectionFactory = new AMQConnectionFactory(_connectionString);
- connection = connectionFactory.createConnection();
-
- _connectionFactoryString = ((AMQConnectionFactory) connectionFactory).getConnectionURL().getURL();
- }
- catch (JMSException jmsqe)
- {
- fail("Unable to create Connection:" + jmsqe);
- }
- catch (URLSyntaxException urlse)
- {
- fail("Unable to create Connection:" + urlse);
- }
-
- try
- {
- Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- _topic = session.createTopic("Fruity");
- }
- catch (JMSException jmse)
- {
-
- }
- // Perform the binds
- ctx.bind("ConnectionFactory", connectionFactory);
- if (output)
- {
- System.out.println("Bound factory\n" + ((AMQConnectionFactory) connectionFactory).getConnectionURL());
- }
- ctx.bind("Connection", connection);
- if (output)
- {
- System.out.println("Bound Connection\n" + ((AMQConnection) connection).toURL());
- }
- ctx.bind("Topic", _topic);
- if (output)
- {
- System.out.println("Bound Topic:\n" + ((AMQTopic) _topic).toURL());
- }
- _bound = true;
-
- // Check that it is bound
- //Object obj = ctx.lookup("Connection");
- //System.out.println(((AMQConnection)obj).toURL());
-
- // Close the context when we're done
- ctx.close();
- }
- catch (NamingException e)
- {
- System.out.println("Operation failed: " + e);
- if (e instanceof NameAlreadyBoundException)
- {
- throw(NameAlreadyBoundException) e;
- }
-
- if (e instanceof NoInitialContextException)
- {
- throw(NoInitialContextException) e;
- }
- }
- finally
- {
- try
- {
- if (connection != null)
- {
- connection.close();
- }
- }
- catch (JMSException e)
- {
- //ignore just want it closed
- }
- }
- }
-
- public String connectionFactoryValue()
- {
- if (_connectionFactoryString != null)
- {
- return _connectionFactoryString;
- }
- else
- {
- return "";
- }
- }
-
- public String connectionValue()
- {
- if (_connectionString != null)
- {
- return _connectionString;
- }
- else
- {
- return "";
- }
- }
-
- public String topicValue()
- {
- if (_topic != null)
- {
- return ((AMQTopic) _topic).toURL();
- }
- else
- {
- return "";
- }
-
- }
-
- public boolean bound()
- {
- return _bound;
- }
-
- public String getProviderURL()
- {
- return PROVIDER_URL;
- }
-
- public static void main(String[] args) throws NameAlreadyBoundException, NoInitialContextException
- {
- new Bind(true);
- }
-}
diff --git a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/JNDIReferenceableTest.java b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/JNDIReferenceableTest.java
deleted file mode 100644
index 9fc186f19a..0000000000
--- a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/JNDIReferenceableTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.test.unit.jndi.referenceabletest;
-
-import junit.framework.TestCase;
-//import org.apache.qpid.testutil.VMBrokerSetup;
-
-import javax.naming.NameAlreadyBoundException;
-import javax.naming.NoInitialContextException;
-
-/**
- * Usage: To run these you need to have the sun JNDI SPI for the FileSystem.
- * This can be downloaded from sun here:
- * http://java.sun.com/products/jndi/downloads/index.html
- * Click : Download JNDI 1.2.1 & More button
- * Download: File System Service Provider, 1.2 Beta 3
- * and add the two jars in the lib dir to your class path.
- * <p/>
- * Also you need to create the directory /temp/qpid-jndi-test
- */
-public class JNDIReferenceableTest extends TestCase
-{
-/* // FIXME FSContext has been removed from repository. This needs redone with the PropertiesFileInitialContextFactory. QPID-84
- public void testReferenceable()
- {
- Bind b = null;
- try
- {
- try
- {
- b = new Bind();
- }
- catch (NameAlreadyBoundException e)
- {
- if (new Unbind().unbound())
- {
- try
- {
- b = new Bind();
- }
- catch (NameAlreadyBoundException ee)
- {
- fail("Unable to clear bound objects for test.");
- }
- }
- else
- {
- fail("Unable to clear bound objects for test.");
- }
- }
- }
- catch (NoInitialContextException e)
- {
- fail("You don't have the File System SPI on you class path.\n" +
- "This can be downloaded from sun here:\n" +
- "http://java.sun.com/products/jndi/downloads/index.html\n" +
- "Click : Download JNDI 1.2.1 & More button\n" +
- "Download: File System Service Provider, 1.2 Beta 3\n" +
- "and add the two jars in the lib dir to your class path.");
- }
-
- assertTrue(b.bound());
-
- Lookup l = new Lookup(b.getProviderURL());
-
- assertTrue(l.connectionFactoryValue().equals(b.connectionFactoryValue()));
-
- assertTrue(l.connectionValue().equals(b.connectionValue()));
-
- assertTrue(l.topicValue().equals(b.topicValue()));
-
-
- Unbind u = new Unbind();
-
- assertTrue(u.unbound());
-
- }
-
- public static junit.framework.Test suite()
- {
- return new VMBrokerSetup(new junit.framework.TestSuite(JNDIReferenceableTest.class));
- }
- */
-}
diff --git a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Lookup.java b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Lookup.java
deleted file mode 100644
index b804ccb30c..0000000000
--- a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Lookup.java
+++ /dev/null
@@ -1,167 +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.jndi.referenceabletest;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.client.AMQTopic;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.jms.JMSException;
-import java.io.File;
-import java.util.Hashtable;
-
-
-/**
- * Usage: To run these you need to have the sun JNDI SPI for the FileSystem.
- * This can be downloaded from sun here:
- * http://java.sun.com/products/jndi/downloads/index.html
- * Click : Download JNDI 1.2.1 & More button
- * Download: File System Service Provider, 1.2 Beta 3
- * and add the two jars in the lib dir to your class path.
- * <p/>
- * Also you need to create the directory /temp/qpid-jndi-test
- */
-class Lookup
-{
- public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + "/JNDITest";
- public static final String DEFAULT_PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
- public String PROVIDER_URL = DEFAULT_PROVIDER_URL;
-
- AMQTopic _topic = null;
- AMQConnection _connection = null;
- AMQConnectionFactory _connectionFactory = null;
- private String _connectionURL;
-
-
- public Lookup()
- {
- this(DEFAULT_PROVIDER_URL);
- }
-
- public Lookup(String providerURL)
- {
-
- PROVIDER_URL = providerURL;
-
- // Set up the environment for creating the initial context
- Hashtable env = new Hashtable(11);
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.fscontext.RefFSContextFactory");
-
- env.put(Context.PROVIDER_URL, PROVIDER_URL);
-
- File file = new File(PROVIDER_URL.substring(PROVIDER_URL.indexOf("://") + 3));
-
- if (file.exists() && !file.isDirectory())
- {
- System.out.println("Couldn't make directory file already exists");
- return;
- }
- else
- {
- if (!file.exists())
- {
- if (!file.mkdirs())
- {
- System.out.println("Couldn't make directory");
- return;
- }
- }
- }
-
- try
- {
- // Create the initial context
- Context ctx = new InitialContext(env);
-
- _topic = (AMQTopic) ctx.lookup("Topic");
-
- _connection = (AMQConnection) ctx.lookup("Connection");
-
- _connectionURL = _connection.toURL();
-
- _connectionFactory = (AMQConnectionFactory) ctx.lookup("ConnectionFactory");
- //System.out.println(topic);
-
- // Close the context when we're done
- ctx.close();
- }
- catch (NamingException e)
- {
- System.out.println("Operation failed: " + e);
- }
- finally
- {
- try
- {
- if (_connection != null)
- {
- _connection.close();
- }
- }
- catch (JMSException e)
- {
- //ignore just need to close
- }
- }
- }
-
- public String connectionFactoryValue()
- {
- if (_connectionFactory != null)
- {
- return _connectionFactory.getConnectionURL().toString();
- }
- return "";
- }
-
- public String connectionValue()
- {
- if (_connectionURL != null)
- {
- return _connectionURL;
- }
- return "";
- }
-
- public String topicValue()
- {
- if (_topic != null)
- {
- return _topic.toURL();
- }
- return "";
- }
-
- public String getProviderURL()
- {
- return PROVIDER_URL;
- }
-
- public static void main(String[] args)
- {
- new Lookup();
- }
-}
-
diff --git a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Unbind.java b/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Unbind.java
deleted file mode 100644
index 869bc55d8f..0000000000
--- a/qpid/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/referenceabletest/Unbind.java
+++ /dev/null
@@ -1,173 +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.jndi.referenceabletest;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingException;
-import javax.jms.Connection;
-import javax.jms.JMSException;
-import java.io.File;
-import java.util.Hashtable;
-
-/**
- * Usage: To run these you need to have the sun JNDI SPI for the FileSystem.
- * This can be downloaded from sun here:
- * http://java.sun.com/products/jndi/downloads/index.html
- * Click : Download JNDI 1.2.1 & More button
- * Download: File System Service Provider, 1.2 Beta 3
- * and add the two jars in the lib dir to your class path.
- * <p/>
- * Also you need to create the directory /temp/qpid-jndi-test
- */
-class Unbind
-{
- public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + "/JNDITest" + System.currentTimeMillis();
- public static final String DEFAULT_PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
- public String PROVIDER_URL = DEFAULT_PROVIDER_URL;
-
- boolean _unbound = false;
-
- public Unbind()
- {
- this(false, DEFAULT_PROVIDER_URL);
- }
-
- public Unbind(Boolean output)
- {
- this(output, DEFAULT_PROVIDER_URL);
- }
-
- public Unbind(String provider)
- {
- this(false, provider);
- }
-
- public Unbind(boolean output, String providerURL)
- {
- PROVIDER_URL = providerURL;
- // Set up the environment for creating the initial context
- Hashtable env = new Hashtable(11);
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.fscontext.RefFSContextFactory");
- env.put(Context.PROVIDER_URL, PROVIDER_URL);
-
- File file = new File(PROVIDER_URL.substring(PROVIDER_URL.indexOf("://") + 3));
-
- if (file.exists() && !file.isDirectory())
- {
- System.out.println("Couldn't make directory file already exists");
- return;
- }
- else
- {
- if (!file.exists())
- {
- if (!file.mkdirs())
- {
- System.out.println("Couldn't make directory");
- return;
- }
- }
- }
-
- try
- {
- // Create the initial context
- Context ctx = new InitialContext(env);
-
- // Remove the binding
- ctx.unbind("ConnectionFactory");
- ctx.unbind("Connection");
- ctx.unbind("Topic");
-
- // Check that it is gone
- Object obj = null;
- try
- {
- obj = ctx.lookup("ConnectionFactory");
- }
- catch (NameNotFoundException ne)
- {
- if (output)
- {
- System.out.println("unbind ConnectionFactory successful");
- }
- try
- {
- obj = ctx.lookup("Connection");
- try
- {
- ((Connection) obj).close();
- }
- catch (JMSException e)
- {
- //ignore just need to close
- }
- }
- catch (NameNotFoundException ne2)
- {
- if (output)
- {
- System.out.println("unbind Connection successful");
- }
-
- try
- {
- obj = ctx.lookup("Topic");
- }
- catch (NameNotFoundException ne3)
- {
- if (output)
- {
- System.out.println("unbind Topic successful");
- }
- _unbound = true;
- }
- }
- }
-
- //System.out.println("unbind failed; object still there: " + obj);
-
- // Close the context when we're done
-
- ctx.close();
-
- }
- catch (NamingException e)
- {
- System.out.println("Operation failed: " + e);
- }
- }
-
- public boolean unbound()
- {
- return _unbound;
- }
-
- public static void main(String[] args)
- {
-
- new Unbind(true);
- }
-}
-
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java
new file mode 100644
index 0000000000..165059946c
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.client;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Message;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue
+ * <p/>
+ * The message delivery process:
+ * Mina puts a message on _queue in AMQSession and the dispatcher thread take()s
+ * from here and dispatches to the _consumers. If the _consumer doesn't have a message listener set at connection start
+ * then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple consumers on a
+ * session can run in any order and a synchronous put/poll will block the dispatcher).
+ * <p/>
+ * When setting the message listener later the _synchronousQueue is just poll()'ed and the first message delivered
+ * the remaining messages will be left on the queue and lost, subsequent messages on the session will arrive first.
+ */
+public class DispatcherTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(DispatcherTest.class);
+
+ Context _context;
+
+ private static final int MSG_COUNT = 6;
+ private int _receivedCount = 0;
+ private int _receivedCountWhileStopped = 0;
+ private Connection _clientConnection, _producerConnection;
+ private MessageConsumer _consumer;
+ MessageProducer _producer;
+ Session _clientSession, _producerSession;
+
+ private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(1); //all messages Sent Lock
+ private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(1); //all messages Sent Lock
+
+ private volatile boolean _connectionStopped = false;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ InitialContextFactory factory = new PropertiesFileInitialContextFactory();
+
+ Hashtable<String, String> env = new Hashtable<String, String>();
+
+ env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'");
+ env.put("queue.queue", "direct://amq.direct//MessageListenerTest");
+
+ _context = factory.getInitialContext(env);
+
+ Queue queue = (Queue) _context.lookup("queue");
+
+ //Create Client 1
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer = _clientSession.createConsumer(queue);
+
+ //Create Producer
+ _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _producerConnection.start();
+
+ _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _producer = _producerSession.createProducer(queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+
+ _clientConnection.close();
+
+ _producerConnection.close();
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+
+ public void testAsynchronousRecieve()
+ {
+
+ _logger.info("Test Start");
+
+
+ assertTrue(!((AMQConnection) _clientConnection).started());
+
+ //Set default Message Listener
+ try
+ {
+ _consumer.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 ML 1 Received Message(" + _receivedCount + "):" + message);
+
+ _receivedCount++;
+
+ if (_receivedCount == MSG_COUNT)
+ {
+ _allFirstMessagesSent.countDown();
+ }
+
+ if (_connectionStopped)
+ {
+ _logger.info("Running with Message:" + _receivedCount);
+ }
+
+ if (_connectionStopped && _allFirstMessagesSent.getCount() == 0)
+ {
+ _receivedCountWhileStopped++;
+ }
+
+ if (_allFirstMessagesSent.getCount() == 0)
+ {
+ if (_receivedCount == MSG_COUNT * 2)
+ {
+ _allSecondMessagesSent.countDown();
+ }
+ }
+ }
+ });
+
+ assertTrue("Connecion should not be started", !((AMQConnection) _clientConnection).started());
+ _clientConnection.start();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer1");
+ }
+
+
+ try
+ {
+ _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+
+ try
+ {
+ assertTrue("Connecion should be started", ((AMQConnection) _clientConnection).started());
+ _clientConnection.stop();
+ _connectionStopped = true;
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error stopping connection");
+ }
+
+
+ try
+ {
+ _logger.error("Send additional messages");
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Unable to send additional messages", e);
+ }
+
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ //ignore
+ }
+
+ try
+ {
+ _logger.info("Restarting connection");
+
+ _connectionStopped = false;
+ _clientConnection.start();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Better ML on consumer1", e);
+ }
+
+
+ _logger.info("Waiting upto 2 seconds for messages");
+
+ try
+ {
+ _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+
+ assertEquals("Messages not received correctly", 0, _allFirstMessagesSent.getCount());
+ assertEquals("Messages not received correctly", 0, _allSecondMessagesSent.getCount());
+ assertEquals("Client didn't get all messages", MSG_COUNT * 2, _receivedCount);
+ assertEquals("Messages received while stopped is not 0", 0, _receivedCountWhileStopped);
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(DispatcherTest.class);
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java
new file mode 100644
index 0000000000..28bb2b614b
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 junit.framework.TestCase;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Message;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue
+ * <p/>
+ * The message delivery process:
+ * Mina puts a message on _queue in AMQSession and the dispatcher thread take()s
+ * from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at connection start
+ * then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple consumers on a
+ * session can run in any order and a synchronous put/poll will block the dispatcher).
+ * <p/>
+ * When setting the message listener later the _synchronousQueue is just poll()'ed and the first message delivered
+ * the remaining messages will be left on the queue and lost, subsequent messages on the session will arrive first.
+ */
+public class ResetMessageListenerTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(ResetMessageListenerTest.class);
+
+ Context _context;
+
+ private static final int MSG_COUNT = 6;
+ private int receivedCount1ML1 = 0;
+ private int receivedCount1ML2 = 0;
+ private int receivedCount2 = 0;
+ private Connection _clientConnection, _producerConnection;
+ private MessageConsumer _consumer1;
+ private MessageConsumer _consumer2;
+ MessageProducer _producer;
+ Session _clientSession, _producerSession;
+
+ private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(2); //all messages Sent Lock
+ private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(2); //all messages Sent Lock
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ InitialContextFactory factory = new PropertiesFileInitialContextFactory();
+
+ Hashtable<String, String> env = new Hashtable<String, String>();
+
+ env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'");
+ env.put("queue.queue", "direct://amq.direct//MessageListenerTest");
+
+ _context = factory.getInitialContext(env);
+
+ Queue queue = (Queue) _context.lookup("queue");
+
+ //Create Client 1
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer1 = _clientSession.createConsumer(queue);
+
+ //Create Client 2 on same session
+ _consumer2 = _clientSession.createConsumer(queue);
+
+ //Create Producer
+ _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _producerConnection.start();
+
+ _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _producer = _producerSession.createProducer(queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+ assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent.getCount());
+ assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent.getCount());
+ assertEquals("Client 1 ML1 didn't get all messages", MSG_COUNT / 2, receivedCount1ML1);
+ assertEquals("Client 2 didn't get all messages", MSG_COUNT, receivedCount2);
+ assertEquals("Client 1 ML2 didn't get all messages", MSG_COUNT / 2, receivedCount1ML2);
+
+ _clientConnection.close();
+
+ _producerConnection.close();
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+
+ public void testAsynchronousRecieve()
+ {
+
+ _logger.info("Test Start");
+
+ //Set default Message Listener
+ try
+ {
+ _consumer1.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 ML 1 Received Message(" + receivedCount1ML1 + "):" + message);
+
+ receivedCount1ML1++;
+ if (receivedCount1ML1 == MSG_COUNT / 2)
+ {
+ _allFirstMessagesSent.countDown();
+ }
+ }
+ });
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer1");
+ }
+
+
+ try
+ {
+ _consumer2.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 2 Received Message(" + receivedCount2 + "):" + message);
+
+ receivedCount2++;
+ if (receivedCount2 == MSG_COUNT / 2)
+ {
+ _logger.info("Client 2 received all its messages1");
+ _allFirstMessagesSent.countDown();
+ }
+
+ if (receivedCount2 == MSG_COUNT)
+ {
+ _logger.info("Client 2 received all its messages2");
+ _allSecondMessagesSent.countDown();
+ }
+ }
+ });
+
+ _clientConnection.start();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer2");
+
+ }
+
+
+ try
+ {
+ _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ _logger.info("Received first batch of messages");
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+
+ try
+ {
+ _clientConnection.stop();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error stopping connection");
+ }
+
+ _logger.info("Reset Message Listener to better listener while connection stopped, will restart session");
+ try
+ {
+ _consumer1.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 ML2 Received Message(" + receivedCount1ML1 + "):" + message);
+
+ receivedCount1ML2++;
+ if (receivedCount1ML2 == MSG_COUNT / 2)
+ {
+ _allSecondMessagesSent.countDown();
+ }
+ }
+ });
+
+ _clientConnection.start();
+ }
+ catch (javax.jms.IllegalStateException e)
+ {
+ _logger.error("Connection not stopped while setting ML", e);
+ fail("Unable to change message listener:" + e.getCause());
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Better ML on consumer1", e);
+ }
+
+ try
+ {
+ _logger.error("Send additional messages");
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Unable to send additional messages", e);
+ }
+
+ _logger.info("Waiting upto 2 seconds for messages");
+
+ try
+ {
+ _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ResetMessageListenerTest.class);
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/message/TestNonQpidTextMessage.java b/qpid/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java
index f7bea1b36a..c3434164d8 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/message/TestNonQpidTextMessage.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java
@@ -24,7 +24,7 @@ import javax.jms.*;
import java.util.Enumeration;
import java.io.Serializable;
-public class TestNonQpidTextMessage implements ObjectMessage {
+public class NonQpidObjectMessage implements ObjectMessage {
private JMSObjectMessage _realMessage;
private String _contentString;
@@ -34,7 +34,7 @@ public class TestNonQpidTextMessage implements ObjectMessage {
* does not inherit from the Qpid message superclasses
* and expand our unit testing of MessageConverter et al
*/
- public TestNonQpidTextMessage()
+ public NonQpidObjectMessage()
{
_realMessage = new JMSObjectMessage();
}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java
new file mode 100644
index 0000000000..3287314a44
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client.connection;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.message.AMQMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQConnectionException;
+import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.AMQConnectionFailureException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.MessageProducer;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+import junit.framework.TestCase;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ConnectionStartTest extends TestCase
+{
+
+ String _broker = "vm://:1";
+
+ AMQConnection _connection;
+ private Session _consumerSess;
+ private MessageConsumer _consumer;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ try
+ {
+ AMQQueue queue = new AMQQueue("ConnectionStartTest");
+
+ AMQConnection pubCon = new AMQConnection(_broker, "guest", "guest", "fred", "test");
+
+ Session pubSess = pubCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+
+ MessageProducer pub = pubSess.createProducer(queue);
+
+ pub.send(pubSess.createTextMessage("Initial Message"));
+
+ _connection = new AMQConnection(_broker, "guest", "guest", "fred", "test");
+
+ _consumerSess = _connection.createSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+
+ _consumer = _consumerSess.createConsumer(queue);
+
+ pubCon.close();
+
+ }
+ catch (Exception e)
+ {
+ fail("Connection to " + _broker + " should succeed. Reason: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _connection.close();
+ TransportConnection.killVMBroker(1);
+ }
+
+ public void testSimpleReceiveConnection()
+ {
+ try
+ {
+ assertTrue("Connection should not be started", !_connection.started());
+ //Note that this next line will start the dispatcher in the session
+ // should really not be called before _connection start
+ assertTrue("There should not be messages waiting for the consumer", _consumer.receiveNoWait() == null);
+ _connection.start();
+ assertTrue("There should be messages waiting for the consumer", _consumer.receiveNoWait() == null);
+ assertTrue("Connection should be started", _connection.started());
+
+ }
+ catch (JMSException e)
+ {
+ fail("An error occured during test because:" + e);
+ }
+
+ }
+
+ public void testMessageListenerConnection()
+ {
+ final CountDownLatch _gotMessage = new CountDownLatch(1);
+
+ try
+ {
+ assertTrue("Connection should not be started", !_connection.started());
+ _consumerSess.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ try
+ {
+ assertTrue("Connection should be started", _connection.started());
+ assertEquals("Mesage Received", "Initial Message", ((TextMessage) message).getText());
+ _gotMessage.countDown();
+ }
+ catch (JMSException e)
+ {
+ fail("Couldn't get message text because:" + e.getCause());
+ }
+ }
+ });
+
+ assertTrue("Connection should not be started", !_connection.started());
+ _connection.start();
+ assertTrue("Connection should be started", _connection.started());
+
+ try
+ {
+ _gotMessage.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ fail("Timed out awaiting message via onMessage");
+ }
+
+ }
+ catch (JMSException e)
+ {
+ fail("Failed because:" + e.getCause());
+ }
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ConnectionStartTest.class);
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
index c09d2504eb..2d61ceb00f 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
@@ -26,7 +26,7 @@ import org.apache.qpid.client.transport.TransportConnection;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.message.TestNonQpidTextMessage;
+import org.apache.qpid.client.message.NonQpidObjectMessage;
import org.apache.qpid.framing.AMQShortString;
import javax.jms.*;
@@ -71,7 +71,7 @@ public class JMSPropertiesTest extends TestCase
MessageProducer producer = producerSession.createProducer(queue);
//create a test message to send
- ObjectMessage sentMsg = new TestNonQpidTextMessage();
+ ObjectMessage sentMsg = new NonQpidObjectMessage();
sentMsg.setJMSCorrelationID(JMS_CORR_ID);
sentMsg.setJMSDeliveryMode(JMS_DELIV_MODE);
sentMsg.setJMSType(JMS_TYPE);
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java
index 6a335b8627..a8a5c7d8b2 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java
@@ -31,10 +31,12 @@ import javax.jms.Message;
import javax.jms.Destination;
import javax.jms.TextMessage;
import javax.jms.MapMessage;
+import javax.jms.JMSException;
import java.util.HashMap;
-public class MessageConverterTest extends TestCase {
+public class MessageConverterTest extends TestCase
+{
public static final String JMS_CORR_ID = "QPIDID_01";
public static final int JMS_DELIV_MODE = 1;
@@ -50,53 +52,79 @@ public class MessageConverterTest extends TestCase {
super.setUp();
testTextMessage = new JMSTextMessage();
- //Add JMSProperties
- testTextMessage.setJMSCorrelationID(JMS_CORR_ID);
- testTextMessage.setJMSDeliveryMode(JMS_DELIV_MODE);
- testTextMessage.setJMSType(JMS_TYPE);
- testTextMessage.setJMSReplyTo(JMS_REPLY_TO);
+ //Set Message Text
testTextMessage.setText("testTextMessage text");
-
- //Add non-JMS properties
- testTextMessage.setStringProperty("testProp1","testValue1");
- testTextMessage.setDoubleProperty("testProp2",Double.MIN_VALUE);
+ setMessageProperties(testTextMessage);
testMapMessage = new JMSMapMessage();
- testMapMessage.setString("testMapString","testMapStringValue");
- testMapMessage.setDouble("testMapDouble",Double.MAX_VALUE);
+ testMapMessage.setString("testMapString", "testMapStringValue");
+ testMapMessage.setDouble("testMapDouble", Double.MAX_VALUE);
}
public void testSetProperties() throws Exception
{
- AbstractJMSMessage newMessage = new MessageConverter((TextMessage)testTextMessage).getConvertedMessage();
-
- //check JMS prop values on newMessage match
- assertEquals("JMS Correlation ID mismatch",testTextMessage.getJMSCorrelationID(),newMessage.getJMSCorrelationID());
- assertEquals("JMS Delivery mode mismatch",testTextMessage.getJMSDeliveryMode(),newMessage.getJMSDeliveryMode());
- assertEquals("JMS Type mismatch",testTextMessage.getJMSType(),newMessage.getJMSType());
- assertEquals("JMS Reply To mismatch",testTextMessage.getJMSReplyTo(),newMessage.getJMSReplyTo());
-
- //check non-JMS standard props ok too
- assertEquals("Test String prop value mismatch",testTextMessage.getStringProperty("testProp1"),
- newMessage.getStringProperty("testProp1"));
- assertEquals("Test Double prop value mismatch",testTextMessage.getDoubleProperty("testProp2"),
- newMessage.getDoubleProperty("testProp2"));
+ AbstractJMSMessage newMessage = new MessageConverter((TextMessage) testTextMessage).getConvertedMessage();
+ mesagePropertiesTest(testTextMessage, newMessage);
}
public void testJMSTextMessageConversion() throws Exception
{
- AbstractJMSMessage newMessage = new MessageConverter((TextMessage)testTextMessage).getConvertedMessage();
- assertEquals("Converted message text mismatch",((JMSTextMessage)newMessage).getText(),testTextMessage.getText());
+ AbstractJMSMessage newMessage = new MessageConverter((TextMessage) testTextMessage).getConvertedMessage();
+ assertEquals("Converted message text mismatch", ((JMSTextMessage) newMessage).getText(), testTextMessage.getText());
}
public void testJMSMapMessageConversion() throws Exception
{
- AbstractJMSMessage newMessage = new MessageConverter((MapMessage)testMapMessage).getConvertedMessage();
- assertEquals("Converted map message String mismatch",((JMSMapMessage)newMessage).getString("testMapString"),
- testMapMessage.getString("testMapString"));
- assertEquals("Converted map message Double mismatch",((JMSMapMessage)newMessage).getDouble("testMapDouble"),
- testMapMessage.getDouble("testMapDouble"));
+ AbstractJMSMessage newMessage = new MessageConverter((MapMessage) testMapMessage).getConvertedMessage();
+ assertEquals("Converted map message String mismatch", ((JMSMapMessage) newMessage).getString("testMapString"),
+ testMapMessage.getString("testMapString"));
+ assertEquals("Converted map message Double mismatch", ((JMSMapMessage) newMessage).getDouble("testMapDouble"),
+ testMapMessage.getDouble("testMapDouble"));
+
+ }
+
+ public void testMessageConversion() throws Exception
+ {
+ Message newMessage = new NonQpidMessage();
+ setMessageProperties(newMessage);
+ mesagePropertiesTest(testTextMessage, newMessage);
+ }
+
+ private void setMessageProperties(Message message) throws JMSException
+ {
+ message.setJMSCorrelationID(JMS_CORR_ID);
+ message.setJMSDeliveryMode(JMS_DELIV_MODE);
+ message.setJMSType(JMS_TYPE);
+ message.setJMSReplyTo(JMS_REPLY_TO);
+ //Add non-JMS properties
+ message.setStringProperty("testProp1", "testValue1");
+ message.setDoubleProperty("testProp2", Double.MIN_VALUE);
+ }
+
+
+ private void mesagePropertiesTest(Message expectedMessage, Message actualMessage)
+ {
+ try
+ {
+ //check JMS prop values on newMessage match
+ assertEquals("JMS Correlation ID mismatch", expectedMessage.getJMSCorrelationID(), actualMessage.getJMSCorrelationID());
+ assertEquals("JMS Delivery mode mismatch", expectedMessage.getJMSDeliveryMode(), actualMessage.getJMSDeliveryMode());
+ assertEquals("JMS Type mismatch", expectedMessage.getJMSType(), actualMessage.getJMSType());
+ assertEquals("JMS Reply To mismatch", expectedMessage.getJMSReplyTo(), actualMessage.getJMSReplyTo());
+
+ //check non-JMS standard props ok too
+ assertEquals("Test String prop value mismatch", expectedMessage.getStringProperty("testProp1"),
+ actualMessage.getStringProperty("testProp1"));
+
+ assertEquals("Test Double prop value mismatch", expectedMessage.getDoubleProperty("testProp2"),
+ actualMessage.getDoubleProperty("testProp2"));
+ }
+ catch (JMSException e)
+ {
+ fail("An error occured testing the property values" + e.getCause());
+ e.printStackTrace();
+ }
}
protected void tearDown() throws Exception
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java
new file mode 100644
index 0000000000..e992290513
--- /dev/null
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java
@@ -0,0 +1,410 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.message;
+
+import javax.jms.Message;
+import javax.jms.JMSException;
+import javax.jms.Destination;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+public class NonQpidMessage implements Message
+{
+ private String _JMSMessageID;
+ private long _JMSTimestamp;
+ private byte[] _JMSCorrelationIDAsBytes;
+ private String _JMSCorrelationID;
+ private Destination _JMSReplyTo;
+ private Destination _JMSDestination;
+ private int _JMSDeliveryMode;
+ private boolean _JMSRedelivered;
+ private String _JMSType;
+ private long _JMSExpiration;
+ private int _JMSPriority;
+ private Hashtable _properties;
+
+ public NonQpidMessage()
+ {
+ _properties = new Hashtable();
+ _JMSPriority = javax.jms.Message.DEFAULT_PRIORITY;
+ _JMSDeliveryMode = javax.jms.Message.DEFAULT_DELIVERY_MODE;
+ }
+
+ public String getJMSMessageID() throws JMSException
+ {
+ return _JMSMessageID;
+ }
+
+ public void setJMSMessageID(String string) throws JMSException
+ {
+ _JMSMessageID = string;
+ }
+
+ public long getJMSTimestamp() throws JMSException
+ {
+ return _JMSTimestamp;
+ }
+
+ public void setJMSTimestamp(long l) throws JMSException
+ {
+ _JMSTimestamp = l;
+ }
+
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException
+ {
+ return _JMSCorrelationIDAsBytes;
+ }
+
+ public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException
+ {
+ _JMSCorrelationIDAsBytes = bytes;
+ }
+
+ public void setJMSCorrelationID(String string) throws JMSException
+ {
+ _JMSCorrelationID = string;
+ }
+
+ public String getJMSCorrelationID() throws JMSException
+ {
+ return _JMSCorrelationID;
+ }
+
+ public Destination getJMSReplyTo() throws JMSException
+ {
+ return _JMSReplyTo;
+ }
+
+ public void setJMSReplyTo(Destination destination) throws JMSException
+ {
+ _JMSReplyTo = destination;
+ }
+
+ public Destination getJMSDestination() throws JMSException
+ {
+ return _JMSDestination;
+ }
+
+ public void setJMSDestination(Destination destination) throws JMSException
+ {
+ _JMSDestination = destination;
+ }
+
+ public int getJMSDeliveryMode() throws JMSException
+ {
+ return _JMSDeliveryMode;
+ }
+
+ public void setJMSDeliveryMode(int i) throws JMSException
+ {
+ _JMSDeliveryMode = i;
+ }
+
+ public boolean getJMSRedelivered() throws JMSException
+ {
+ return _JMSRedelivered;
+ }
+
+ public void setJMSRedelivered(boolean b) throws JMSException
+ {
+ _JMSRedelivered = b;
+ }
+
+ public String getJMSType() throws JMSException
+ {
+ return _JMSType;
+ }
+
+ public void setJMSType(String string) throws JMSException
+ {
+ _JMSType = string;
+ }
+
+ public long getJMSExpiration() throws JMSException
+ {
+ return _JMSExpiration;
+ }
+
+ public void setJMSExpiration(long l) throws JMSException
+ {
+ _JMSExpiration = l;
+ }
+
+ public int getJMSPriority() throws JMSException
+ {
+ return _JMSPriority;
+ }
+
+ public void setJMSPriority(int i) throws JMSException
+ {
+ _JMSPriority = i;
+ }
+
+ public void clearProperties() throws JMSException
+ {
+ _properties.clear();
+ }
+
+ public boolean propertyExists(String string) throws JMSException
+ {
+ return _properties.containsKey(string);
+ }
+
+ public boolean getBooleanProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Boolean)
+ {
+ return (Boolean) o;
+ }
+ else
+ {
+ return Boolean.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public byte getByteProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Byte)
+ {
+ return (Byte) o;
+ }
+ else
+ {
+ return Byte.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public short getShortProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Short)
+ {
+ return (Short) o;
+ }
+ else
+ {
+ return Short.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public int getIntProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Integer)
+ {
+ return (Integer) o;
+ }
+ else
+ {
+ return Integer.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public long getLongProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Long)
+ {
+ return (Long) o;
+ }
+ else
+ {
+ return Long.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public float getFloatProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Float)
+ {
+ return (Float) o;
+ }
+ else
+ {
+ return Float.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public double getDoubleProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Double)
+ {
+ return (Double) o;
+ }
+ else
+ {
+ return Double.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public String getStringProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof String)
+ {
+ return (String) o;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public Object getObjectProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Boolean)
+ {
+ return (Boolean) o;
+ }
+ else
+ {
+ return Boolean.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public Enumeration getPropertyNames() throws JMSException
+ {
+ return _properties.keys();
+ }
+
+ public void setBooleanProperty(String string, boolean b) throws JMSException
+ {
+ _properties.put(string, b);
+ }
+
+ public void setByteProperty(String string, byte b) throws JMSException
+ {
+ _properties.put(string, b);
+ }
+
+ public void setShortProperty(String string, short i) throws JMSException
+ {
+ _properties.put(string, i);
+ }
+
+ public void setIntProperty(String string, int i) throws JMSException
+ {
+ _properties.put(string, i);
+ }
+
+ public void setLongProperty(String string, long l) throws JMSException
+ {
+ _properties.put(string, l);
+ }
+
+ public void setFloatProperty(String string, float v) throws JMSException
+ {
+ _properties.put(string, v);
+ }
+
+ public void setDoubleProperty(String string, double v) throws JMSException
+ {
+ _properties.put(string, v);
+ }
+
+ public void setStringProperty(String string, String string1) throws JMSException
+ {
+ _properties.put(string, string1);
+ }
+
+ public void setObjectProperty(String string, Object object) throws JMSException
+ {
+ _properties.put(string, object);
+ }
+
+ public void acknowledge() throws JMSException
+ {
+
+ }
+
+ public void clearBody() throws JMSException
+ {
+
+ }
+}
diff --git a/qpid/java/distribution/src/main/assembly/src.xml b/qpid/java/distribution/src/main/assembly/src.xml
index 49e1f8bfb2..8aa6183b4d 100644
--- a/qpid/java/distribution/src/main/assembly/src.xml
+++ b/qpid/java/distribution/src/main/assembly/src.xml
@@ -41,7 +41,7 @@
</fileSet>
<fileSet>
<directory>..</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
+ <outputDirectory>qpid-${qpid.version}-src/java</outputDirectory>
<includes>
<include>**/*</include>
</includes>
@@ -71,5 +71,24 @@
<exclude>**/eclipse-plugin/src/main/resources/**</exclude>
</excludes>
</fileSet>
+ <fileSet>
+ <directory>../../gentools</directory>
+ <outputDirectory>qpid-${qpid.version}-src/gentools</outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ <excludes>
+ <exclude>**/build</exclude>
+ <exclude>**/build/**/*</exclude>
+ <exclude>**/*.class</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>../../specs</directory>
+ <outputDirectory>qpid-${qpid.version}-src/specs</outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
</fileSets>
</assembly>
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
index 2fadee6f54..b3efc107da 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
@@ -28,8 +28,8 @@ package org.apache.qpid.management.ui;
public class Constants
{
public final static String APPLICATION_NAME = "Qpid Management Console";
- public final static String ITEM_VALUE = "value";
- public final static String ITEM_TYPE = "type";
+ public final static String VALUE = "value";
+ public final static String TYPE = "type";
public final static String SERVER = "server";
public final static String DOMAIN = "domain";
public final static String NODE_TYPE_MBEANTYPE = "mbeantype";
@@ -42,18 +42,25 @@ public class Constants
public final static String RESULT = "Result";
public final static String VIRTUAL_HOST = "VirtualHost";
- public final static String ATTRIBUTE_QUEUE_DEPTH = "QueueDepth";
+ // Attributes and operations are used to customize the GUI for Qpid. If these are changes in the
+ // Qpid server, then these should be updated accordingly
+ public final static String ATTRIBUTE_QUEUE_OWNER = "owner";
+ public final static String ATTRIBUTE_QUEUE_DEPTH = "QueueDepth";
+ public final static String ATTRIBUTE_QUEUE_CONSUMERCOUNT = "ActiveConsumerCount";
+ public final static String OPERATION_CREATE_QUEUE = "createNewQueue";
+ public final static String OPERATION_CREATE_BINDING = "createNewBinding";
public final static String ALL = "All";
public final static String NAVIGATION_ROOT = "Qpid Connections";
public final static String DESCRIPTION = " Description";
- public final static String BROKER_MANAGER = "Broker_Manager";
public final static String QUEUE = "Queue";
public final static String EXCHANGE = "Exchange";
public final static String EXCHANGE_TYPE = "ExchangeType";
public final static String[] EXCHANGE_TYPE_VALUES = {"direct", "topic", "headers"};
+ public final static String[] BOOLEAN_TYPE_VALUES = {"false", "true"};
+ public final static String[] ATTRIBUTE_TABLE_TITLES = {"Attribute Name", "Value"};
public final static String CONNECTION ="Connection";
public final static String ACTION_ADDSERVER = "New Connection";
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
index e87d77159d..4cdfffa459 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
@@ -32,7 +32,7 @@ public abstract class ManagedBean extends ManagedObject
private String _uniqueName = "";
private String _domain = "";
private String _type = "";
- private String _virtualHostName = "Default";
+ private String _virtualHostName = null;
private ManagedServer _server = null;
private HashMap _properties = null;
@@ -48,7 +48,9 @@ public abstract class ManagedBean extends ManagedObject
public void setProperties(HashMap properties)
{
this._properties = properties;
- setVirtualHostName(getProperty(Constants.VIRTUAL_HOST));
+ setName(getProperty("name"));
+ setType(getProperty("type"));
+ _virtualHostName = getProperty(Constants.VIRTUAL_HOST);
}
public String getDomain()
{
@@ -89,12 +91,30 @@ public abstract class ManagedBean extends ManagedObject
return _virtualHostName;
}
- public void setVirtualHostName(String virtualHost)
+ /**
+ * Returns mbean instance name. MBeans which have only one instance, the type attribute will be returned
+ * @return
+ */
+ public String getInstanceName()
{
- if (virtualHost != null)
- {
- this._virtualHostName = virtualHost;
- }
+ if (getName() != null)
+ return getName();
+ else
+ return getType();
}
+ public boolean isQueue()
+ {
+ return _type.endsWith(Constants.QUEUE);
+ }
+
+ public boolean isConnection()
+ {
+ return _type.endsWith(Constants.CONNECTION);
+ }
+
+ public boolean isExchange()
+ {
+ return _type.endsWith(Constants.EXCHANGE);
+ }
}
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
index 4f6bbd8bc0..b498454fc1 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
@@ -34,14 +34,11 @@ import org.apache.qpid.management.ui.model.OperationDataModel;
public abstract class ServerRegistry
{
private ManagedServer _managedServer = null;
- // list of all Connection mbeans
- //private List<ManagedBean> _connections = new ArrayList<ManagedBean>();
+ // map of all Connection mbeans
private ConcurrentMap<String,List<ManagedBean>> _connections = new ConcurrentHashMap<String,List<ManagedBean>>();
- // list of all exchange mbeans
- //private List<ManagedBean> _exchanges = new ArrayList<ManagedBean>();
+ // map of all exchange mbeans
private ConcurrentMap<String,List<ManagedBean>> _exchanges = new ConcurrentHashMap<String,List<ManagedBean>>();
- // list of all queue mbenas
- //private List<ManagedBean> _queues = new ArrayList<ManagedBean>();
+ // map of all queue mbenas
private ConcurrentMap<String,List<ManagedBean>> _queues = new ConcurrentHashMap<String,List<ManagedBean>>();
public ServerRegistry()
@@ -68,31 +65,26 @@ public abstract class ServerRegistry
{
String vHost = mbean.getVirtualHostName();
_connections.putIfAbsent(vHost, new ArrayList<ManagedBean>());
- List<ManagedBean> beans = _connections.get(vHost);
- beans.add(mbean);
+ _connections.get(vHost).add(mbean);
}
protected void addExchangeMBean(ManagedBean mbean)
{
String vHost = mbean.getVirtualHostName();
_exchanges.putIfAbsent(vHost, new ArrayList<ManagedBean>());
- List<ManagedBean> beans = _exchanges.get(vHost);
- beans.add(mbean);
+ _exchanges.get(vHost).add(mbean);
}
protected void addQueueMBean(ManagedBean mbean)
{
String vHost = mbean.getVirtualHostName();
_queues.putIfAbsent(vHost, new ArrayList<ManagedBean>());
- List<ManagedBean> beans = _queues.get(vHost);
- beans.add(mbean);
+ _queues.get(vHost).add(mbean);
}
protected void removeConnectionMBean(ManagedBean mbean)
{
- String vHost = mbean.getVirtualHostName();
- List<ManagedBean> beans = _connections.get(vHost);
- beans.remove(mbean);
+ _connections.get(mbean.getVirtualHostName()).remove(mbean);
}
protected void removeExchangeMBean(ManagedBean mbean)
@@ -126,10 +118,7 @@ public abstract class ServerRegistry
public abstract void removeManagedObject(ManagedBean mbean);
- public List<ManagedBean> getObjectsToBeRemoved()
- {
- return null;
- }
+ public abstract List<ManagedBean> getObjectsToBeRemoved();
public abstract ManagedAttributeModel getAttributeModel(ManagedBean mbean);
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
index dd665eabb3..3561e16098 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java
@@ -36,10 +36,8 @@ public class JMXManagedObject extends ManagedBean
{
super();
this._objName = objName;
- setName(_objName.getKeyProperty("name"));
- setType(_objName.getKeyProperty("type"));
setUniqueName(_objName.toString());
- setDomain(_objName.getDomain());
+ setDomain(_objName.getDomain());
super.setProperties(new HashMap(_objName.getKeyPropertyList()));
}
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
index 72c4fa3d9d..882fdfb038 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
@@ -131,15 +131,15 @@ public class JMXServerRegistry extends ServerRegistry
public void addManagedObject(ManagedBean mbean)
{
- if (mbean.getType().endsWith(Constants.QUEUE) && !mbean.getName().startsWith("tmp_"))
+ if (mbean.isQueue() && !mbean.getName().startsWith("tmp_"))
{
addQueueMBean(mbean);
}
- else if (mbean.getType().endsWith(Constants.EXCHANGE))
+ else if (mbean.isExchange())
{
addExchangeMBean(mbean);
}
- else if (mbean.getType().endsWith(Constants.CONNECTION))
+ else if (mbean.isConnection())
{
addConnectionMBean(mbean);
}
@@ -149,12 +149,18 @@ public class JMXServerRegistry extends ServerRegistry
public void removeManagedObject(ManagedBean mbean)
{
- if (mbean.getType().endsWith(Constants.QUEUE))
+ if (mbean.isQueue())
+ {
removeQueueMBean(mbean);
- else if (mbean.getType().endsWith(Constants.EXCHANGE))
+ }
+ else if (mbean.isExchange())
+ {
removeExchangeMBean(mbean);
- else if (mbean.getType().endsWith(Constants.CONNECTION))
+ }
+ else if (mbean.isConnection())
+ {
removeConnectionMBean(mbean);
+ }
_mbeansMap.remove(mbean.getUniqueName());
}
@@ -319,6 +325,12 @@ public class JMXServerRegistry extends ServerRegistry
}
}
+ /**
+ * When the mbean registration request is received from the mbean server, then the client listener
+ * can use this method. It will add the mbean to a list, which will be used to add the mbean to
+ * the registry and gui
+ * @param objName
+ */
public void registerManagedObject(ObjectName objName)
{
JMXManagedObject managedObject = new JMXManagedObject(objName);
@@ -327,10 +339,20 @@ public class JMXServerRegistry extends ServerRegistry
addManagedObject(managedObject);
}
+ /**
+ * When mbean unregistration notification is received from the mbean server, then client listener
+ * can invoke this method. It will add the mbean to the list of mbeans to be removed from registry
+ * @param objName
+ */
public void unregisterManagedObject(ObjectName objName)
{
ManagedBean mbean = _mbeansMap.get(objName.toString());
- _mbeansToBeRemoved.add(mbean);
+ // Check if mbean was not available in the map. It can happen if mbean unregistration
+ // notification is received and the mbean is not added in the map.
+ if (mbean != null)
+ {
+ _mbeansToBeRemoved.add(mbean);
+ }
}
public List<ManagedBean> getObjectsToBeRemoved()
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
index 8334beeeb9..1a1de11e30 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
@@ -144,39 +144,44 @@ public class MBeanUtility
if (mbean == null)
{
ViewUtility.popupErrorMessage("Error", "Managed Object is null \n" + ex.toString());
+ ex.printStackTrace();
}
else if (ex instanceof IOException)
{
- ViewUtility.popupErrorMessage(mbean.getName(), "IO Error occured \n" + ex.toString());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), "IO Error occured \n" + ex.toString());
+ ex.printStackTrace();
}
else if (ex instanceof ReflectionException)
{
- ViewUtility.popupErrorMessage(mbean.getName(), "Server has thrown error \n" + ex.toString());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Server has thrown error \n" + ex.toString());
+ ex.printStackTrace();
}
else if (ex instanceof InstanceNotFoundException)
{
- ViewUtility.popupErrorMessage(mbean.getName(), "Managed Object Not Found \n" + ex.toString());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Managed Object Not Found \n" + ex.toString());
+ ex.printStackTrace();
}
else if (ex instanceof MBeanException)
{
String cause = ((MBeanException)ex).getTargetException().toString();
if (cause == null)
cause = ex.toString();
- ViewUtility.popupInfoMessage(mbean.getName(), cause);
+ ViewUtility.popupInfoMessage(mbean.getInstanceName(), cause);
}
else if (ex instanceof JMException)
{
- ViewUtility.popupErrorMessage(mbean.getName(), "Management Exception occured \n" + ex.toString());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Management Exception occured \n" + ex.toString());
}
else if (ex instanceof ManagementConsoleException)
{
- ViewUtility.popupErrorMessage(mbean.getName(), ex.getMessage());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage());
}
else
{
- ViewUtility.popupErrorMessage(mbean.getName(), ex.toString());
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.toString());
+ ex.printStackTrace();
}
- ex.printStackTrace();
+
}
/**
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java
index 4ca47c88ea..9d1d44559e 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java
@@ -20,60 +20,81 @@
*/
package org.apache.qpid.management.ui.model;
+/**
+ * Class representing an mbean operation parameter
+ * @author Bhupendra Bhardwaj
+ */
public class ParameterData
{
- private String name;
- private String description;
- private String type;
- private Object value;
+ private String _name;
+ private String _description;
+ private String _type;
+ private Object _value;
- ParameterData(String value)
+ ParameterData(String name)
{
- this.name = value;
+ this._name = name;
}
public String getDescription()
{
- return description;
+ return _description;
}
public void setDescription(String description)
{
- this.description = description;
+ this._description = description;
}
public String getName()
{
- return name;
+ return _name;
}
public String getType()
{
- return type;
+ return _type;
}
public void setType(String type)
{
- this.type = type;
+ this._type = type;
}
public Object getValue()
{
- return value;
+ return _value;
}
public void setValueFromString(String strValue)
{
- if ("int".equals(type))
- value = Integer.parseInt(strValue);
- else if ("boolean".equals(type))
- value = Boolean.valueOf(strValue);
- else if ("long".equals(type))
- value = Long.parseLong(strValue);
+ if ("int".equals(_type))
+ _value = Integer.parseInt(strValue);
+ else if (isBoolean())
+ _value = Boolean.valueOf(strValue);
+ else if ("long".equals(_type))
+ _value = Long.parseLong(strValue);
else
- value = strValue;
+ _value = strValue;
}
public void setValue(Object value)
{
- this.value = value;
+ this._value = value;
+ }
+
+ public boolean isBoolean()
+ {
+ return (_type.equals("boolean") || _type.equals("java.lang.Boolean"));
+ }
+
+ public void setDefaultValue()
+ {
+ if (isBoolean())
+ {
+ _value = Boolean.valueOf("false");
+ }
+ else
+ {
+ _value = null;
+ }
}
}
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
index 2b8e5cee1a..feb853ab00 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
@@ -90,7 +90,6 @@ public class AttributesTabControl extends TabControl
private Table _table = null;
private TableViewer _tableViewer = null;
private static final int[] tableWidths = new int[] {300, 300};
- private final String[] _tableTitles = {"Attribute Name", "Value"};
private Composite _tableComposite = null;
private Composite _buttonsComposite = null;
@@ -159,10 +158,10 @@ public class AttributesTabControl extends TabControl
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
_table.setLayoutData(gridData);
- for (int i = 0; i < _tableTitles.length; ++i)
+ for (int i = 0; i < Constants.ATTRIBUTE_TABLE_TITLES.length; ++i)
{
final TableColumn column = new TableColumn(_table, SWT.NONE);
- column.setText(_tableTitles[i]);
+ column.setText(Constants.ATTRIBUTE_TABLE_TITLES[i]);
column.setWidth(tableWidths[i]);
column.setResizable(false);
}
@@ -178,7 +177,7 @@ public class AttributesTabControl extends TabControl
{
_tableViewer = new TableViewer(_table);
_tableViewer.setUseHashlookup(true);
- _tableViewer.setColumnProperties(_tableTitles);
+ _tableViewer.setColumnProperties(Constants.ATTRIBUTE_TABLE_TITLES);
_tableViewer.setContentProvider(new ContentProviderImpl());
_tableViewer.setLabelProvider(new LabelProviderImpl());
_tableViewer.setSorter(new ViewerSorterImpl());
@@ -485,7 +484,7 @@ public class AttributesTabControl extends TabControl
// Name
Label label = new Label(parent, SWT.NONE);
- label.setText(_tableTitles[0]);
+ label.setText(Constants.ATTRIBUTE_TABLE_TITLES[0]);
GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false);
label.setLayoutData(layoutData);
Text value = new Text(parent, SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY);
@@ -503,7 +502,7 @@ public class AttributesTabControl extends TabControl
// value
label = new Label(parent, SWT.NONE);
- label.setText(_tableTitles[1]);
+ label.setText(Constants.ATTRIBUTE_TABLE_TITLES[1]);
label.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false));
if (!attribute.isReadable())
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java
index 3e76e3e1c0..37c0fba2ef 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java
@@ -20,6 +20,7 @@ import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.TabFolder;
@@ -41,7 +42,7 @@ public class MBeanTypeTabControl
private TabFolder _tabFolder = null;
private Composite _composite = null;
private Composite _listComposite = null;
- private Composite _buttonsComposite = null;
+ private Composite _sortingComposite = null;
private Label _labelName = null;
private Label _labelDesc = null;
private Label _labelList = null;
@@ -50,6 +51,8 @@ public class MBeanTypeTabControl
private Button _refreshButton = null;
private Button _addButton = null;
private Button _sortBySizeButton = null;
+ private Button _sortByConsumercountButton = null;
+ private Button _sortByNameButton = null;
private String _type = null;
@@ -57,10 +60,12 @@ public class MBeanTypeTabControl
// is to be added to the navigation view.
private HashMap<String, ManagedBean> _objectsMap = new HashMap<String, ManagedBean>();
// Map required for sorting queues based on attribute values
- private Map<AttributeData, ManagedBean> _queueMap = new LinkedHashMap<AttributeData, ManagedBean>();
+ private Map<AttributeData, ManagedBean> _queueDepthMap = new LinkedHashMap<AttributeData, ManagedBean>();
+ // Map used for sorting Queues based on consumer count
+ private Map<AttributeData, ManagedBean> _queueConsumerCountMap = new LinkedHashMap<AttributeData, ManagedBean>();
private Sorter _sorterByName = new Sorter();
- private ComparatorImpl _sorterByQueueDepth = new ComparatorImpl();
+ private ComparatorImpl _sorterByAttribute = new ComparatorImpl();
public MBeanTypeTabControl(TabFolder tabFolder)
{
@@ -90,12 +95,7 @@ public class MBeanTypeTabControl
String[] selectedItems = _list.getSelection();
for (int i = 0; i < selectedItems.length; i++)
{
- String name = selectedItems[i];;
- if (Constants.QUEUE.equals(_type))
- {
- int endIndex = name.lastIndexOf("(");
- name = name.substring(0, endIndex -1);
- }
+ String name = selectedItems[i];
// pass the ManagedBean to the navigation view to be added
ManagedBean mbean = _objectsMap.get(name);
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
@@ -126,12 +126,42 @@ public class MBeanTypeTabControl
}
});
+ _sortByNameButton.addSelectionListener(new SelectionAdapter(){
+ public void widgetSelected(SelectionEvent e)
+ {
+ try
+ {
+ java.util.List<String> list = new ArrayList<String>(_objectsMap.keySet());
+ Collections.sort(list);
+ _list.setItems(list.toArray(new String[0]));
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(ex);
+ }
+ }
+ });
+
_sortBySizeButton.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e)
{
try
{
- sortQueueByQueueDepth();
+ sortQueuesByQueueDepth();
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(ex);
+ }
+ }
+ });
+
+ _sortByConsumercountButton.addSelectionListener(new SelectionAdapter(){
+ public void widgetSelected(SelectionEvent e)
+ {
+ try
+ {
+ sortQueuesByConsumerCount();
}
catch (Exception ex)
{
@@ -143,6 +173,18 @@ public class MBeanTypeTabControl
private void createWidgets()
{
+ /* _form
+ * |
+ * _composite
+ * |
+ * ---------------------------------------------------------------------
+ * | | |
+ * _labelName, _labelDesc, _listComposite _sortingComposite
+ * _addButton, _refreshButton | |
+ * _labelList, _list sortingGroup
+ * |
+ * sorting radio buttons
+ */
_form.getBody().setLayout(new GridLayout());
_composite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
_composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
@@ -166,7 +208,7 @@ public class MBeanTypeTabControl
_refreshButton = _toolkit.createButton(_composite, Constants.BUTTON_REFRESH, SWT.PUSH);
gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
- gridData.widthHint = 80;
+ gridData.widthHint = 120;
_refreshButton.setLayoutData(gridData);
// Composite to contain the item list
@@ -188,15 +230,39 @@ public class MBeanTypeTabControl
// Composite to contain buttons like - Sort by size
- _buttonsComposite = _toolkit.createComposite(_composite);
+ _sortingComposite = _toolkit.createComposite(_composite);
gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
- _buttonsComposite.setLayoutData(gridData);
- _buttonsComposite.setLayout(new GridLayout());
+ _sortingComposite.setLayoutData(gridData);
+ _sortingComposite.setLayout(new GridLayout());
- _sortBySizeButton = _toolkit.createButton(_buttonsComposite, "Sort by Queue Depth", SWT.PUSH);
- gridData = new GridData(SWT.CENTER, SWT.CENTER, true, false);
- _sortBySizeButton.setLayoutData(gridData);
+ Group sortingGroup = new Group(_sortingComposite, SWT.SHADOW_NONE);
+ sortingGroup.setBackground(_sortingComposite.getBackground());
+ sortingGroup.setText(" Sort List By ");
+ sortingGroup.setFont(ApplicationRegistry.getFont(Constants.FONT_BOLD));
+ gridData = new GridData(SWT.CENTER, SWT.TOP, true, true);
+ sortingGroup.setLayoutData(gridData);
+ sortingGroup.setLayout(new GridLayout());
+ _sortByNameButton = _toolkit.createButton(sortingGroup, "Queue Name", SWT.RADIO);
+ gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
+ _sortByNameButton.setLayoutData(gridData);
+
+ _sortBySizeButton = _toolkit.createButton(sortingGroup, "Queue Depth", SWT.RADIO);
+ gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
+ _sortBySizeButton.setLayoutData(gridData);
+
+ _sortByConsumercountButton = _toolkit.createButton(sortingGroup, "Consumer Count", SWT.RADIO);
+ gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
+ _sortByConsumercountButton.setLayoutData(gridData);
+
+ selectDefaultSortingButton();
+ }
+
+ private void selectDefaultSortingButton()
+ {
+ _sortByNameButton.setSelection(true);
+ _sortBySizeButton.setSelection(false);
+ _sortByConsumercountButton.setSelection(false);
}
public void refresh(String typeName) throws Exception
@@ -225,7 +291,9 @@ public class MBeanTypeTabControl
{
// map should be cleared before populating it with new values
_objectsMap.clear();
- _queueMap.clear();
+ _queueDepthMap.clear();
+ _queueConsumerCountMap.clear();
+
ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
String[] items = null;
java.util.List<ManagedBean> list = null;
@@ -235,27 +303,27 @@ public class MBeanTypeTabControl
{
list = serverRegistry.getQueues(MBeanView.getVirtualHost());
items = getQueueItems(list);
- _sortBySizeButton.setVisible(true);
+ selectDefaultSortingButton();
+ _sortingComposite.setVisible(true);
}
else if (_type.equals(Constants.EXCHANGE))
{
list = serverRegistry.getExchanges(MBeanView.getVirtualHost());
items = getItems(list);
- _sortBySizeButton.setVisible(false);
+ _sortingComposite.setVisible(false);
}
else if (_type.equals(Constants.CONNECTION))
{
list = serverRegistry.getConnections(MBeanView.getVirtualHost());
items = getItems(list);
- _sortBySizeButton.setVisible(false);
+ _sortingComposite.setVisible(false);
}
else
{
throw new Exception("Unknown mbean type " + _type);
}
- _list.setItems(items);
-
+ _list.setItems(items);
}
// sets the map with appropriate mbean and name
@@ -290,30 +358,48 @@ public class MBeanTypeTabControl
AttributeData data = MBeanUtility.getAttributeData(mbean, Constants.ATTRIBUTE_QUEUE_DEPTH);
String value = data.getValue().toString();
items[i] = mbean.getName() + " (" + value + " KB)";
- _objectsMap.put(mbean.getName(), mbean);
- _queueMap.put(data, mbean);
+ _objectsMap.put(items[i], mbean);
+ _queueDepthMap.put(data, mbean);
+ data = MBeanUtility.getAttributeData(mbean, Constants.ATTRIBUTE_QUEUE_CONSUMERCOUNT);
+ _queueConsumerCountMap.put(data, mbean);
i++;
}
return items;
}
- private void sortQueueByQueueDepth() throws Exception
+ private void sortQueuesByQueueDepth()
{
// Queues are already in the alphabetically sorted order in _queueMap, now sort for queueDepth
- java.util.List<AttributeData> list = new ArrayList<AttributeData>(_queueMap.keySet());
- Collections.sort(list, _sorterByQueueDepth);
+ java.util.List<AttributeData> list = new ArrayList<AttributeData>(_queueDepthMap.keySet());
+ Collections.sort(list, _sorterByAttribute);
String[] items = new String[list.size()];
int i = 0;
for (AttributeData data : list)
{
- ManagedBean mbean = _queueMap.get(data);
+ ManagedBean mbean = _queueDepthMap.get(data);
String value = data.getValue().toString();
items[i++] = mbean.getName() + " (" + value + " KB)";
}
_list.setItems(items);
}
+ private void sortQueuesByConsumerCount()
+ {
+ java.util.List<AttributeData> list = new ArrayList<AttributeData>(_queueConsumerCountMap.keySet());
+ Collections.sort(list, _sorterByAttribute);
+
+ String[] items = new String[list.size()];
+ int i = 0;
+ for (AttributeData data : list)
+ {
+ ManagedBean mbean = _queueConsumerCountMap.get(data);
+ String value = data.getValue().toString();
+ items[i++] = mbean.getName() + " (" + value + " )";
+ }
+ _list.setItems(items);
+ }
+
private class ComparatorImpl implements java.util.Comparator<AttributeData>
{
public int compare(AttributeData data1, AttributeData data2)
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 8e262075a9..af429553dc 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
@@ -33,11 +33,9 @@ import java.util.List;
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.Constants;
import org.apache.qpid.management.ui.ManagedBean;
-import org.apache.qpid.management.ui.ManagedObject;
import org.apache.qpid.management.ui.ManagedServer;
import org.apache.qpid.management.ui.ServerRegistry;
import org.apache.qpid.management.ui.exceptions.InfoRequiredException;
-import org.apache.qpid.management.ui.exceptions.ManagementConsoleException;
import org.apache.qpid.management.ui.jmx.JMXServerRegistry;
import org.apache.qpid.management.ui.jmx.MBeanUtility;
import org.eclipse.jface.viewers.DoubleClickEvent;
@@ -243,7 +241,7 @@ public class NavigationView extends ViewPart
String domain = server.getDomain();
try
{
- if (!domain.equals("All"))
+ if (!domain.equals(Constants.ALL))
{
TreeObject domainNode = new TreeObject(domain, Constants.DOMAIN);
domainNode.setParent(serverNode);
@@ -281,17 +279,6 @@ public class NavigationView extends ViewPart
private void populateDomain(TreeObject domain) throws IOException, Exception
{
ManagedServer server = (ManagedServer)domain.getParent().getManagedObject();
- /*
- // Add these three types - Connection, Exchange, Queue
- // By adding these, these will always be available, even if there are no mbeans under thse types
- // This is required because, the mbeans will be added from mbeanview, by selecting from the list
- TreeObject typeChild = new TreeObject(Constants.CONNECTION, Constants.TYPE);
- typeChild.setParent(domain);
- typeChild = new TreeObject(Constants.EXCHANGE, Constants.TYPE);
- typeChild.setParent(domain);
- typeChild = new TreeObject(Constants.QUEUE, Constants.TYPE);
- typeChild.setParent(domain);
- */
// Now populate the mbenas under those types
List<ManagedBean> mbeans = MBeanUtility.getManagedObjectsForDomain(server, domain.getName());
@@ -302,17 +289,20 @@ public class NavigationView extends ViewPart
serverRegistry.addManagedObject(mbean);
// Add all mbeans other than Connections, Exchanges and Queues. Because these will be added
- // manually by selecting from MBeanView
-
- if (!(mbean.getType().endsWith(Constants.CONNECTION) ||
- mbean.getType().endsWith(Constants.EXCHANGE) ||
- mbean.getType().endsWith(Constants.QUEUE)))
+ // manually by selecting from MBeanView
+ if (!(mbean.isConnection() || mbean.isExchange() || mbean.isQueue()) )
{
addManagedBean(domain, mbean);
}
}
}
+ /**
+ * Add these three types - Connection, Exchange, Queue
+ * By adding these, these will always be available, even if there are no mbeans under thse types
+ * This is required because, the mbeans will be added from mbeanview, by selecting from the list
+ * @param parent Node
+ */
private void addDefaultNodes(TreeObject parent)
{
TreeObject typeChild = new TreeObject(Constants.CONNECTION, Constants.NODE_TYPE_MBEANTYPE);
@@ -360,6 +350,7 @@ public class NavigationView extends ViewPart
* Adds the given MBean to the given domain node. Creates Notification node for the MBean.
* @param domain
* @param mbean mbean
+ * @throws Exception
*/
private void addManagedBean(TreeObject domain, ManagedBean mbean) throws Exception
{
@@ -797,6 +788,11 @@ public class NavigationView extends ViewPart
}// end of run method.
}// end of Worker class
+ /**
+ * Adds the mbean to the navigation tree
+ * @param mbean
+ * @throws Exception
+ */
public void addManagedBean(ManagedBean mbean) throws Exception
{
TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
@@ -833,7 +829,6 @@ public class NavigationView extends ViewPart
{
for (ManagedBean mbean : removalList)
{
- System.out.println("removing " + mbean.getName() + " " + mbean.getType());
TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
List<TreeObject> domains = treeServerObject.getChildren();
TreeObject domain = null;
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
index 8568ee33bf..fc42561c75 100644
--- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
@@ -66,9 +66,9 @@ import org.eclipse.ui.forms.widgets.FormToolkit;
*/
public class OperationTabControl extends TabControl
{
- private int heightForAParameter = 30;
- private int labelNumerator = 30;
- private int valueNumerator = labelNumerator + 20;
+ private static final int heightForAParameter = 30;
+ private static final int labelWidth = 30;
+ private static final int valueWidth = labelWidth + 25;
private FormToolkit _toolkit;
private Form _form;
@@ -218,9 +218,9 @@ public class OperationTabControl extends TabControl
}
// Customised parameter widgets
- if (_mbean.getType().endsWith(Constants.EXCHANGE) &&
+ if (_mbean.isExchange() &&
Constants.EXCHANGE_TYPE_VALUES[2].equals(_mbean.getProperty(Constants.EXCHANGE_TYPE)) &&
- _opData.getName().equalsIgnoreCase("createNewBinding"))
+ _opData.getName().equalsIgnoreCase(Constants.OPERATION_CREATE_BINDING))
{
customCreateNewBinding();
return;
@@ -229,80 +229,79 @@ public class OperationTabControl extends TabControl
_paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
_paramsComposite.setLayout(new FormLayout());
+ int parameterPositionOffset = 0;
for (ParameterData param : params)
{
boolean valueInCombo = false;
Label label = _toolkit.createLabel(_paramsComposite, ViewUtility.getDisplayText(param.getName()));
FormData formData = new FormData();
- formData.top = new FormAttachment(0, params.indexOf(param) * heightForAParameter + 2);
- formData.right = new FormAttachment(labelNumerator);
+ if (params.indexOf(param) == 0)
+ {
+ parameterPositionOffset = 0;
+ }
+ else
+ {
+ parameterPositionOffset += heightForAParameter;
+ }
+ formData.top = new FormAttachment(0, parameterPositionOffset + 2);
+ formData.right = new FormAttachment(labelWidth);
label.setLayoutData(formData);
label.setToolTipText(param.getDescription());
formData = new FormData();
- formData.top = new FormAttachment(0, params.indexOf(param) * heightForAParameter);
+ formData.top = new FormAttachment(0, parameterPositionOffset);
formData.left = new FormAttachment(label, 5);
- formData.right = new FormAttachment(valueNumerator);
+ formData.right = new FormAttachment(valueWidth);
+ String[] items = null;
if (param.getName().equals(Constants.QUEUE))
{
- Combo combo = new Combo(_paramsComposite, SWT.READ_ONLY | SWT.DROP_DOWN);
- String[] items = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_virtualHostName);
- combo.setItems(items);
- combo.add("Select Queue", 0);
- combo.select(0);
- combo.setLayoutData(formData);
- combo.setData(param);
- combo.addSelectionListener(parameterSelectionListener);
- valueInCombo = true;
+ items = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_virtualHostName);
}
else if (param.getName().equals(Constants.EXCHANGE))
{
- Combo combo = new Combo(_paramsComposite, SWT.READ_ONLY | SWT.DROP_DOWN);
- String[] items = ApplicationRegistry.getServerRegistry(_mbean).getExchangeNames(_virtualHostName);
- combo.setItems(items);
- combo.add("Select Exchange", 0);
- combo.select(0);
- combo.setLayoutData(formData);
- combo.setData(param);
- combo.addSelectionListener(parameterSelectionListener);
- valueInCombo = true;
+ items = ApplicationRegistry.getServerRegistry(_mbean).getExchangeNames(_virtualHostName);
}
else if (param.getName().equals(Constants.EXCHANGE_TYPE))
{
- Combo combo = new Combo(_paramsComposite, SWT.READ_ONLY | SWT.DROP_DOWN);
- combo.setItems(Constants.EXCHANGE_TYPE_VALUES);
- combo.add("Select Exchange Type", 0);
- combo.select(0);
- combo.setLayoutData(formData);
- combo.setData(param);
- combo.addSelectionListener(parameterSelectionListener);
- valueInCombo = true;
+ items = Constants.EXCHANGE_TYPE_VALUES;
+ }
+
+ if (items != null)
+ {
+ org.eclipse.swt.widgets.List _list = new org.eclipse.swt.widgets.List(_paramsComposite, SWT.BORDER | SWT.V_SCROLL);
+ int listSize = _form.getClientArea().height / 3;
+ int itemsHeight = items.length * (_list.getItemHeight() + 2);
+ listSize = (listSize > itemsHeight) ? itemsHeight : listSize;
+ parameterPositionOffset = parameterPositionOffset + listSize;
+ formData.bottom = new FormAttachment(0, parameterPositionOffset);
+ _list.setLayoutData(formData);
+ _list.setData(param);
+ _list.setItems(items);
+ _list.addSelectionListener(parameterSelectionListener);
+ valueInCombo = true;
}
- else if (param.getType().equals("boolean") || param.getType().equals("java.lang.Boolean"))
+ else if (param.isBoolean())
{
- Combo combo = new Combo(_paramsComposite, SWT.READ_ONLY | SWT.DROP_DOWN);
- combo.setItems(new String[] {"false", "true"});
- combo.select(0);
- param.setValueFromString(combo.getItem(0));
- combo.setLayoutData(formData);
- combo.setData(param);
- combo.addSelectionListener(bolleanSelectionListener);
+ Button booleanButton = _toolkit.createButton(_paramsComposite, "", SWT.CHECK);
+ booleanButton.setLayoutData(formData);
+ booleanButton.setData(param);
+ booleanButton.addSelectionListener(bolleanSelectionListener);
valueInCombo = true;
}
else
{
Text text = _toolkit.createText(_paramsComposite, "", SWT.NONE);
formData = new FormData();
- formData.top = new FormAttachment(0, params.indexOf(param) * heightForAParameter);
+ formData.top = new FormAttachment(0, parameterPositionOffset);
formData.left = new FormAttachment(label, 5);
- formData.right = new FormAttachment(valueNumerator);
+ formData.right = new FormAttachment(valueWidth);
text.setLayoutData(formData);
text.addKeyListener(keyListener);
text.addVerifyListener(verifyListener);
text.setData(param);
}
- // parameter type (int, String etc)
+ // display the parameter data type next to the text field
if (valueInCombo)
label = _toolkit.createLabel(_paramsComposite, "");
else
@@ -314,8 +313,8 @@ public class OperationTabControl extends TabControl
label = _toolkit.createLabel(_paramsComposite, "(" + str + ")");
}
formData = new FormData();
- formData.top = new FormAttachment(0, params.indexOf(param) * heightForAParameter);
- formData.left = new FormAttachment(valueNumerator, 5);
+ formData.top = new FormAttachment(0, parameterPositionOffset);
+ formData.left = new FormAttachment(valueWidth, 5);
label.setLayoutData(formData);
}
}
@@ -350,14 +349,14 @@ public class OperationTabControl extends TabControl
Label label = _toolkit.createLabel(composite, ViewUtility.getDisplayText(param.getName()));
FormData formData = new FormData();
formData.top = new FormAttachment(0, 2);
- formData.right = new FormAttachment(labelNumerator);
+ formData.right = new FormAttachment(labelWidth);
label.setLayoutData(formData);
label.setToolTipText(param.getDescription());
formData = new FormData();
formData.top = new FormAttachment(0);
formData.left = new FormAttachment(label, 5);
- formData.right = new FormAttachment(valueNumerator);
+ formData.right = new FormAttachment(valueWidth);
Combo combo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN);
String[] items = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_virtualHostName);
@@ -492,7 +491,7 @@ public class OperationTabControl extends TabControl
{
for (ParameterData param : params)
{
- param.setValue(null);
+ param.setDefaultValue();
}
}
}
@@ -535,6 +534,14 @@ public class OperationTabControl extends TabControl
{
if (param.getValue() == null || param.getValue().toString().length() == 0)
{
+ // Customized check, because for this parameter null is allowed
+ if (param.getName().equals(Constants.ATTRIBUTE_QUEUE_OWNER) &&
+ _opData.getName().equals(Constants.OPERATION_CREATE_QUEUE))
+ {
+ continue;
+ }
+ // End of custom code
+
ViewUtility.popupInfoMessage(_form.getText(),
"Please select the " + ViewUtility.getDisplayText(param.getName()));
@@ -619,16 +626,25 @@ public class OperationTabControl extends TabControl
{
public void widgetSelected(SelectionEvent e)
{
- Combo combo = (Combo)e.widget;
- ParameterData parameter = (ParameterData)combo.getData();
- if (combo.getSelectionIndex() > 0)
+ ParameterData parameter = (ParameterData)e.widget.getData();
+ parameter.setValue(null);
+ if (e.widget instanceof Combo)
{
- String item = combo.getItem(combo.getSelectionIndex());
- parameter.setValueFromString(item);
+ Combo combo = (Combo)e.widget;
+ if (combo.getSelectionIndex() > 0)
+ {
+ String item = combo.getItem(combo.getSelectionIndex());
+ parameter.setValueFromString(item);
+ }
}
- else
+ else if (e.widget instanceof org.eclipse.swt.widgets.List)
{
- parameter.setValue(null);
+ org.eclipse.swt.widgets.List list = (org.eclipse.swt.widgets.List)e.widget;
+ String[] selectedItems = list.getSelection();
+ if (selectedItems.length > 0)
+ {
+ parameter.setValueFromString(selectedItems[0]);
+ }
}
}
}
@@ -640,10 +656,18 @@ public class OperationTabControl extends TabControl
{
public void widgetSelected(SelectionEvent e)
{
- Combo combo = (Combo)e.widget;
- ParameterData parameter = (ParameterData)combo.getData();
- String item = combo.getItem(combo.getSelectionIndex());
- parameter.setValueFromString(item);
+ ParameterData parameter = (ParameterData)(e.widget.getData());
+ if (e.widget instanceof Button)
+ {
+ Button button = (Button)e.widget;
+ parameter.setValue(button.getSelection());
+ }
+ else if (e.widget instanceof Combo)
+ {
+ Combo combo = (Combo)e.widget;
+ String item = combo.getItem(combo.getSelectionIndex());
+ parameter.setValueFromString(item);
+ }
}
}
diff --git a/qpid/java/perftests/bin/run_many.sh b/qpid/java/perftests/bin/run_many.sh
deleted file mode 100755
index cca2ffec21..0000000000
--- a/qpid/java/perftests/bin/run_many.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-# args:
-# <number of processes to start>
-# <name of run>
-# <command ro run>
-
-for i in `seq 1 $1`; do
- $3 >$2.$i.out 2>>$2.err &
- echo $! > $2.$i.pid
-done;
diff --git a/qpid/java/perftests/bin/serviceProvidingClient.sh b/qpid/java/perftests/bin/serviceProvidingClient.sh
deleted file mode 100755
index 0f4264be10..0000000000
--- a/qpid/java/perftests/bin/serviceProvidingClient.sh
+++ /dev/null
@@ -1,33 +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.
-#
-# args supplied: <brokerdetails> <num messages>
-
-if [[ $# != 1 ]] ; then
- echo "usage: ./serviceProvidingClient.sh <brokerdetails> [<P[ersistent]|N[onPersistent] (default N)> <T[ransacted]|N[onTransacted] (default N)>] [selector]"
- exit 1
-fi
-
-thehosts=$1
-shift
-
-. ./setupclasspath.sh
-echo $CP
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.requestreply.ServiceProvidingClient $thehosts guest guest /test serviceQ "$@"
diff --git a/qpid/java/perftests/bin/serviceRequestReply-MultipleClients.sh b/qpid/java/perftests/bin/serviceRequestReply-MultipleClients.sh
deleted file mode 100755
index 81558c2c0b..0000000000
--- a/qpid/java/perftests/bin/serviceRequestReply-MultipleClients.sh
+++ /dev/null
@@ -1,53 +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.
-#
-# args supplied: <brokerdetails> <num messages> <num clients>
-
-if [[ $# < 3 ]] ; then
- echo "usage: ./serviceRequestReply-QuickTest.sh <brokerdetails> <Number of messages> <number of clients> [<P[ersistent]|N[onPersistent] (default N)> <T[ransacted]|N[onTransacted] (default N)>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-
-numberofmessages=$1
-shift
-
-numberofclients=$1
-shift
-
-. ./setupclasspath.sh
-echo $CP
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.requestreply.ServiceProvidingClient $thehosts guest guest /test serviceQ "$@" &
-
-providingclient=$!
-
-./run_many.sh $numberofclients requestClients "./serviceRequestingClient.sh $thehosts $numberofmessages $@"
-
-sleeping=$(( numberofmessages * 1 / 10 ))
-
-echo "Sleeping for $sleeping secconds to completion"
-sleep $sleeping
-
-kill $providingclient
-
-echo "Results"
-cat requestClients.*.out \ No newline at end of file
diff --git a/qpid/java/perftests/bin/serviceRequestReply-QuickTest.sh b/qpid/java/perftests/bin/serviceRequestReply-QuickTest.sh
deleted file mode 100755
index 31c5e9eb74..0000000000
--- a/qpid/java/perftests/bin/serviceRequestReply-QuickTest.sh
+++ /dev/null
@@ -1,43 +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.
-#
-# args supplied: <brokerdetails> <num messages>
-
-if [[ $# < 2 ]] ; then
- echo "usage: ./serviceRequestReply-QuickTest.sh <brokerdetails> <Number of messages> [<P[ersistent]|N[onPersistent] (default N)> <T[ransacted]|N[onTransacted] (default N)>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-
-numberofmessages=$1
-shift
-
-. ./setupclasspath.sh
-echo $CP
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.requestreply.ServiceProvidingClient $thehosts guest guest /test serviceQ "$@" &
-
-providingclient=$!
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.requestreply.ServiceRequestingClient $thehosts guest guest /test serviceQ $numberofmessages "$@"
-
-kill $providingclient
-
diff --git a/qpid/java/perftests/bin/serviceRequestingClient-createLogFile.sh b/qpid/java/perftests/bin/serviceRequestingClient-createLogFile.sh
deleted file mode 100755
index c078caf7d1..0000000000
--- a/qpid/java/perftests/bin/serviceRequestingClient-createLogFile.sh
+++ /dev/null
@@ -1,38 +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.
-#
-
-##LOGDIR=$QPID_HOME/logs
-LOGDIR=../logs
-date=`date +"%y%m%d%H%M%S"`
-LOGFILE=$LOGDIR/perftest.log.$date
-
-## create the log dir
-if [ ! -d $LOGDIR ]; then
- mkdir $LOGDIR
-fi
-
-echo "********** Running the test **************"
-echo "creating logfile $LOGFILE"
-echo
-
-./serviceRequestingClient.sh $@ 2>&1 | tee $LOGFILE
-
-echo "********** End of test ******************"
-echo \ No newline at end of file
diff --git a/qpid/java/perftests/bin/serviceRequestingClient.sh b/qpid/java/perftests/bin/serviceRequestingClient.sh
deleted file mode 100755
index c03cc519c6..0000000000
--- a/qpid/java/perftests/bin/serviceRequestingClient.sh
+++ /dev/null
@@ -1,34 +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.
-#
-# usage: ./serviceRequestingClient.sh <brokerdetails> <number of messages> [<message size 4096b default>] [<P[ersistent]|N[onPersistent]> <T[ransacted]|N[onTransacted]>]
-
-if [[ $# < 2 ]] ; then
- echo "usage: ./serviceRequestingClient.sh <brokerdetails> <number of messages> [<message size 4096b default>] [<P[ersistent]|N[onPersistent]> <T[ransacted]|N[onTransacted]>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-
-# XXX -Xms1024m -XX:NewSize=300m
-. ./setupclasspath.sh
-echo $CP
-
-$JAVA_HOME/bin/java -cp $CP -Dlog.dir="$QPID_HOME/logs" -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.requestreply.ServiceRequestingClient $thehosts guest guest /test serviceQ "$@"
diff --git a/qpid/java/perftests/bin/setupclasspath.sh b/qpid/java/perftests/bin/setupclasspath.sh
deleted file mode 100755
index ef7a037c11..0000000000
--- a/qpid/java/perftests/bin/setupclasspath.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-if [ -z $QPID_HOME ] ; then
- echo "QPID_HOME must be set"
- exit
-fi
-
-CP=../lib/qpid-performance.jar:$QPID_HOME/lib/qpid-incubating.jar
-
-if [ `uname -o` == "Cygwin" ] ; then
- CP=`cygpath --path --windows $CP`
-fi
-
-
diff --git a/qpid/java/perftests/bin/testPingClient.sh b/qpid/java/perftests/bin/testPingClient.sh
deleted file mode 100755
index 4eca4a7999..0000000000
--- a/qpid/java/perftests/bin/testPingClient.sh
+++ /dev/null
@@ -1,33 +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.
-#
-# args supplied: <host:port>
-#
-if [[ $# < 1 ]] ; then
- echo "usage: ./testPingClient.sh <host details> [<selector>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-echo $thehosts
-# XXX -Xms1024m -XX:NewSize=300m
-. ./setupclasspath.sh
-echo $CP
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.ping.TestPingClient $thehosts guest guest /test "$@"
diff --git a/qpid/java/perftests/bin/testPingProducer.sh b/qpid/java/perftests/bin/testPingProducer.sh
deleted file mode 100755
index 39ab487b60..0000000000
--- a/qpid/java/perftests/bin/testPingProducer.sh
+++ /dev/null
@@ -1,33 +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.
-#
-# args supplied: <host:port>
-#
-if [[ $# < 1 ]] ; then
- echo "usage: ./testPingProducer.sh <host details> [<selector>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-echo $thehosts
-# XXX -Xms1024m -XX:NewSize=300m
-. ./setupclasspath.sh
-echo $CP
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.ping.TestPingProducer $thehosts /test
diff --git a/qpid/java/perftests/bin/testPingPublisher.sh b/qpid/java/perftests/bin/testPingPublisher.sh
deleted file mode 100755
index e8219e7612..0000000000
--- a/qpid/java/perftests/bin/testPingPublisher.sh
+++ /dev/null
@@ -1,33 +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.
-#
-# args supplied: <host:port>
-#
-if [[ $# < 1 ]] ; then
- echo "usage: ./testPingPublisher.sh <host details>"
- exit 1
-fi
-
-thehosts=$1
-shift
-echo $thehosts
-# XXX -Xms1024m -XX:NewSize=300m
-. ./setupclasspath.sh
-echo $CP
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.pingpong.TestPingPublisher $thehosts /test
diff --git a/qpid/java/perftests/bin/testPingSubscriber.sh b/qpid/java/perftests/bin/testPingSubscriber.sh
deleted file mode 100755
index a0520be093..0000000000
--- a/qpid/java/perftests/bin/testPingSubscriber.sh
+++ /dev/null
@@ -1,33 +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.
-#
-# args supplied: <host:port>
-#
-if [[ $# < 1 ]] ; then
- echo "usage: ./testPingSubscriber.sh <host details> [<selector>]"
- exit 1
-fi
-
-thehosts=$1
-shift
-echo $thehosts
-# XXX -Xms1024m -XX:NewSize=300m
-. ./setupclasspath.sh
-echo $CP
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="debug" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.pingpong.TestPingSubscriber $thehosts guest guest /test "$@"
diff --git a/qpid/java/perftests/bin/topic-QuickTest.sh b/qpid/java/perftests/bin/topic-QuickTest.sh
deleted file mode 100755
index 931f102893..0000000000
--- a/qpid/java/perftests/bin/topic-QuickTest.sh
+++ /dev/null
@@ -1,55 +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.
-#
-# args supplied: <host> <port> <messages> <clients> <batches>
-
-if [[ $# < 5 ]] ; then
- echo "usage: ./topic-QuickTest.sh <host> <port> <messages> <clients> <batches> [other params for both listener and publisher]"
- exit 1
-fi
-
-host=$1
-shift
-
-port=$1
-shift
-
-nomessages=$1
-shift
-
-noclients=$1
-shift
-
-batches=$1
-shift
-
-sleeptime=$(( 2 * $noclients ))
-
-. ./setupclasspath.sh
-echo $CP
-
-./run_many.sh $noclients topic "$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level='warn' -Damqj.test.logging.level='info' -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.topic.Listener -host $host -port $port $@" &
-
-echo
-echo "Pausing for $sleeptime seconds to allow clients to connect"
-sleep $sleeptime
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.topic.Publisher -host $host -port $port -messages $nomessages -clients $noclients -batch $batches $@
-
-
diff --git a/qpid/java/perftests/bin/topicListener.sh b/qpid/java/perftests/bin/topicListener.sh
deleted file mode 100755
index 757a8c9edb..0000000000
--- a/qpid/java/perftests/bin/topicListener.sh
+++ /dev/null
@@ -1,26 +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.
-#
-
-
-# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-. ./setupclasspath.sh
-echo $CP
-
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.topic.Listener $@
diff --git a/qpid/java/perftests/bin/topicPublisher.sh b/qpid/java/perftests/bin/topicPublisher.sh
deleted file mode 100755
index 8bcdaca3c4..0000000000
--- a/qpid/java/perftests/bin/topicPublisher.sh
+++ /dev/null
@@ -1,23 +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.
-#
-
-# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-. ./setupclasspath.sh
-$JAVA_HOME/bin/java -cp $CP -Damqj.logging.level="warn" -Damqj.test.logging.level="info" -Dlog4j.configuration=src/perftests.log4j org.apache.qpid.topic.Publisher $@
diff --git a/qpid/java/perftests/pom.xml b/qpid/java/perftests/pom.xml
index 396701d3ed..3bcda0f359 100644
--- a/qpid/java/perftests/pom.xml
+++ b/qpid/java/perftests/pom.xml
@@ -19,6 +19,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-perftests</artifactId>
@@ -35,9 +36,33 @@
<properties>
<topDirectoryLocation>..</topDirectoryLocation>
- <log4j.perftests>perftests.log4j</log4j.perftests>
+ <log4j.perftests>perftests.log4j</log4j.perftests>
</properties>
+ <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. -->
+ <repositories>
+ <repository>
+ <id>junit-toolkit.snapshots</id>
+ <name>JUnit Toolkit SNAPSHOT Repository</name>
+ <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. -->
+ <pluginRepositories>
+ <pluginRepository>
+ <id>junit-toolkit-plugin.snapshots</id>
+ <name>JUnit Toolkit SNAPSHOT Repository</name>
+ <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+
<dependencies>
<dependency>
@@ -50,15 +75,15 @@
<artifactId>log4j</artifactId>
</dependency>
- <!-- Test dependencies. -->
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
+ <groupId>uk.co.thebadgerset</groupId>
+ <artifactId>junit-toolkit</artifactId>
</dependency>
+ <!-- Test dependencies. -->
<dependency>
- <groupId>uk.co.thebadgerset</groupId>
- <artifactId>junit-toolkit</artifactId>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
</dependency>
</dependencies>
@@ -72,45 +97,41 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <!--<skip>true</skip>-->
- </configuration>
</plugin>
- <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository. It will take a day or two from 16/1/2007.
+ <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository.
- Configures the toolkit test runner for performance testing. These can be run from within maven, or by using the generated
+ Configures the toolkit test runner for performance testing. These can be run from within maven, or by using the generated
scripts.
- To run from maven:
+ To run from within maven:
- mvn uk.co.thebadgerset:junit-toolkit-maven-plugin:tktest
+ mvn uk.co.thebadgerset:junit-toolkit-maven-plugin:tktest
- To run from the command line (after doing assembly:assembly goal):
+ To run from the command line (after doing assembly:assembly goal):
- java -cp target/test_jar-jar-with-dependencies.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -s 1 -r 100000 -o target org.apache.qpid.requestreply.PingPongTestPerf
+ java -cp target/test_jar-jar-with-dependencies.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -s 1 -r 100000
+ -o target org.apache.qpid.requestreply.PingPongTestPerf
- To generate the scripts do:
+ To generate the scripts do:
- mvn uk.co.thebadgerset:junit-toolkit-maven-plugin:tkscriptgen
+ mvn uk.co.thebadgerset:junit-toolkit-maven-plugin:tkscriptgen
- Then to run the scripts do (after doing assembly:assembly goal):
+ Then to run the scripts, in the target directory do (after doing assembly:assembly goal):
- ./bin/script_name or ./bin/script_name.bat
+ ./script_name.sh
- These scripts can find everything in the 'all test dependencies' jar created by the assembly:assembly goal.
- -->
-<!--
+ These scripts can find everything in the 'all test dependencies' jar created by the assembly:assembly goal.
+ -->
<plugin>
<groupId>uk.co.thebadgerset</groupId>
<artifactId>junit-toolkit-maven-plugin</artifactId>
- <version>0.3</version>
<configuration>
- <scriptOutDirectory>target</scriptOutDirectory>
- <testJar>${project.build.finalName}-all-test-deps.jar</testJar>
+ <scriptOutDirectory>target</scriptOutDirectory>
+ <testJar>${project.build.finalName}-all-test-deps.jar</testJar>
- <systemproperties>
+ <systemproperties>
<property>
<name>log4j.configuration</name>
<value>${log4j.perftests}</value>
@@ -119,7 +140,7 @@
<name>amqj.logging.level</name>
<value>warn</value>
</property>
- <property>
+ <property><!-- Turn off most logging messages from the junit-toolkit test tool itself. -->
<name>badger.level</name>
<value>warn</value>
</property>
@@ -127,148 +148,45 @@
<name>amqj.test.logging.level</name>
<value>info</value>
</property>
- </systemproperties>
+ </systemproperties>
<commands>
- <!## Run the ping pong test once. This is just to check toolkit test runner is working. Real tests follow. ##>
- <PingOnce>-n PingOnce -s [1] -r 1 -t testPingOk -o . org.apache.qpid.ping.PingTestPerf</PingOnce>
-
- <!## Tests the accuracy of the throttle implementation at different speeds. Throttle is used to restrict message rate in some tsts. ##>
- <ThrottleTest>-n ThrottleTest -r 5 -s [10,10000],samples=100,exp -t testThrottle -o . org.apache.qpid.ping.ThrottleTestPerf</ThrottleTest>
-
- <!##
- Skim Tests.
- These are not part of the performance suite. They run quick tests to check that the different combinations of
- options that the performance suite uses are going to work.
- ##>
- <Skim-Tx>-n Skim-Tx -s [1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true</Skim-Tx>
- <Skim-Size>-n Skim-Size -s [1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messagesize=51200</Skim-Size>
- <Skim-Many>-n Skim-Many -s [1] -c [4] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Skim-Many>
- <Skim-Queues>-n Skim-Queues -s [1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf destinationcount=10</Skim-Queues>
- <Skim-Duration>-n Skim-Duration -s [1000] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Skim-Duration>
- <Skim-Rate>-n Skim-Rate -s [1000] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=100</Skim-Rate>
-
- <!## P2P Volume Tests. ##>
- <VT-Qpid-1>-n VT-Qpid-1 -s [15000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 CommitBatchSize=20000 transacted=true</VT-Qpid-1>
- <VT-Qpid-2>-n VT-Qpid-2 -s [15000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000</VT-Qpid-2>
- <!## Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. ##>
- <VT-Qpid-3>-n VT-Qpid-3 -s [3000000] -d 24H -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true rate=10000 BatchSize=3000000 CommitBatchSize=40000 transacted=true</VT-Qpid-3>
- <VT-Qpid-4>-n VT-Qpid-4 -s [3000000] -d 24H -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true rate=10000 BatchSize=3000000</VT-Qpid-4>
-
- <!## P2P Scalability Tests. ##>
- <!## 250,000 Total, 1P-1T-1C ##>
- <PT-Qpid-1>-n PT-Qpid-1 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true CommitBatchSize=20000 transacted=true</PT-Qpid-1>
- <PT-Qpid-2>-n PT-Qpid-2 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true </PT-Qpid-2>
-
- <!## 25000 Msgs * 10 Brokers = 250,000 Total, 10P-1Q-10C ##>
- <PT-Qpid-3>-n PT-Qpid-3 -s [25000] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true transacted=true CommitBatchSize=20000</PT-Qpid-3>
- <PT-Qpid-4>-n PT-Qpid-4 -s [25000] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true </PT-Qpid-4>
-
- <!## 25000 Msgs * 10 Brokers = 250,000 Tota,l 10P-10T-10C 10*(1P-1Q-1C) ##>
- <PT-Qpid-5>-n PT-Qpid-5 -s [25000] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationcount=1 transacted=true</PT-Qpid-5>
- <PT-Qpid-6>-n PT-Qpid-6 -s [25000] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationcount=1</PT-Qpid-6>
-
- <!## 2500 Msgs * 10 Brokers * 10 Topics/Clients = 250,000 Total, 10P-100T-10C 10*(1P-10T-1C) ##>
- <PT-Qpid-7>-n PT-Qpid-7 -s [2500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationcount=10 transacted=true</PT-Qpid-7>
- <PT-Qpid-8>-n PT-Qpid-8 -s [2500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationcount=10</PT-Qpid-8>
-
- <!## 2500 Msgs * 100 Brokers = 250,000 Total, 100P-100T-100C 100*(1P-1T-1C) ##>
- <PT-Qpid-9>-n PT-Qpid-9 -s [2500] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=1 transacted=true CommitBatchSize=500</PT-Qpid-9>
- <PT-Qpid-10>-n PT-Qpid-10 -s [2500] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=1</PT-Qpid-10>
-
- <!## 250 Msgs * 100 Brokers * 10 Clients = 250,000 Total, 100P-1000T-100C 100*(1P-10T-1C) ##>
- <PT-Qpid-11>-n PT-Qpid-11 -s [250] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=10 transacted=true CommitBatchSize=50</PT-Qpid-11>
- <PT-Qpid-12>-n PT-Qpid-12 -s [250] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=10</PT-Qpid-12>
-
- <!## 250 Msgs * 1000 Brokers = 250,000 Total, 1000P-1000T-1000C 1000*(1P-1T-1C) ##>
- <PT-Qpid-13>-n PT-Qpid-13 -s [250] -c[1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=1 transacted=true CommitBatchSize=50</PT-Qpid-13>
- <PT-Qpid-14>-n PT-Qpid-14 -s [250] -c[1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=250 destinationcount=1</PT-Qpid-14>
-
- <!## P2P Volume Tests. ##>
- <VQ-Qpid-1>-n VQ-Qpid-1 -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 transacted=true CommitBatchSize=40000</VQ-Qpid-1>
- <VQ-Qpid-2>-n VQ-Qpid-2 -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000</VQ-Qpid-2>
- <!## Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. ##>
- <VQ-Qpid-3>-n VQ-Qpid-3 -s [3000000] -d 24H -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=10000 BatchSize=3000000 transacted=true CommitBatchSize=40000</VQ-Qpid-3>
- <VQ-Qpid-4>-n VQ-Qpid-4 -s [3000000] -d 24H -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=10000 BatchSize=3000000 </VQ-Qpid-4>
-
- <!## P2P Scalability Tests. ##>
- <!## 15,000 Total, 1P-1Q-1C ##>
- <PQ-Qpid-1>-n PQ-Qpid-1 -s [15000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true</PQ-Qpid-1>
- <PQ-Qpid-2>-n PQ-Qpid-2 -s [15000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</PQ-Qpid-2>
-
- <!## 1500 Messages * 10 Brokers = 15,000 Total, 10P-1Q-10C ##>
- <PQ-Qpid-3>-n PQ-Qpid-3 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationname=ping transacted=true CommitBatchSize=500</PQ-Qpid-3>
- <PQ-Qpid-4>-n PQ-Qpid-4 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationname=ping</PQ-Qpid-4>
-
- <!## 1500 Messages * 10 Brokers = 15,000 Total, 10P-10Q-10C 10*(1P-1Q-1C) ##>
- <PQ-Qpid-5>-n PQ-Qpid-5 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=1 transacted=true CommitBatchSize=500</PQ-Qpid-5>
- <PQ-Qpid-6>-n PQ-Qpid-6 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=1</PQ-Qpid-6>
-
- <!## 1500 Messages * 10 Brokers = 15,000 Total, 10P-100Q-10C 10*(1P-10Q-1C) ##>
- <PQ-Qpid-7>-n PQ-Qpid-7 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=10 transacted=true CommitBatchSize=500</PQ-Qpid-7>
- <PQ-Qpid-8>-n PQ-Qpid-8 -s [1500] -c[10] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=10</PQ-Qpid-8>
-
- <!## 150 Messages * 100 Brokers = 15,000 Total, 100P-100Q-100C 100*(1P-1Q-1C) ##>
- <PQ-Qpid-9>-n PQ-Qpid-9 -s [150] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=50 destinationcount=1 transacted=true CommitBatchSize=50</PQ-Qpid-9>
- <PQ-Qpid-10>-n PQ-Qpid-10 -s [150] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=50 destinationcount=1 </PQ-Qpid-10>
-
- <!## 150 Messages * 100 Brokers = 15,000 Total, 100P-1000Q-100C 100*(1P-10Q-1C) ##>
- <PQ-Qpid-11>-n PQ-Qpid-11 -s [150] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=10 transacted=true CommitBatchSize=50</PQ-Qpid-11>
- <PQ-Qpid-12>-n PQ-Qpid-12 -s [150] -c[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=100 destinationcount=10</PQ-Qpid-12>
-
- <!## 15 Messages * 1000 Brokers = 15,000 Total, 1000P-1000Q-1000C 1000*(1P-1Q-1C) ##>
- <PQ-Qpid-13>-n PQ-Qpid-13 -s [15] -c[1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=15 transacted=true CommitBatchSize=15</PQ-Qpid-13>
- <PQ-Qpid-14>-n PQ-Qpid-14 -s [15] -c[1000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=15 </PQ-Qpid-14>
-
- <!## Increasing Message Payload Tests. ##>
- <!## Queue Testing ##>
- <LT-Qpid-1-512b>-n LT-Qpid-1-512b -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=512 transacted=true CommitBatchSize=10000</LT-Qpid-1-512b>
- <LT-Qpid-2-512b>-n LT-Qpid-2-512b -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=512</LT-Qpid-2-512b>
-
- <LT-Qpid-1-1K>-n LT-Qpid-1-1K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 transacted=true CommitBatchSize=10000</LT-Qpid-1-1K>
- <LT-Qpid-2-1K>-n LT-Qpid-2-1K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000</LT-Qpid-2-1K>
-
- <LT-Qpid-1-5K>-n LT-Qpid-1-5K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=5120 transacted=true CommitBatchSize=10000</LT-Qpid-1-5K>
- <LT-Qpid-2-5K>-n LT-Qpid-2-5K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=5120</LT-Qpid-2-5K>
-
- <LT-Qpid-1-10K>-n LT-Qpid-1-10K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=10240 transacted=true CommitBatchSize=10000</LT-Qpid-1-10K>
- <LT-Qpid-2-10K>-n LT-Qpid-2-10K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=10240 </LT-Qpid-2-10K>
-
- <LT-Qpid-1-50K>-n LT-Qpid-1-50K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=51200 transacted=true CommitBatchSize=10000</LT-Qpid-1-50K>
- <LT-Qpid-2-50K>-n LT-Qpid-2-50K -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=51200</LT-Qpid-2-50K>
-
- <LT-Qpid-1-1M>-n LT-Qpid-1-1M -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=1048576 transacted=true CommitBatchSize=10000</LT-Qpid-1-1M>
- <LT-Qpid-2-1M>-n LT-Qpid-2-1M -s [1000000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true BatchSize=10000 messagesize=1048476</LT-Qpid-2-1M>
-
- <!## Topic Testing ##>
- <LT-Qpid-3-512b>-n LT-Qpid-3-512b -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=512 transacted=true CommitBatchSize=10000</LT-Qpid-3-512b>
- <LT-Qpid-4-512b>-n LT-Qpid-4-512b -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=512</LT-Qpid-4-512b>
-
- <LT-Qpid-3-1K>-n LT-Qpid-3-1K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 transacted=true CommitBatchSize=10000</LT-Qpid-3-1K>
- <LT-Qpid-4-1K>-n LT-Qpid-4-1K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000</LT-Qpid-4-1K>
-
- <LT-Qpid-3-5K>-n LT-Qpid-3-5K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=5120 transacted=true CommitBatchSize=10000</LT-Qpid-3-5K>
- <LT-Qpid-4-5K>-n LT-Qpid-4-5K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=5120</LT-Qpid-4-5K>
-
- <LT-Qpid-3-10K>-n LT-Qpid-3-10K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=10240 transacted=true CommitBatchSize=10000</LT-Qpid-3-10K>
- <LT-Qpid-4-10K>-n LT-Qpid-4-10K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=10240</LT-Qpid-4-10K>
-
- <LT-Qpid-3-50K>-n LT-Qpid-3-50K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=51200 transacted=true CommitBatchSize=10000</LT-Qpid-3-50K>
- <LT-Qpid-4-50K>-n LT-Qpid-4-50K -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=51200</LT-Qpid-4-50K>
-
- <LT-Qpid-3-1M>-n LT-Qpid-3-1M -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=1048576 transacted=true CommitBatchSize=10000</LT-Qpid-3-1M>
- <LT-Qpid-4-1M>-n LT-Qpid-4-1M -s [900000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 messagesize=1048576 </LT-Qpid-4-1M>
-
- <!## Failover Tests. ##>
- <!## Transactional ##>
- <FT-Qpid-1>-n FT-Qpid-1 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 transacted=true CommitBatchSize=10000 broker="tcp://localhost:5001;tcp://localhost:5002" FailBeforeSend=true</FT-Qpid-1>
- <FT-Qpid-2>-n FT-Qpid-2 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 transacted=true CommitBatchSize=10000 broker="tcp://localhost:5001;tcp://localhost:5002" FailAfterSend=true</FT-Qpid-2>
- <FT-Qpid-3>-n FT-Qpid-3 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 transacted=true CommitBatchSize=10000 broker="tcp://localhost:5001;tcp://localhost:5002" FailAfterCommit=true</FT-Qpid-3>
-
- <!## Non Transactional ##>
- <FT-Qpid-4>-n FT-Qpid-4 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 broker="tcp://localhost:5001;tcp://localhost:5002" transacted=false FailBeforeSend=true</FT-Qpid-4>
- <FT-Qpid-5>-n FT-Qpid-5 -s [250000] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10000 broker="tcp://localhost:5001;tcp://localhost:5002" transacted=false FailAfterSend=true</FT-Qpid-5>
-
+ <!-- Single pings. These can be scaled up by overriding the parameters when calling the test script. -->
+ <Ping-Once>-n Ping-Once -s [1] -r 1 -t testPingOk -o . org.apache.qpid.ping.PingTestPerf</Ping-Once>
+ <Ping-Once-Async>-n Ping-Once-Async -s [1] -r 1 -t testAsyncPingOk -o . org.apache.qpid.ping.PingAsyncTestPerf</Ping-Once-Async>
+ <Ping-Latency>-n Ping-Latency -s [1000] -d 10S -t testPingLatency -o . org.apache.qpid.ping.PingLatencyTestPerf</Ping-Latency>
+
+ <!-- More example Tests. These are examples to exercise all the features of the test harness. Can scale up with option overrides. -->
+ <Ping-Tx>-n Ping-Tx -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true</Ping-Tx>
+ <Ping-Size>-n Ping-Size -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messagesize=512</Ping-Size>
+ <Ping-Concurrent>-n Ping-Concurrent -s [100] -c [4] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Ping-Concurrent>
+ <Ping-Many-Queues>
+ -n Ping-Many-Queues -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf destinationcount=4
+ </Ping-Many-Queues>
+ <Ping-Duration>-n Ping-Duration -s [100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Ping-Duration>
+ <Ping-Rate>-n Ping-Rate -s [100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=500</Ping-Rate>
+ <Ping-PubSub>-n Ping-PubSub -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true</Ping-PubSub>
+ <Ping-Many-Topics>
+ -n Ping-Many-Topics -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationcount=4
+ </Ping-Many-Topics>
+ <Ping-Persistent>
+ -n Ping-Persistent -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true
+ </Ping-Persistent>
+ <Ping-Batch-Logging>
+ -n Ping-Batch-Logging -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf BatchSize=10
+ </Ping-Batch-Logging>
+ <Ping-Failover-Before-Send>
+ -n Ping-Failover-Before-Send -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf CommitBatchSize=10 FailBeforeSend=true
+ </Ping-Failover-Before-Send>
+ <Ping-Failover-After-Send>
+ -n Ping-Failover-After-Send -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf CommitBatchSize=10 FailAfterSend=true
+ </Ping-Failover-After-Send>
+ <Ping-Failover-Before-Commit>
+ -n Ping-Failover-Before-Commit -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf CommitBatchSize=10 FailBeforeCommit=true
+ </Ping-Failover-Before-Commit>
+ <Ping-Failover-After-Commit>
+ -n Ping-Failover-After-Commit -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf CommitBatchSize=10 FailAfterCommit=true
+ </Ping-Failover-After-Commit>
</commands>
</configuration>
@@ -276,13 +194,13 @@
<executions>
<execution>
<phase>test</phase>
- <!##<goals>
+ <!--<goals>
<goal>tktest</goal>
- </goals>##>
+ </goals>-->
</execution>
</executions>
</plugin>
--->
+
<!-- Bundles all the dependencies, fully expanded into a single jar, required to run the tests.
Usefull when bundling system, integration or performance tests into a convenient
@@ -312,7 +230,7 @@
</plugins>
<resources>
- <!-- Include source files in built jar -->
+ <!-- Include source files in built jar -->
<resource>
<targetPath>src/</targetPath>
<filtering>false</filtering>
@@ -321,7 +239,7 @@
<include>**/*.java</include>
</includes>
</resource>
- <!-- Include a log4j configuration in the jar at the root level (don't name this log4j.properties though as won't be able to override it). -->
+ <!-- Include a log4j configuration in the jar at the root level (don't name this log4j.properties though as won't be able to override it). -->
<resource>
<targetPath>/</targetPath>
<filtering>false</filtering>
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java
deleted file mode 100644
index 97b411323e..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java
+++ /dev/null
@@ -1,204 +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.ping;
-
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-
-import javax.jms.JMSException;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.jms.Session;
-
-/**
- * Provides common functionality that ping clients (the recipients of ping messages) can use. This base class keeps
- * track of the connection used to send pings, provides a convenience method to commit a transaction only when a session
- * to commit on is transactional, keeps track of whether the ping client is pinging to a queue or a topic, provides
- * prompts to the console to terminate brokers before and after commits, in order to test failover functionality, and
- * provides a convience formatter for outputing readable timestamps for pings.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Commit the current transcation on a session.
- * <tr><td> Generate failover promts.
- * <tr><td> Keep track the connection.
- * <tr><td> Keep track of p2p or topic ping type.
- * </table>
- *
- * @todo This base class does not seem particularly usefull and all functionality is duplicated in {@link AbstractPingProducer}.
- * Merge it into that class.
- */
-public abstract class AbstractPingClient
-{
- private static final Logger _logger = Logger.getLogger(TestPingClient.class);
-
- /** A convenient formatter to use when time stamping output. */
- protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
-
- /** Holds the connection to the broker. */
- private AMQConnection _connection;
-
- /** Flag used to indicate if this is a point to point or pub/sub ping client. */
- private boolean _isPubSub = false;
-
- /**
- * This flag is used to indicate that the user should be prompted to kill a broker, in order to test
- * failover, immediately before committing a transaction.
- */
- protected boolean _failBeforeCommit = false;
-
- /**
- * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test
- * failover, immediate after committing a transaction.
- */
- protected boolean _failAfterCommit = false;
-
- /**
- * Convenience method to commit the transaction on the specified session. If the session to commit on is not
- * a transactional session, this method does nothing.
- *
- * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
- * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
- * after the commit is applied.
- *
- * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
- */
- protected void commitTx(Session session) throws JMSException
- {
- if (session.getTransacted())
- {
- try
- {
- if (_failBeforeCommit)
- {
- _logger.trace("Failing Before Commit");
- doFailover();
- }
-
- session.commit();
-
- if (_failAfterCommit)
- {
- _logger.trace("Failing After Commit");
- doFailover();
- }
-
- _logger.trace("Session Commited.");
- }
- catch (JMSException e)
- {
- _logger.trace("JMSException on commit:" + e.getMessage(), e);
-
- try
- {
- session.rollback();
- _logger.debug("Message rolled back.");
- }
- catch (JMSException jmse)
- {
- _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
-
- // Both commit and rollback failed. Throw the rollback exception.
- throw jmse;
- }
- }
- }
- }
-
- /**
- * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- *
- * @param broker The name of the broker to terminate.
- */
- protected void doFailover(String broker)
- {
- System.out.println("Kill Broker " + broker + " now.");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
- }
-
- /**
- * Prompts the user to terminate the broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- */
- protected void doFailover()
- {
- System.out.println("Kill Broker now.");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
-
- }
-
- /**
- * Gets the underlying connection that this ping client is running on.
- *
- * @return The underlying connection that this ping client is running on.
- */
- public AMQConnection getConnection()
- {
- return _connection;
- }
-
- /**
- * Sets the connection that this ping client is using.
- *
- * @param connection The ping connection.
- */
- public void setConnection(AMQConnection connection)
- {
- this._connection = connection;
- }
-
- /**
- * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic.
- *
- * @param pubsub <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public void setPubSub(boolean pubsub)
- {
- _isPubSub = pubsub;
- }
-
- /**
- * Checks whether this client is a p2p or pub/sub ping client.
- *
- * @return <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public boolean isPubSub()
- {
- return _isPubSub;
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java
deleted file mode 100644
index 091a865473..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java
+++ /dev/null
@@ -1,524 +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.ping;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.jms.*;
-import javax.jms.Connection;
-import javax.jms.Message;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQNoConsumersException;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.client.message.TestMessageFactory;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.jms.Session;
-
-/**
- * Provides common functionality that ping producers (the senders of ping messages) can use. This base class keeps
- * track of the connection used to send pings; provides a convenience method to commit a transaction only when a session
- * to commit on is transactional; keeps track of whether the ping client is pinging to a queue or a topic; provides
- * prompts to the console to terminate brokers before and after commits, in order to test failover functionality;
- * requires sub-classes to implement a ping loop, that this provides a run loop to repeatedly call; provides a
- * default shutdown hook to cleanly terminate the run loop; keeps track of the destinations to send pings to;
- * provides a convenience method to generate short pauses; and provides a convience formatter for outputing readable
- * timestamps for pings.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Commit the current transcation on a session.
- * <tr><td> Generate failover promts.
- * <tr><td> Keep track the connection.
- * <tr><td> Keep track of p2p or topic ping type.
- * <tr><td> Call ping loop to repeatedly send pings.
- * <tr><td> Provide a shutdown hook.
- * <tr><td> Generate short pauses.
- * </table>
- *
- * @todo Destination count versus list of desintations is redundant. Use _destinions.size() to get the count and
- * use a list of 1 destination when only 1 is needed. It is only important to distinguish when 1 destination
- * is shared between multiple ping producers on the same JVM or if each ping producer has its own single
- * destination.
- *
- * @todo Timestamp messages in nanos, not millis. Millis seems to have bad resolution, at least on windows.
- */
-public abstract class AbstractPingProducer implements Runnable, ExceptionListener
-{
- private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class);
-
- /** Flag used to indicate if this is a point to point or pub/sub ping client. */
- private boolean _isPubSub = false;
-
- /** A convenient formatter to use when time stamping output. */
- protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
-
- /**
- * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when
- * creating multiple ping producers in the same JVM.
- */
- private static AtomicInteger _queueSequenceID = new AtomicInteger();
-
- /** Used to tell the ping loop when to terminate, it only runs while this is true. */
- protected boolean _publish = true;
-
- /** Holds the connection to the broker. */
- private Connection _connection;
-
- /** Holds the producer session, needed to create ping messages. */
- private Session _producerSession;
-
- /** Holds the number of destinations that this ping producer will send pings to, defaulting to a single destination. */
- protected int _destinationCount = 1;
-
- /** Holds the set of destiniations that this ping producer pings. */
- private List<Destination> _destinations = new ArrayList<Destination>();
-
- /** Holds the message producer to send the pings through. */
- protected org.apache.qpid.jms.MessageProducer _producer;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */
- protected boolean _failBeforeCommit = false;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */
- protected boolean _failAfterCommit = false;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */
- protected boolean _failBeforeSend = false;
-
- /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */
- protected boolean _failAfterSend = false;
-
- /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */
- protected boolean _failOnce = true;
-
- /** Holds the number of sends that should be performed in every transaction when using transactions. */
- protected int _txBatchSize = 1;
-
- /**
- * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic.
- *
- * @param pubsub <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public void setPubSub(boolean pubsub)
- {
- _isPubSub = pubsub;
- }
-
- /**
- * Checks whether this client is a p2p or pub/sub ping client.
- *
- * @return <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
- */
- public boolean isPubSub()
- {
- return _isPubSub;
- }
-
- /**
- * Convenience method for a short pause.
- *
- * @param sleepTime The time in milliseconds to pause for.
- */
- public static void pause(long sleepTime)
- {
- if (sleepTime > 0)
- {
- try
- {
- Thread.sleep(sleepTime);
- }
- catch (InterruptedException ie)
- { }
- }
- }
-
- /**
- * Implementations should provide this method to perform a single ping cycle (which may send many messages). The
- * run loop will repeatedly call this method until the publish flag is set to false.
- */
- public abstract void pingLoop();
-
- /**
- * Generates a test message of the specified size, with the specified reply-to destination and persistence flag.
- *
- * @param replyQueue The reply-to destination for the message.
- * @param messageSize The desired size of the message in bytes.
- * @param persistent <tt>true</tt> if the message should use persistent delivery, <tt>false</tt> otherwise.
- *
- * @return A freshly generated test message.
- *
- * @throws JMSException All underlying JMSException are allowed to fall through.
- */
- public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException
- {
- ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent);
- // Timestamp the message.
- msg.setLongProperty("timestamp", System.currentTimeMillis());
-
- return msg;
- }
-
- /**
- * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this
- * flag has been cleared.
- */
- public void stop()
- {
- _publish = false;
- }
-
- /**
- * Implements a ping loop that repeatedly pings until the publish flag becomes false.
- */
- public void run()
- {
- // Keep running until the publish flag is cleared.
- while (_publish)
- {
- pingLoop();
- }
- }
-
- /**
- * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the
- * connection, this clears the publish flag which in turn will halt the ping loop.
- *
- * @param e The exception that triggered this callback method.
- */
- public void onException(JMSException e)
- {
- _publish = false;
- _logger.debug("There was a JMSException: " + e.getMessage(), e);
- }
-
- /**
- * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered
- * with the runtime system as a shutdown hook.
- *
- * @return A shutdown hook for the ping loop.
- */
- public Thread getShutdownHook()
- {
- return new Thread(new Runnable()
- {
- public void run()
- {
- stop();
- }
- });
- }
-
- /**
- * Gets the underlying connection that this ping client is running on.
- *
- * @return The underlying connection that this ping client is running on.
- */
- public Connection getConnection()
- {
- return _connection;
- }
-
- /**
- * Sets the connection that this ping client is using.
- *
- * @param connection The ping connection.
- */
- public void setConnection(Connection connection)
- {
- this._connection = connection;
- }
-
- /**
- * Gets the producer session that the ping client is using to send pings on.
- *
- * @return The producer session that the ping client is using to send pings on.
- */
- public Session getProducerSession()
- {
- return _producerSession;
- }
-
- /**
- * Keeps track of the producer session that the ping client is using to send pings on.
- *
- * @param session The producer session that the ping client is using to send pings on.
- */
- public void setProducerSession(Session session)
- {
- this._producerSession = session;
- }
-
- /**
- * Gets the number of destinations that this ping client is sending to.
- *
- * @return The number of destinations that this ping client is sending to.
- */
- public int getDestinationsCount()
- {
- return _destinationCount;
- }
-
- /**
- * Sets the number of destination that this ping client should send to.
- *
- * @param count The number of destination that this ping client should send to.
- *
- * @deprectaed Use _destinations.size() instead.
- */
- public void setDestinationsCount(int count)
- {
- this._destinationCount = count;
- }
-
- /**
- * Commits the transaction on the producer session.
- *
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- *
- * @deprecated Use the commitTx(Session session) method instead, to explicitly specify which session is being
- * committed. This makes it more obvious what is going on.
- */
- protected void commitTx() throws JMSException
- {
- commitTx(getProducerSession());
- }
-
- /**
- * Creates the specified number of destinations to send pings to. Topics or Queues will be created depending on
- * the value of the {@link #_isPubSub} flag.
- *
- * @param count The number of ping destinations to create.
- */
- protected void createDestinations(int count)
- {
- // Create the desired number of ping destinations.
- for (int i = 0; i < count; i++)
- {
- AMQDestination destination = null;
-
- // Check if this is a pub/sub pinger, in which case create topics.
- if (isPubSub())
- {
- AMQShortString name =
- new AMQShortString("AMQTopic_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis());
- destination = new AMQTopic(name);
- }
- // Otherwise this is a p2p pinger, in which case create queues.
- else
- {
- AMQShortString name =
- new AMQShortString("AMQQueue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis());
- destination = new AMQQueue(name, name, false, false, false);
- }
-
- _destinations.add(destination);
- }
- }
-
- /**
- * Returns the destination from the destinations list with the given index.
- *
- * @param index The index of the destination to get.
- *
- * @return Destination with the given index.
- */
- protected Destination getDestination(int index)
- {
- return _destinations.get(index);
- }
-
- /**
- * Convenience method to commit the transaction on the specified session. If the session to commit on is not
- * a transactional session, this method does nothing (unless the failover after send flag is set).
- *
- * <p/>If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit
- * is applied. This flag applies whether the pinger is transactional or not.
- *
- * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
- * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
- * after the commit is applied. These flags will only apply if using a transactional pinger.
- *
- * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
- *
- * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit
- * method, because commits only apply to transactional pingers, but fail after send applied to transactional
- * and non-transactional alike.
- */
- protected void commitTx(Session session) throws JMSException
- {
- _logger.trace("Batch time reached");
- if (_failAfterSend)
- {
- _logger.trace("Batch size reached");
- if (_failOnce)
- {
- _failAfterSend = false;
- }
-
- _logger.trace("Failing After Send");
- doFailover();
- }
-
- if (session.getTransacted())
- {
- try
- {
- if (_failBeforeCommit)
- {
- if (_failOnce)
- {
- _failBeforeCommit = false;
- }
-
- _logger.trace("Failing Before Commit");
- doFailover();
- }
-
- session.commit();
-
- if (_failAfterCommit)
- {
- if (_failOnce)
- {
- _failAfterCommit = false;
- }
-
- _logger.trace("Failing After Commit");
- doFailover();
- }
-
- _logger.trace("Session Commited.");
- }
- catch (JMSException e)
- {
- _logger.trace("JMSException on commit:" + e.getMessage(), e);
-
- // Warn that the bounce back client is not available.
- if (e.getLinkedException() instanceof AMQNoConsumersException)
- {
- _logger.debug("No consumers on queue.");
- }
-
- try
- {
- session.rollback();
- _logger.trace("Message rolled back.");
- }
- catch (JMSException jmse)
- {
- _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
-
- // Both commit and rollback failed. Throw the rollback exception.
- throw jmse;
- }
- }
- }
- }
-
- /**
- * Sends the specified message to the default destination of the ping producer.
- *
- * @param message The message to send.
- *
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- */
- protected void sendMessage(Message message) throws JMSException
- {
- sendMessage(null, message);
- }
-
- /**
- * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination
- * of the ping producer. If an explicit destination is set, this overrides the default.
- *
- * @param destination The destination to send to.
- * @param message The message to send.
- *
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- */
- protected void sendMessage(Destination destination, Message message) throws JMSException
- {
- if (_failBeforeSend)
- {
- if (_failOnce)
- {
- _failBeforeSend = false;
- }
-
- _logger.trace("Failing Before Send");
- doFailover();
- }
-
- if (destination == null)
- {
- _producer.send(message);
- }
- else
- {
- _producer.send(destination, message);
- }
- }
-
- /**
- * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- *
- * @param broker The name of the broker to terminate.
- */
- protected void doFailover(String broker)
- {
- System.out.println("Kill Broker " + broker + " now then press return");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
- }
-
- /**
- * Prompts the user to terminate the broker, in order to test failover functionality. This method will block
- * until the user supplied some input on the terminal.
- */
- protected void doFailover()
- {
- System.out.println("Kill Broker now then press return");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- { }
-
- System.out.println("Continuing.");
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java
new file mode 100644
index 0000000000..1a37f47b35
--- /dev/null
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ping;
+
+import java.util.List;
+
+import javax.jms.Destination;
+
+import org.apache.qpid.requestreply.PingPongProducer;
+
+/**
+ * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer}
+ * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues.
+ * It is an all in one ping client, that produces and consumes its own pings.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Create a ping pong producer that listens to its own pings <td> {@link PingPongProducer}
+ * </table>
+ */
+public class PingClient extends PingPongProducer
+{
+ private static int _pingClientCount;
+
+ /**
+ * Creates a ping producer with the specified parameters, of which there are many. See their individual comments
+ * for details. This constructor creates ping pong producer but de-registers its reply-to destination message
+ * listener, and replaces it by listening to all of its ping destinations.
+ *
+ * @param brokerDetails The URL of the broker to send pings to.
+ * @param username The username to log onto the broker with.
+ * @param password The password to log onto the broker with.
+ * @param virtualpath The virtual host name to use on the broker.
+ * @param destinationName The name (or root where multiple destinations are used) of the desitination to send
+ * pings to.
+ * @param selector The selector to filter replies with.
+ * @param transacted Indicates whether or not pings are sent and received in transactions.
+ * @param persistent Indicates whether pings are sent using peristent delivery.
+ * @param messageSize Specifies the size of ping messages to send.
+ * @param verbose Indicates that information should be printed to the console on every ping.
+ * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover.
+ * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover.
+ * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover.
+ * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover.
+ * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all.
+ * @param txBatchSize Specifies the number of pings to send in each transaction.
+ * @param noOfDestinations The number of destinations to ping. Must be 1 or more.
+ * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as
+ * possible, with no rate restriction.
+ * @param pubsub True to ping topics, false to ping queues.
+ * @param unique True to use unique destinations for each ping pong producer, false to share.
+ *
+ * @throws Exception Any exceptions are allowed to fall through.
+ */
+ public PingClient(String brokerDetails, String username, String password, String virtualpath, String destinationName,
+ String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose,
+ boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce,
+ int txBatchSize, int noOfDestinations, int rate, boolean pubsub, boolean unique) throws Exception
+ {
+ super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize,
+ verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate,
+ pubsub, unique);
+
+ _pingClientCount++;
+ }
+
+ /**
+ * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the
+ * effect of making this pinger listen to its own pings.
+ *
+ * @return The ping destinations.
+ */
+ public List<Destination> getReplyDestinations()
+ {
+ return _pingDestinations;
+ }
+
+ public int getConsumersPerTopic()
+ {
+ if (_isUnique)
+ {
+ return 1;
+ }
+ else
+ {
+ return _pingClientCount;
+ }
+ }
+
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java
deleted file mode 100644
index 949ace20e1..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java
+++ /dev/null
@@ -1,192 +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.ping;
-
-import java.net.InetAddress;
-
-import javax.jms.*;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.jms.Session;
-
-/**
- * PingClient is a message listener that received time stamped ping messages. It can work out how long a ping took,
- * provided that its clokc is synchronized to that of the ping producer, or by running it on the same machine (or jvm)
- * as the ping producer.
- * <p/>
- * <p/>There is a verbose mode flag which causes information about each ping to be output to the console
- * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should
- * be disabled for real timing tests as writing to the console will slow things down.
- * <p/>
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide command line invocation to start the ping consumer on a configurable broker url.
- * </table>
- *
- * @todo Add a better command line interpreter to the main method. The command line is not very nice...
- */
-class TestPingClient extends AbstractPingClient implements MessageListener
-{
- private static final Logger _logger = Logger.getLogger(TestPingClient.class);
-
- /**
- * Used to indicate that the reply generator should log timing info to the console (logger info level).
- */
- private boolean _verbose = false;
-
- /**
- * The producer session.
- */
- private Session _consumerSession;
-
- /**
- * Creates a TestPingClient on the specified session.
- *
- * @param brokerDetails
- * @param username
- * @param password
- * @param queueName
- * @param virtualpath
- * @param transacted
- * @param selector
- * @param verbose
- * @param afterCommit
- *@param beforeCommit @throws Exception All underlying exceptions allowed to fall through. This is only test code...
- */
- public TestPingClient(String brokerDetails, String username, String password, String queueName, String virtualpath,
- boolean transacted, String selector, boolean verbose, boolean afterCommit, boolean beforeCommit) throws Exception
- {
- // Create a connection to the broker.
- InetAddress address = InetAddress.getLocalHost();
- String clientID = address.getHostName() + System.currentTimeMillis();
-
- setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath));
-
- // Create a transactional or non-transactional session depending on the command line parameter.
- _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
-
- // Connect a consumer to the ping queue and register this to be called back by it.
- Queue q = new AMQQueue(queueName);
- MessageConsumer consumer = _consumerSession.createConsumer(q, 1, false, false, selector);
-
- consumer.setMessageListener(this);
-
- // Hang on to the verbose flag setting.
- _verbose = verbose;
-
- // Set failover interrupts
- _failAfterCommit = afterCommit;
- _failBeforeCommit = beforeCommit;
- }
-
- /**
- * Starts a stand alone ping-pong client running in verbose mode.
- *
- * @param args
- */
- public static void main(String[] args) throws Exception
- {
- _logger.info("Starting...");
-
- // Display help on the command line.
- if (args.length < 4)
- {
- System.out.println(
- "Usage: brokerdetails username password virtual-path [queueName] [verbose] [transacted] [selector] [failover:<before|after>:commit]");
- System.exit(1);
- }
-
- // Extract all command line parameters.
- String brokerDetails = args[0];
- String username = args[1];
- String password = args[2];
- String virtualpath = args[3];
- String queueName = (args.length >= 5) ? args[4] : "ping";
- boolean verbose = (args.length >= 6) ? Boolean.parseBoolean(args[5]) : true;
- boolean transacted = (args.length >= 7) ? Boolean.parseBoolean(args[6]) : false;
- String selector = (args.length == 8) ? args[7] : null;
-
- boolean afterCommit = false;
- boolean beforeCommit = false;
-
- for (String arg : args)
- {
- if (arg.startsWith("failover:"))
- {
- //failover:<before|after>:<send:commit>
- String[] parts = arg.split(":");
- if (parts.length == 3)
- {
- if (parts[2].equals("commit"))
- {
- afterCommit = parts[1].equals("after");
- beforeCommit = parts[1].equals("before");
- }
- }
- else
- {
- System.out.println("Unrecognized failover request:" + arg);
- }
- }
- }
-
- // Create the test ping client and set it running.
- TestPingClient pingClient =
- new TestPingClient(brokerDetails, username, password, queueName, virtualpath, transacted, selector, verbose, afterCommit, beforeCommit);
-
- pingClient.getConnection().start();
-
- System.out.println("Waiting...");
- }
- /**
- * This is a callback method that is notified of all messages for which this has been registered as a message
- * listener on a message consumer.
- *
- * @param message The message that triggered this callback.
- */
- public void onMessage(javax.jms.Message message)
- {
- try
- {
- // Spew out some timing information if verbose mode is on.
- if (_verbose)
- {
- Long timestamp = message.getLongProperty("timestamp");
-
- if (timestamp != null)
- {
- long diff = System.currentTimeMillis() - timestamp;
- System.out.println("Ping time: " + diff);
- }
- }
-
- // Commit the transaction if running in transactional mode.
- commitTx(_consumerSession);
- }
- catch (JMSException e)
- {
- _logger.error("There was a JMSException: " + e.getMessage(), e);
- }
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java
deleted file mode 100644
index acb0135b86..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.ping;
-
-import javax.jms.JMSException;
-import javax.jms.MessageConsumer;
-import javax.jms.ObjectMessage;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.requestreply.PingPongProducer;
-import org.apache.qpid.topic.Config;
-
-/**
- * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue).
- * The producer and consumer created by this test send and receive messages to and from the same Queue. ie.
- * pingQueue and replyQueue are same.
- * This class extends @see org.apache.qpid.requestreply.PingPongProducer which different ping and reply Queues
- */
-public class TestPingItself extends PingPongProducer
-{
- private static final Logger _logger = Logger.getLogger(TestPingItself.class);
-
- /**
- * If noOfDestinations is <= 1 : There will be one Queue and one consumer instance for the test
- * If noOfDestinations is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances
- * as there are queues, each listening to a Queue. A producer is created which picks up a queue from
- * the list of queues to send message
- *
- * @param brokerDetails
- * @param username
- * @param password
- * @param virtualpath
- * @param queueName
- * @param selector
- * @param transacted
- * @param persistent
- * @param messageSize
- * @param verbose
- * @param afterCommit
- * @param beforeCommit
- * @param afterSend
- * @param beforeSend
- * @param failOnce
- * @param batchSize
- * @param noOfDestinations
- * @throws Exception
- */
- public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName,
- String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose,
- boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce,
- int batchSize, int noOfDestinations, int rate, boolean pubsub) throws Exception
- {
- super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent,
- messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize,
- noOfDestinations, rate, pubsub);
-
- if (noOfDestinations > DEFAULT_DESTINATION_COUNT)
- {
- createDestinations(noOfDestinations);
- _persistent = persistent;
- _messageSize = messageSize;
- _verbose = verbose;
-
- createConsumers(selector);
- createProducer();
- }
- }
-
- /**
- * Sets the replyQueue to be the same as ping queue.
- */
- @Override
- public void createConsumer(String selector) throws JMSException
- {
- // Create a message consumer to get the replies with and register this to be called back by it.
- setReplyDestination(getPingDestination());
- MessageConsumer consumer =
- getConsumerSession().createConsumer(getReplyDestination(), PREFETCH, false, EXCLUSIVE, selector);
- consumer.setMessageListener(this);
- }
-
- /**
- * Starts a ping-pong loop running from the command line.
- *
- * @param args The command line arguments as defined above.
- */
- public static void main(String[] args) throws Exception
- {
- // Extract the command line.
- Config config = new Config();
- config.setOptions(args);
- if (args.length == 0)
- {
- _logger.info("Running test with default values...");
- }
-
- String brokerDetails = config.getHost() + ":" + config.getPort();
- String virtualpath = "/test";
- boolean verbose = true;
- boolean transacted = config.isTransacted();
- boolean persistent = config.usePersistentMessages();
- int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE;
- int messageCount = config.getMessages();
- int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT;
- int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE;
- int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE;
- boolean pubsub = config.isPubSub();
-
- String destName = config.getDestination();
- if (destName == null)
- {
- destName = PING_DESTINATION_NAME;
- }
-
- boolean afterCommit = false;
- boolean beforeCommit = false;
- boolean afterSend = false;
- boolean beforeSend = false;
- boolean failOnce = false;
-
- for (String arg : args)
- {
- if (arg.startsWith("failover:"))
- {
- //failover:<before|after>:<send:commit>
- String[] parts = arg.split(":");
- if (parts.length == 3)
- {
- if (parts[2].equals("commit"))
- {
- afterCommit = parts[1].equals("after");
- beforeCommit = parts[1].equals("before");
- }
-
- if (parts[2].equals("send"))
- {
- afterSend = parts[1].equals("after");
- beforeSend = parts[1].equals("before");
- }
-
- if (parts[1].equals("once"))
- {
- failOnce = true;
- }
-
- }
- else
- {
- System.out.println("Unrecognized failover request:" + arg);
- }
- }
- }
-
- // Create a ping producer to handle the request/wait/reply cycle.
- TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, destName, null,
- transacted, persistent, messageSize, verbose, afterCommit,
- beforeCommit, afterSend, beforeSend, failOnce, batchSize,
- destCount, rate, pubsub);
-
- pingItself.getConnection().start();
-
- // Create a shutdown hook to terminate the ping-pong producer.
- Runtime.getRuntime().addShutdownHook(pingItself.getShutdownHook());
-
- // Ensure that the ping pong producer is registered to listen for exceptions on the connection too.
- pingItself.getConnection().setExceptionListener(pingItself);
-
- if ((destCount > DEFAULT_DESTINATION_COUNT) || (messageCount > 0))
- {
- _logger.info("Destinations Count:" + destCount + ", Transacted:" + transacted + ", persistent:" +
- persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub);
- pingItself.pingLoop();
- }
- else
- {
- _logger.info("Destination:" + destName + ", Transacted:" + transacted + ", persistent:" +
- persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub);
- // set the message count to 0 to run this loop
- // Run a few priming pings to remove warm up time from test results.
- pingItself.prime(PRIMING_LOOPS);
-
- _logger.info("Running the infinite loop and pinging the broker...");
- // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception.
- Thread pingThread = new Thread(pingItself);
- pingThread.run();
- pingThread.join();
- }
-
- pingItself.getConnection().close();
- }
-
- private static void usage()
- {
- System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" +
- "-destinationname : queue/topic name\n" +
- "-transacted : (true/false). Default is false\n" +
- "-persistent : (true/false). Default is false\n" +
- "-pubsub : (true/false). Default is false\n" +
- "-selector : selector string\n" +
- "-payload : paylaod size. Default is 0\n" +
- "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" +
- "-destinationscount : no of destinations for multi-destinations test\n" +
- "-batchsize : batch size\n" +
- "-rate : thruput rate\n");
- System.exit(0);
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java
deleted file mode 100644
index d9e81d39de..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java
+++ /dev/null
@@ -1,249 +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.ping;
-
-import java.net.InetAddress;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import javax.jms.*;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.jms.MessageProducer;
-import org.apache.qpid.jms.Session;
-
-/**
- * PingProducer is a client that sends timestamped pings to a queue. It is designed to be run from the command line
- * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session and
- * configured message producer.
- * <p/>
- * <p/>This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop
- * does all its work through helper methods, so that code wishing to run a ping cycle is not forced to do so
- * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is
- * also registered to terminate the ping loop cleanly.
- * <p/>
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide a ping cycle.
- * <tr><td> Provide command line invocation to loop the ping cycle on a configurable broker url.
- * </table>
- */
-class TestPingProducer extends AbstractPingProducer
-{
- private static final Logger _logger = Logger.getLogger(TestPingProducer.class);
-
- /**
- * Used to set up a default message size.
- */
- private static final int DEFAULT_MESSAGE_SIZE = 0;
-
- /**
- * Used to define how long to wait between pings.
- */
- private static final long SLEEP_TIME = 250;
-
- /**
- * Holds the name of the queue to send pings on.
- */
- private static final String PING_QUEUE_NAME = "ping";
-
- private static TestPingProducer _pingProducer;
-
- /**
- * Determines whether this producer sends persistent messages from the run method.
- */
- private boolean _persistent = false;
-
- /**
- * Holds the message size to send, from the run method.
- */
- private int _messageSize = DEFAULT_MESSAGE_SIZE;
-
- /**
- * Used to indicate that the ping loop should print out whenever it pings.
- */
- private boolean _verbose = false;
-
- public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName,
- boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit,
- boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize)
- throws Exception
- {
- // Create a connection to the broker.
- InetAddress address = InetAddress.getLocalHost();
- String clientID = address.getHostName() + System.currentTimeMillis();
-
- setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath));
-
- // Create a transactional or non-transactional session, based on the command line arguments.
- setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE));
-
- // Create a queue to send the pings on.
- Queue pingQueue = new AMQQueue(queueName);
- _producer = (MessageProducer) getProducerSession().createProducer(pingQueue);
-
- _persistent = persistent;
- _messageSize = messageSize;
-
- _verbose = verbose;
-
- // Set failover interrupts
- _failAfterCommit = afterCommit;
- _failBeforeCommit = beforeCommit;
- _failAfterSend = afterSend;
- _failBeforeSend = beforeSend;
- _txBatchSize = batchSize;
- _failOnce = failOnce;
- }
-
- /**
- * Starts a ping-pong loop running from the command line. The bounce back client {@link TestPingClient} also needs
- * to be started to bounce the pings back again.
- *
- * @param args The command line arguments as defined above.
- */
- public static void main(String[] args) throws Exception
- {
- // Extract the command line.
- if (args.length < 2)
- {
- System.err.println(
- "Usage: TestPingPublisher <brokerDetails> <virtual path> "
- + "[<verbose(true|false)> <transacted(true|false))> <persistent(true|false)> <message size in bytes> <batchsize>");
- System.exit(0);
- }
-
- String brokerDetails = args[0];
- String virtualpath = args[1];
- boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true;
- boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false;
- boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false;
- int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE;
- int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1;
-
- boolean afterCommit = false;
- boolean beforeCommit = false;
- boolean afterSend = false;
- boolean beforeSend = false;
- boolean failOnce = false;
-
- for (String arg : args)
- {
- if (arg.startsWith("failover:"))
- {
- //failover:<before|after>:<send:commit>
- String[] parts = arg.split(":");
- if (parts.length == 3)
- {
- if (parts[2].equals("commit"))
- {
- afterCommit = parts[1].equals("after");
- beforeCommit = parts[1].equals("before");
- }
-
- if (parts[2].equals("send"))
- {
- afterSend = parts[1].equals("after");
- beforeSend = parts[1].equals("before");
- }
-
- if (parts[1].equals("once"))
- {
- failOnce = true;
- }
- }
- else
- {
- System.out.println("Unrecognized failover request:" + arg);
- }
- }
- }
-
- // Create a ping producer to generate the pings.
- _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted,
- persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend,
- beforeSend, failOnce, batchSize);
-
- // Start the connection running.
- _pingProducer.getConnection().start();
-
- // Create a shutdown hook to terminate the ping-pong producer.
- Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook());
-
- // Ensure the ping loop execption listener is registered on the connection to terminate it on error.
- _pingProducer.getConnection().setExceptionListener(_pingProducer);
-
- // Start the ping loop running until it is interrupted.
- Thread pingThread = new Thread(_pingProducer);
- pingThread.run();
- pingThread.join();
- }
-
- /**
- * Sends the specified ping message.
- *
- * @param message The message to send.
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- */
- public void ping(Message message) throws JMSException
- {
- sendMessage(message);
-
- // Keep the messageId to correlate with the reply.
- String messageId = message.getJMSMessageID();
-
- // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of
- // this method, as the message will not be sent until the transaction is committed.
- commitTx();
- }
-
- /**
- * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and
- * waits for short pauses in between each.
- */
- public void pingLoop()
- {
- try
- {
- // Generate a sample message and time stamp it.
- ObjectMessage msg = getTestMessage(null, _messageSize, _persistent);
- msg.setLongProperty("timestamp", System.currentTimeMillis());
-
- // Send the message.
- ping(msg);
-
- if (_verbose)
- {
- System.out.println("Pinged at: " + timestampFormatter.format(new Date())); //" + " with id: " + msg.getJMSMessageID());
- }
- // Introduce a short pause if desired.
- pause(SLEEP_TIME);
- }
- catch (JMSException e)
- {
- _publish = false;
- _logger.error("There was a JMSException: " + e.getMessage(), e);
- }
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java
deleted file mode 100644
index 3b2dcc4d36..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java
+++ /dev/null
@@ -1,197 +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.pingpong;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.url.URLSyntaxException;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.client.BasicMessageProducer;
-import org.apache.qpid.client.message.TestMessageFactory;
-import org.apache.qpid.jms.MessageProducer;
-import org.apache.qpid.jms.Session;
-
-import javax.jms.*;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * A client that behaves as follows:
- * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li>
- * <li>Creates a temporary queue</li>
- * <li>Creates messages containing a property that is the name of the temporary queue</li>
- * <li>Fires off a message on the original queue and waits for a response on the temporary queue</li>
- * </ul>
- */
-public class TestPingPublisher implements ExceptionListener
-{
- private static final Logger _log = Logger.getLogger(TestPingPublisher.class);
-
- private AMQConnection _connection;
-
- private boolean _publish;
- private static int _messageSize = 0;
- private long SLEEP_TIME = 0L;
-
-// private class CallbackHandler implements MessageListener
-// {
-//
-// private int _actualMessageCount;
-//
-//
-// public void onMessage(Message m)
-// {
-// if (_log.isDebugEnabled())
-// {
-// _log.debug("Message received: " + m);
-// }
-// _actualMessageCount++;
-// if (_actualMessageCount % 1000 == 0)
-// {
-// _log.info("Received message count: " + _actualMessageCount);
-// }
-// }
-// }
-
- public TestPingPublisher(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException
- {
- try
- {
- createConnection(brokerDetails, clientID, virtualpath);
-
- Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- //AMQQueue destination = new AMQQueue("ping");
- AMQTopic destination = new AMQTopic("ping");
- MessageProducer producer = (MessageProducer) session.createProducer(destination);
-
- _connection.setExceptionListener(this);
-
- _connection.start();
-
- int msgCount = 0;
- while (_publish)
- {
-/*
- TextMessage msg = session.createTextMessage(
- "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber);
-*/
- ObjectMessage msg = null;
- if (_messageSize != 0)
- {
- msg = TestMessageFactory.newObjectMessage(session, _messageSize);
- }
- else
- {
- msg = session.createObjectMessage();
- }
-
- Long time = System.nanoTime();
- msg.setStringProperty("timestampString", Long.toString(time));
- msg.setLongProperty("timestamp", time);
-
- ((BasicMessageProducer) producer).send(msg, DeliveryMode.PERSISTENT, true);
-
- _log.info("Message Sent:" + msgCount++);
- _log.debug(msg);
-
- if (msgCount == Integer.MAX_VALUE)
- {
- _publish = false;
- }
-
- if (SLEEP_TIME > 0)
- {
- try
- {
- Thread.sleep(SLEEP_TIME);
- }
- catch (InterruptedException ie)
- {
- //do nothing
- }
- }
- }
-
- }
- catch (JMSException e)
- {
- e.printStackTrace();
- }
- }
-
- private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException
- {
- _publish = true;
- _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath);
- _log.info("Connected with URL:" + _connection.toURL());
- }
-
- /**
- * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank
- * means the server will allocate a name.
- */
- public static void main(String[] args)
- {
- if (args.length < 2)
- {
- System.err.println("Usage: TestPingPublisher <brokerDetails> <virtual path> [message size in bytes]");
- System.exit(0);
- }
- try
- {
- InetAddress address = InetAddress.getLocalHost();
- String clientID = address.getHostName() + System.currentTimeMillis();
- if (args.length > 2 )
- {
- _messageSize = Integer.parseInt(args[2]);
- }
- new TestPingPublisher(args[0], clientID, args[1]);
- }
- catch (UnknownHostException e)
- {
- e.printStackTrace();
- }
- catch (AMQException e)
- {
- System.err.println("Error in client: " + e);
- e.printStackTrace();
- }
- catch (URLSyntaxException e)
- {
- System.err.println("Error in connection arguments : " + e);
- }
-
- //System.exit(0);
- }
-
- /**
- * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException)
- */
- public void onException(JMSException e)
- {
- System.err.println(e.getMessage());
-
- _publish = false;
- e.printStackTrace(System.err);
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java
deleted file mode 100644
index b43319744a..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java
+++ /dev/null
@@ -1,134 +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.pingpong;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.Level;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.jms.Session;
-
-import javax.jms.MessageConsumer;
-import javax.jms.MessageListener;
-import javax.jms.Topic;
-import javax.jms.JMSException;
-import java.net.InetAddress;
-
-public class TestPingSubscriber
-{
- private static final Logger _logger = Logger.getLogger(TestPingSubscriber.class);
-
- private static class TestPingMessageListener implements MessageListener
- {
- public TestPingMessageListener()
- {
- }
-
- long _lastTimestamp = 0L;
- long _lastTimestampString = 0L;
-
- public void onMessage(javax.jms.Message message)
- {
- Long time = System.nanoTime();
-
- if (_logger.isInfoEnabled())
- {
- long timestampString = 0L;
-
- try
- {
- long timestamp = message.getLongProperty("timestamp");
- timestampString = Long.parseLong(message.getStringProperty("timestampString"));
-
- if (timestampString != timestamp)
- {
- _logger.info("Timetamps differ!:\n" +
- "timestamp:" + timestamp + "\n" +
- "timestampString:" + timestampString);
- }
-
- }
- catch (JMSException jmse)
- {
- _logger.error("JMSException caught:" + jmse.getMessage(), jmse);
- }
-
-
- long stringDiff = time - timestampString;
-
- _logger.info("Ping: TS:" + stringDiff / 1000 + "us");
-
- // _logger.info(_name + " got message '" + message + "\n");
- }
- }
- }
-
- public static void main(String[] args)
- {
- _logger.info("Starting...");
-
- if (args.length < 4)
- {
- System.out.println("Usage: brokerdetails username password virtual-path [selector] ");
- System.exit(1);
- }
- try
- {
- InetAddress address = InetAddress.getLocalHost();
- AMQConnection con1 = new AMQConnection(args[0], args[1], args[2],
- address.getHostName(), args[3]);
-
- _logger.info("Connected with URL:" + con1.toURL());
-
- final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session)
- con1.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
-
- String selector = null;
-
- if (args.length == 5)
- {
- selector = args[4];
- _logger.info("Message selector is <" + selector + ">...");
- }
- else
- {
- _logger.info("Not using message selector ");
- }
-
- Topic t = new AMQTopic("ping");
-
- MessageConsumer consumer1 = session1.createConsumer(t,
- 1, false, false, selector);
-
- consumer1.setMessageListener(new TestPingMessageListener());
- con1.start();
- }
- catch (Throwable t)
- {
- System.err.println("Fatal error: " + t);
- t.printStackTrace();
- }
-
- System.out.println("Waiting...");
- }
-}
-
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java
deleted file mode 100644
index 1e98e45bba..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.apache.qpid.ping;
-
-/**
- * Throttle is a helper class used in situations where a controlled rate of processing is desired. It allows a certain
- * number of operations-per-second to be defined and supplies a {@link #throttle} method that can only be called at
- * most at that rate. The first call to the throttle method will return immediately, subsequent calls will introduce
- * a short pause to fill out the remainder of the current cycle to attain the desired rate. If there is no remainder
- * left then it will return immediately.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- *
- * @author Rupert Smith
- */
-public class Throttle
-{
- /** Holds the length of the cycle in nano seconds. */
- long cycleLengthNanos = 0L;
-
- /** Records the nano time of the last call to the throttle method. */
- long lastTimeNanos = 0L;
-
- /**
- * Sets up the desired rate of operation per second that the throttle method should restrict to.
- *
- * @param opsPerSecond The maximum number of calls per second that the throttle method will take.
- */
- public void setRate(int opsPerSecond)
- {
- // Calculate the length of a cycle.
- cycleLengthNanos = 1000000000 / opsPerSecond;
- }
-
- /**
- * Introduces a short pause to fill out any time left in the cycle since this method was last called, of length
- * defined by a call to the {@link #setRate} method.
- */
- public void throttle()
- {
- // Record the time now.
- long currentTimeNanos = System.nanoTime();
-
- // Check if there is any time remaining in the current cycle and introduce a short wait to fill out the
- // remainder of the cycle if needed.
- long remainingTimeNanos = cycleLengthNanos - (currentTimeNanos - lastTimeNanos);
-
- if (remainingTimeNanos > 0)
- {
- long milliWait = remainingTimeNanos / 1000000;
- int nanoWait = (int) (remainingTimeNanos % 1000000);
-
- try
- {
- Thread.currentThread().sleep(milliWait, nanoWait);
- }
- catch (InterruptedException e)
- {
- // Just ignore this?
- }
- }
-
- // Keep the time of the last call to this method to calculate the next cycle.
- //lastTimeNanos = currentTimeNanos;
- lastTimeNanos = System.nanoTime();
- }
-}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
index bae6aa0dc2..ab795d0459 100644
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java
@@ -20,7 +20,9 @@
*/
package org.apache.qpid.requestreply;
+import java.io.IOException;
import java.net.InetAddress;
+import java.text.SimpleDateFormat;
import java.util.Date;
import javax.jms.*;
@@ -32,7 +34,6 @@ import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQTopic;
import org.apache.qpid.jms.ConnectionListener;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.ping.AbstractPingClient;
import org.apache.qpid.topic.Config;
/**
@@ -58,7 +59,7 @@ import org.apache.qpid.topic.Config;
*
* @todo Make verbose accept a number of messages, only prints to console every X messages.
*/
-public class PingPongBouncer extends AbstractPingClient implements MessageListener
+public class PingPongBouncer implements MessageListener
{
private static final Logger _logger = Logger.getLogger(PingPongBouncer.class);
@@ -73,6 +74,9 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
/** The default exclusive flag for the message consumer. */
private static final boolean EXCLUSIVE = false;
+ /** A convenient formatter to use when time stamping output. */
+ protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
+
/** Used to indicate that the reply generator should log timing info to the console (logger info level). */
private boolean _verbose = false;
@@ -93,6 +97,24 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
/** The producer session. */
private Session _producerSession;
+ /** Holds the connection to the broker. */
+ private AMQConnection _connection;
+
+ /** Flag used to indicate if this is a point to point or pub/sub ping client. */
+ private boolean _isPubSub = false;
+
+ /**
+ * This flag is used to indicate that the user should be prompted to kill a broker, in order to test
+ * failover, immediately before committing a transaction.
+ */
+ protected boolean _failBeforeCommit = false;
+
+ /**
+ * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test
+ * failover, immediate after committing a transaction.
+ */
+ protected boolean _failAfterCommit = false;
+
/**
* Creates a PingPongBouncer on the specified producer and consumer sessions.
*
@@ -110,8 +132,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
* @throws Exception All underlying exceptions allowed to fall through. This is only test code...
*/
public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath,
- String destinationName, boolean persistent, boolean transacted, String selector,
- boolean verbose, boolean pubsub) throws Exception
+ String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose,
+ boolean pubsub) throws Exception
{
// Create a client id to uniquely identify this client.
InetAddress address = InetAddress.getLocalHost();
@@ -133,7 +155,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
// Create the queue to listen for message on.
createConsumerDestination(destinationName);
- MessageConsumer consumer = _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector);
+ MessageConsumer consumer =
+ _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector);
// Create a producer for the replies, without a default destination.
_replyProducer = _producerSession.createProducer(null);
@@ -144,18 +167,6 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
consumer.setMessageListener(this);
}
- private void createConsumerDestination(String name)
- {
- if (isPubSub())
- {
- _consumerDestination = new AMQTopic(name);
- }
- else
- {
- _consumerDestination = new AMQQueue(name);
- }
- }
-
/**
* Starts a stand alone ping-pong client running in verbose mode.
*
@@ -177,12 +188,13 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
Config config = new Config();
config.setOptions(args);
String brokerDetails = config.getHost() + ":" + config.getPort();
- String virtualpath = "/test";
+ String virtualpath = "test";
String destinationName = config.getDestination();
if (destinationName == null)
{
destinationName = DEFAULT_DESTINATION_NAME;
}
+
String selector = config.getSelector();
boolean transacted = config.isTransacted();
boolean persistent = config.usePersistentMessages();
@@ -192,13 +204,22 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
//String selector = null;
// Instantiate the ping pong client with the command line options and start it running.
- PingPongBouncer pingBouncer = new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath,
- destinationName, persistent, transacted, selector, verbose, pubsub);
+ PingPongBouncer pingBouncer =
+ new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted,
+ selector, verbose, pubsub);
pingBouncer.getConnection().start();
System.out.println("Waiting...");
}
+ private static void usage()
+ {
+ System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n"
+ + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n"
+ + "-persistent : (true/false). Default is false\n"
+ + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n");
+ }
+
/**
* This is a callback method that is notified of all messages for which this has been registered as a message
* listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to
@@ -260,14 +281,145 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen
}
}
- private static void usage()
+ /**
+ * Gets the underlying connection that this ping client is running on.
+ *
+ * @return The underlying connection that this ping client is running on.
+ */
+ public AMQConnection getConnection()
+ {
+ return _connection;
+ }
+
+ /**
+ * Sets the connection that this ping client is using.
+ *
+ * @param connection The ping connection.
+ */
+ public void setConnection(AMQConnection connection)
+ {
+ this._connection = connection;
+ }
+
+ /**
+ * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic.
+ *
+ * @param pubsub <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
+ */
+ public void setPubSub(boolean pubsub)
+ {
+ _isPubSub = pubsub;
+ }
+
+ /**
+ * Checks whether this client is a p2p or pub/sub ping client.
+ *
+ * @return <tt>true</tt> if this client is pinging a topic, <tt>false</tt> if it is pinging a queue.
+ */
+ public boolean isPubSub()
+ {
+ return _isPubSub;
+ }
+
+ /**
+ * Convenience method to commit the transaction on the specified session. If the session to commit on is not
+ * a transactional session, this method does nothing.
+ *
+ * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
+ * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
+ * after the commit is applied.
+ *
+ * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
+ */
+ protected void commitTx(Session session) throws JMSException
+ {
+ if (session.getTransacted())
+ {
+ try
+ {
+ if (_failBeforeCommit)
+ {
+ _logger.trace("Failing Before Commit");
+ doFailover();
+ }
+
+ session.commit();
+
+ if (_failAfterCommit)
+ {
+ _logger.trace("Failing After Commit");
+ doFailover();
+ }
+
+ _logger.trace("Session Commited.");
+ }
+ catch (JMSException e)
+ {
+ _logger.trace("JMSException on commit:" + e.getMessage(), e);
+
+ try
+ {
+ session.rollback();
+ _logger.debug("Message rolled back.");
+ }
+ catch (JMSException jmse)
+ {
+ _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
+
+ // Both commit and rollback failed. Throw the rollback exception.
+ throw jmse;
+ }
+ }
+ }
+ }
+
+ /**
+ * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block
+ * until the user supplied some input on the terminal.
+ *
+ * @param broker The name of the broker to terminate.
+ */
+ protected void doFailover(String broker)
+ {
+ System.out.println("Kill Broker " + broker + " now.");
+ try
+ {
+ System.in.read();
+ }
+ catch (IOException e)
+ { }
+
+ System.out.println("Continuing.");
+ }
+
+ /**
+ * Prompts the user to terminate the broker, in order to test failover functionality. This method will block
+ * until the user supplied some input on the terminal.
+ */
+ protected void doFailover()
{
- System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" +
- "-destinationname : queue/topic name\n" +
- "-transacted : (true/false). Default is false\n" +
- "-persistent : (true/false). Default is false\n" +
- "-pubsub : (true/false). Default is false\n" +
- "-selector : selector string\n");
+ System.out.println("Kill Broker now.");
+ try
+ {
+ System.in.read();
+ }
+ catch (IOException e)
+ { }
+
+ System.out.println("Continuing.");
+
+ }
+
+ private void createConsumerDestination(String name)
+ {
+ if (isPubSub())
+ {
+ _consumerDestination = new AMQTopic(name);
+ }
+ else
+ {
+ _consumerDestination = new AMQQueue(name);
+ }
}
/**
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
index 263e62cf04..8def95f7b1 100644
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
+++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java
@@ -20,12 +20,14 @@
*/
package org.apache.qpid.requestreply;
+import java.io.IOException;
import java.net.InetAddress;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.jms.*;
@@ -33,25 +35,30 @@ import javax.jms.*;
import org.apache.log4j.Logger;
import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQNoConsumersException;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.client.message.TestMessageFactory;
import org.apache.qpid.jms.MessageProducer;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.ping.AbstractPingProducer;
-import org.apache.qpid.ping.Throttle;
import org.apache.qpid.topic.Config;
+import uk.co.thebadgerset.junit.extensions.BatchedThrottle;
+import uk.co.thebadgerset.junit.extensions.Throttle;
+
/**
* PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back
- * client (see {@link PingPongBouncer} for the bounce back client). It is designed to be run from the command line
- * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session,
- * message producer and message consumer to run the ping-pong cycle on.
+ * client (see {@link PingPongBouncer} for the bounce back client).
* <p/>
* <p/>The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings.
* This means that this class has to do some work to correlate pings with pongs; it expectes the original message
- * id in the ping to be bounced back in the correlation id. If a new temporary queue per ping were used, then
- * this correlation would not need to be done.
+ * correlation id in the ping to be bounced back in the reply correlation id.
+ * <p/>
+ * <p/>This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor.
+ * It can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings
+ * within transactions; control the number of pings to send in each transaction; limit its sending rate; and perform
+ * failover testing.
* <p/>
* <p/>This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop
* does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so
@@ -60,85 +67,265 @@ import org.apache.qpid.topic.Config;
* <p/>
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide a ping and wait for response cycle.
+ * <tr><td> Provide a ping and wait for all responses cycle.
* <tr><td> Provide command line invocation to loop the ping cycle on a configurable broker url.
* </table>
*
- * @todo Make temp queue per ping a command line option.
- * @todo Make the queue name a command line option.
+ * @todo The use of a ping rate {@link #DEFAULT_RATE} and waits between pings {@link #DEFAULT_SLEEP_TIME} are overlapping.
+ * Use the rate and throttling only. Ideally, optionally pass the rate throttle into the ping method, throttle to
+ * be created and configured by the test runner from the -f command line option and made available through
+ * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware
+ * tests.
+ * @todo Make acknowledege mode a test option.
+ * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than
+ * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process
+ * messages concurrently for different ids. Needs to be static so that when using a chained message listener and
+ * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to
+ * be picked up by the PPP that it is atteched to.
+ * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock
+ * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message
+ * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means
+ * that the last message waits until all other messages have been handled before releasing producers but allows
+ * messages to be processed concurrently, unlike the current synchronized block.
+ * @todo Need to multiply up the number of expected messages for pubsub tests as each can be received by many consumers?
*/
-public class PingPongProducer extends AbstractPingProducer implements Runnable, MessageListener, ExceptionListener
+public class PingPongProducer implements Runnable, MessageListener, ExceptionListener
{
private static final Logger _logger = Logger.getLogger(PingPongProducer.class);
/**
+ * Holds the name of the property to get the test message size from.
+ */
+ public static final String MESSAGE_SIZE_PROPNAME = "messagesize";
+
+ /**
+ * Holds the name of the property to get the ping queue name from.
+ */
+ public static final String PING_QUEUE_NAME_PROPNAME = "destinationname";
+
+ /**
+ * Holds the name of the property to get the test delivery mode from.
+ */
+ public static final String PERSISTENT_MODE_PROPNAME = "persistent";
+
+ /**
+ * Holds the name of the property to get the test transactional mode from.
+ */
+ public static final String TRANSACTED_PROPNAME = "transacted";
+
+ /**
+ * Holds the name of the property to get the test broker url from.
+ */
+ public static final String BROKER_PROPNAME = "broker";
+
+ /**
+ * Holds the name of the property to get the test broker virtual path.
+ */
+ public static final String VIRTUAL_PATH_PROPNAME = "virtualPath";
+
+ /**
+ * Holds the name of the property to get the message rate from.
+ */
+ public static final String RATE_PROPNAME = "rate";
+
+ public static final String VERBOSE_OUTPUT_PROPNAME = "verbose";
+
+ /**
+ * Holds the true or false depending on wether it is P2P test or PubSub
+ */
+ public static final String IS_PUBSUB_PROPNAME = "pubsub";
+
+ public static final String FAIL_AFTER_COMMIT_PROPNAME = "FailAfterCommit";
+
+ public static final String FAIL_BEFORE_COMMIT_PROPNAME = "FailBeforeCommit";
+
+ public static final String FAIL_AFTER_SEND_PROPNAME = "FailAfterSend";
+
+ public static final String FAIL_BEFORE_SEND_PROPNAME = "FailBeforeSend";
+
+ public static final String FAIL_ONCE_PROPNAME = "FailOnce";
+
+ public static final String USERNAME_PROPNAME = "username";
+
+ public static final String PASSWORD_PROPNAME = "password";
+
+ public static final String SELECTOR_PROPNAME = "selector";
+
+ public static final String PING_DESTINATION_COUNT_PROPNAME = "destinationscount";
+
+ /**
+ * Holds the name of the property to get the waiting timeout for response messages.
+ */
+ public static final String TIMEOUT_PROPNAME = "timeout";
+
+ public static final String COMMIT_BATCH_SIZE_PROPNAME = "CommitBatchSize";
+
+ public static final String UNIQUE_PROPNAME = "uniqueDests";
+
+ /**
* Used to set up a default message size.
*/
- protected static final int DEFAULT_MESSAGE_SIZE = 0;
+ public static final int DEFAULT_MESSAGE_SIZE = 0;
+
+ /**
+ * Holds the name of the default destination to send pings on.
+ */
+ public static final String DEFAULT_PING_DESTINATION_NAME = "ping";
/**
- * This is set and used when the test is for multiple-destinations
+ * Defines the default number of destinations to ping.
*/
- protected static final int DEFAULT_DESTINATION_COUNT = 0;
+ public static final int DEFAULT_DESTINATION_COUNT = 1;
- protected static final int DEFAULT_RATE = 0;
+ /**
+ * Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction.
+ */
+ public static final int DEFAULT_RATE = 0;
/**
- * Used to define how long to wait between pings.
+ * Defines the default wait between pings.
*/
- protected static final long SLEEP_TIME = 250;
+ public static final long DEFAULT_SLEEP_TIME = 250;
/**
- * Used to define how long to wait before assuming that a ping has timed out.
+ * Default time to wait before assuming that a ping has timed out.
*/
- protected static final long TIMEOUT = 9000;
+ public static final long DEFAULT_TIMEOUT = 30000;
/**
- * Holds the name of the destination to send pings on.
+ * Defines the default number of pings to send in each transaction when running transactionally.
*/
- protected static final String PING_DESTINATION_NAME = "ping";
+ public static final int DEFAULT_TX_BATCH_SIZE = 100;
/**
- * The batch size.
+ * Defines the default prefetch size to use when consuming messages.
*/
- protected static final int DEFAULT_BATCH_SIZE = 100;
+ public static final int DEFAULT_PREFETCH = 100;
- protected static final int PREFETCH = 100;
- protected static final boolean NO_LOCAL = true;
- protected static final boolean EXCLUSIVE = false;
+ /**
+ * Defines the default value of the no local flag to use when consuming messages.
+ */
+ public static final boolean DEFAULT_NO_LOCAL = false;
/**
- * The number of priming loops to run.
+ * Defines the default value of the exclusive flag to use when consuming messages.
*/
- protected static final int PRIMING_LOOPS = 3;
+ public static final boolean DEFAULT_EXCLUSIVE = false;
/**
- * A source for providing sequential unique correlation ids.
+ * Holds the message delivery mode to use for the test.
*/
- private static AtomicLong idGenerator = new AtomicLong(0L);
+ public static final boolean DEFAULT_PERSISTENT_MODE = false;
/**
- * Holds a map from message ids to latches on which threads wait for replies.
+ * Holds the transactional mode to use for the test.
*/
- private static Map<String, CountDownLatch> trafficLights = new HashMap<String, CountDownLatch>();
+ public static final boolean DEFAULT_TRANSACTED = false;
/**
- * Destination where the responses messages will arrive
+ * Holds the default broker url for the test.
*/
- private Destination _replyDestination;
+ public static final String DEFAULT_BROKER = "tcp://localhost:5672";
+
+ /**
+ * Holds the default virtual path for the test.
+ */
+ public static final String DEFAULT_VIRTUAL_PATH = "test";
+
+ /**
+ * Holds the pub/sub mode default, true means ping a topic, false means ping a queue.
+ */
+ public static final boolean DEFAULT_PUBSUB = false;
+
+ /**
+ * Holds the default broker log on username.
+ */
+ public static final String DEFAULT_USERNAME = "guest";
+
+ /**
+ * Holds the default broker log on password.
+ */
+ public static final String DEFAULT_PASSWORD = "guest";
+
+ /**
+ * Holds the default message selector.
+ */
+ public static final String DEFAULT_SELECTOR = null;
+
+ /**
+ * Holds the default failover after commit test flag.
+ */
+ public static final String DEFAULT_FAIL_AFTER_COMMIT = "false";
+
+ /**
+ * Holds the default failover before commit test flag.
+ */
+ public static final String DEFAULT_FAIL_BEFORE_COMMIT = "false";
+
+ /**
+ * Holds the default failover after send test flag.
+ */
+ public static final String DEFAULT_FAIL_AFTER_SEND = "false";
+
+ /**
+ * Holds the default failover before send test flag.
+ */
+ public static final String DEFAULT_FAIL_BEFORE_SEND = "false";
+
+ /**
+ * Holds the default failover only once flag, true means only do one failover, false means failover on every commit cycle.
+ */
+ public static final String DEFAULT_FAIL_ONCE = "true";
+
+ /**
+ * Holds the default verbose mode.
+ */
+ public static final boolean DEFAULT_VERBOSE = false;
+
+ public static final boolean DEFAULT_UNIQUE = true;
+
+ /**
+ * Holds the name of the property to store nanosecond timestamps in ping messages with.
+ */
+ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp";
+
+ /**
+ * A source for providing sequential unique correlation ids. These will be unique within the same JVM.
+ */
+ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L);
+
+ /**
+ * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross
+ * multiple ping producers on the same JVM.
+ */
+ /*private static Map<String, CountDownLatch> trafficLights =
+ Collections.synchronizedMap(new HashMap<String, CountDownLatch>());*/
+ private static Map<String, PerCorrelationId> perCorrelationIds =
+ Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
+
+ /**
+ * A convenient formatter to use when time stamping output.
+ */
+ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS");
+
+ /**
+ * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when
+ * creating multiple ping producers in the same JVM.
+ */
+ protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger();
/**
- * Destination where the producer will be sending message to
+ * Destination where the response messages will arrive.
*/
- private Destination _pingDestination;
+ private Destination _replyDestination;
/**
- * Determines whether this producer sends persistent messages from the run method.
+ * Determines whether this producer sends persistent messages.
*/
protected boolean _persistent;
/**
- * Holds the message size to send, from the run method.
+ * Determines what size of messages this producer sends.
*/
protected int _messageSize;
@@ -147,217 +334,194 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
*/
protected boolean _verbose = false;
+ /**
+ * Holds the session on which ping replies are received.
+ */
protected Session _consumerSession;
/**
* Used to restrict the sending rate to a specified limit.
*/
- private Throttle rateLimiter = null;
+ private Throttle _rateLimiter = null;
/**
- * The throttler can only reliably restrict to a few hundred cycles per second, so a throttling batch size is used
- * to group sends together into batches large enough that the throttler runs slower than that.
+ * Holds a message listener that this message listener chains all its messages to.
*/
- int _throttleBatchSize;
+ private ChainedMessageListener _chainedMessageListener = null;
- private MessageListener _messageListener = null;
+ /**
+ * Flag used to indicate if this is a point to point or pub/sub ping client.
+ */
+ protected boolean _isPubSub = false;
- private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted,
- boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit,
- boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate)
- throws Exception
- {
- // Create a connection to the broker.
- InetAddress address = InetAddress.getLocalHost();
- String clientID = address.getHostName() + System.currentTimeMillis();
+ /**
+ * Flag used to indicate if the destinations should be unique client.
+ */
+ protected static boolean _isUnique = false;
- setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath));
+ /**
+ * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers
+ * on the same JVM using this id generator will allow them to ping on the same queues.
+ */
+ protected AtomicInteger _queueSharedId = new AtomicInteger();
- // Create transactional or non-transactional sessions, based on the command line arguments.
- setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE));
- _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
+ /**
+ * Used to tell the ping loop when to terminate, it only runs while this is true.
+ */
+ protected boolean _publish = true;
- _persistent = persistent;
- _messageSize = messageSize;
- _verbose = verbose;
+ /**
+ * Holds the connection to the broker.
+ */
+ private Connection _connection;
- // Set failover interrupts
- _failAfterCommit = afterCommit;
- _failBeforeCommit = beforeCommit;
- _failAfterSend = afterSend;
- _failBeforeSend = beforeSend;
- _failOnce = failOnce;
- _txBatchSize = batchSize;
-
- // Calculate a throttling batch size and rate such that the throttle runs slower than 100 cycles per second
- // and batched sends within each cycle multiply up to give the desired rate.
- //
- // total rate = throttle rate * batch size.
- // 1 < throttle rate < 100
- // 1 < total rate < 20000
- if (rate > DEFAULT_RATE)
- {
- // Log base 10 over 2 is used here to get a feel for what power of 100 the total rate is.
- // As the total rate goes up the powers of 100 the batch size goes up by powers of 100 to keep the
- // throttle rate back into the range 1 to 100.
- int x = (int) (Math.log10(rate) / 2);
- _throttleBatchSize = (int) Math.pow(100, x);
- int throttleRate = rate / _throttleBatchSize;
-
- _logger.debug("rate = " + rate);
- _logger.debug("x = " + x);
- _logger.debug("_throttleBatchSize = " + _throttleBatchSize);
- _logger.debug("throttleRate = " + throttleRate);
-
- rateLimiter = new Throttle();
- rateLimiter.setRate(throttleRate);
- }
- }
+ /**
+ * Holds the producer session, needed to create ping messages.
+ */
+ private Session _producerSession;
/**
- * Creates a ping pong producer with the specified connection details and type.
- *
- * @param brokerDetails
- * @param username
- * @param password
- * @param virtualpath
- * @param transacted
- * @throws Exception All allowed to fall through. This is only test code...
+ * Holds the set of destiniations that this ping producer pings.
*/
- public PingPongProducer(String brokerDetails, String username, String password, String virtualpath,
- String destinationName, String selector, boolean transacted, boolean persistent,
- int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit,
- boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize,
- int noOfDestinations, int rate, boolean pubsub) throws Exception
- {
- this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit,
- beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate);
+ protected List<Destination> _pingDestinations = new ArrayList<Destination>();
- _destinationCount = noOfDestinations;
- setPubSub(pubsub);
+ /**
+ * Holds the message producer to send the pings through.
+ */
+ protected MessageProducer _producer;
- if (noOfDestinations == DEFAULT_DESTINATION_COUNT)
- {
- if (destinationName != null)
- {
- createPingDestination(destinationName);
- // Create producer and the consumer
- createProducer();
- createConsumer(selector);
- }
- else
- {
- _logger.error("Destination is not specified");
- throw new IllegalArgumentException("Destination is not specified");
- }
- }
- }
+ /**
+ * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit.
+ */
+ protected boolean _failBeforeCommit = false;
- private void createPingDestination(String name)
- {
- if (isPubSub())
- {
- _pingDestination = new AMQTopic(name);
- }
- else
- {
- _pingDestination = new AMQQueue(name);
- }
- }
+ /**
+ * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit.
+ */
+ protected boolean _failAfterCommit = false;
/**
- * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer
- * is created with null destination, so that any destination can be specified while sending
- *
- * @throws JMSException
+ * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send.
*/
- public void createProducer() throws JMSException
- {
- if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT)
- {
- // create producer with initial destination as null for test with multiple-destinations
- // In this case, a different destination will be used while sending the message
- _producer = (MessageProducer) getProducerSession().createProducer(null);
- }
- else
- {
- // Create a producer with known destination to send the pings on.
- _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination);
+ protected boolean _failBeforeSend = false;
- }
+ /**
+ * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send.
+ */
+ protected boolean _failAfterSend = false;
- _producer.setDisableMessageTimestamp(true);
- _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
- }
+ /**
+ * Flag used to indicate that failover prompting should only be done on the first commit, not on every commit.
+ */
+ protected boolean _failOnce = true;
/**
- * Creates the temporary destination to listen to the responses
- *
- * @param selector
- * @throws JMSException
+ * Holds the number of sends that should be performed in every transaction when using transactions.
*/
- public void createConsumer(String selector) throws JMSException
- {
- // Create a temporary destination to get the pongs on.
- if (isPubSub())
- {
- _replyDestination = _consumerSession.createTemporaryTopic();
- }
- else
- {
- _replyDestination = _consumerSession.createTemporaryQueue();
- }
+ protected int _txBatchSize = 1;
- // Create a message consumer to get the replies with and register this to be called back by it.
- MessageConsumer consumer = _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector);
- consumer.setMessageListener(this);
- }
+ /**
+ * Holds the number of consumers that will be attached to each topic.
+ * Each pings will result in a reply from each of the attached clients
+ */
+ static int _consumersPerTopic = 1;
/**
- * Creates consumer instances for each destination. This is used when test is being done with multiple destinations.
+ * Creates a ping producer with the specified parameters, of which there are many. See their individual comments
+ * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on it,
+ * to send and recieve its pings and replies on. The other options are kept, and control how this pinger behaves.
*
- * @param selector
- * @throws JMSException
+ * @param brokerDetails The URL of the broker to send pings to.
+ * @param username The username to log onto the broker with.
+ * @param password The password to log onto the broker with.
+ * @param virtualpath The virtual host name to use on the broker.
+ * @param destinationName The name (or root where multiple destinations are used) of the desitination to send
+ * pings to.
+ * @param selector The selector to filter replies with.
+ * @param transacted Indicates whether or not pings are sent and received in transactions.
+ * @param persistent Indicates whether pings are sent using peristent delivery.
+ * @param messageSize Specifies the size of ping messages to send.
+ * @param verbose Indicates that information should be printed to the console on every ping.
+ * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover.
+ * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover.
+ * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover.
+ * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover.
+ * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all.
+ * @param txBatchSize Specifies the number of pings to send in each transaction.
+ * @param noOfDestinations The number of destinations to ping. Must be 1 or more.
+ * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as
+ * possible, with no rate restriction.
+ * @param pubsub True to ping topics, false to ping queues.
+ * @param unique True to use unique destinations for each ping pong producer, false to share.
+ * @throws Exception Any exceptions are allowed to fall through.
*/
- public void createConsumers(String selector) throws JMSException
+ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath,
+ String destinationName, String selector, boolean transacted, boolean persistent, int messageSize,
+ boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend,
+ boolean beforeSend, boolean failOnce, int txBatchSize, int noOfDestinations, int rate,
+ boolean pubsub, boolean unique) throws Exception
{
- for (int i = 0; i < getDestinationsCount(); i++)
+ _logger.debug("public PingPongProducer(String brokerDetails = " + brokerDetails + ", String username = " + username
+ + ", String password = " + password + ", String virtualpath = " + virtualpath
+ + ", String destinationName = " + destinationName + ", String selector = " + selector
+ + ", boolean transacted = " + transacted + ", boolean persistent = " + persistent
+ + ", int messageSize = " + messageSize + ", boolean verbose = " + verbose + ", boolean afterCommit = "
+ + afterCommit + ", boolean beforeCommit = " + beforeCommit + ", boolean afterSend = " + afterSend
+ + ", boolean beforeSend = " + beforeSend + ", boolean failOnce = " + failOnce + ", int txBatchSize = "
+ + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate
+ + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + "): called");
+
+ // Keep all the relevant options.
+ _persistent = persistent;
+ _messageSize = messageSize;
+ _verbose = verbose;
+ _failAfterCommit = afterCommit;
+ _failBeforeCommit = beforeCommit;
+ _failAfterSend = afterSend;
+ _failBeforeSend = beforeSend;
+ _failOnce = failOnce;
+ _txBatchSize = txBatchSize;
+ _isPubSub = pubsub;
+ _isUnique = unique;
+
+ // Check that one or more destinations were specified.
+ if (noOfDestinations < 1)
{
- MessageConsumer consumer =
- getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector);
- consumer.setMessageListener(this);
+ throw new IllegalArgumentException("There must be at least one destination.");
}
- }
+ // Create a connection to the broker.
+ InetAddress address = InetAddress.getLocalHost();
+ String clientID = address.getHostName() + System.currentTimeMillis();
- public Session getConsumerSession()
- {
- return _consumerSession;
- }
+ _connection = new AMQConnection(brokerDetails, username, password, clientID, virtualpath);
- public Destination getPingDestination()
- {
- return _pingDestination;
- }
+ // Create transactional or non-transactional sessions, based on the command line arguments.
+ _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
+ _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE);
- protected void setPingDestination(Destination destination)
- {
- _pingDestination = destination;
+ // Set up a throttle to control the send rate, if a rate > 0 is specified.
+ if (rate > 0)
+ {
+ _rateLimiter = new BatchedThrottle();
+ _rateLimiter.setRate(rate);
+ }
+
+ // Create the temporary queue for replies.
+ _replyDestination = _consumerSession.createTemporaryQueue();
+
+ // Create the producer and the consumers for all reply destinations.
+ createProducer();
+ createPingDestinations(noOfDestinations, selector, destinationName, unique);
+ createReplyConsumers(getReplyDestinations(), selector);
}
/**
- * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs
+ * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs
* to be started to bounce the pings back again.
- * <p/>
- * <p/>The command line takes from 2 to 4 arguments:
- * <p/><table>
- * <tr><td>brokerDetails <td> The broker connection string.
- * <tr><td>virtualPath <td> The virtual path.
- * <tr><td>transacted <td> A boolean flag, telling this client whether or not to use transactions.
- * <tr><td>size <td> The size of ping messages to use, in bytes.
- * </table>
*
- * @param args The command line arguments as defined above.
+ * @param args The command line arguments.
+ * @throws Exception When something went wrong with the test
*/
public static void main(String[] args) throws Exception
{
@@ -372,22 +536,22 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
}
String brokerDetails = config.getHost() + ":" + config.getPort();
- String virtualpath = "/test";
- String selector = config.getSelector();
+ String virtualpath = "test";
+ String selector = (config.getSelector() == null) ? DEFAULT_SELECTOR : config.getSelector();
boolean verbose = true;
boolean transacted = config.isTransacted();
boolean persistent = config.usePersistentMessages();
int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE;
//int messageCount = config.getMessages();
int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT;
- int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE;
+ int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_TX_BATCH_SIZE;
int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE;
boolean pubsub = config.isPubSub();
String destName = config.getDestination();
if (destName == null)
{
- destName = PING_DESTINATION_NAME;
+ destName = DEFAULT_PING_DESTINATION_NAME;
}
boolean afterCommit = false;
@@ -429,15 +593,13 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
}
// Create a ping producer to handle the request/wait/reply cycle.
- PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath,
- destName, selector, transacted, persistent, messageSize, verbose,
- afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize,
- destCount, rate, pubsub);
+ PingPongProducer pingProducer =
+ new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector,
+ transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend,
+ beforeSend, failOnce, batchSize, destCount, rate, pubsub, false);
pingProducer.getConnection().start();
- // Run a few priming pings to remove warm up time from test results.
- //pingProducer.prime(PRIMING_LOOPS);
// Create a shutdown hook to terminate the ping-pong producer.
Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook());
@@ -450,50 +612,110 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
pingThread.join();
}
- private static void usage()
+ /**
+ * Convenience method for a short pause.
+ *
+ * @param sleepTime The time in milliseconds to pause for.
+ */
+ public static void pause(long sleepTime)
+ {
+ if (sleepTime > 0)
+ {
+ try
+ {
+ Thread.sleep(sleepTime);
+ }
+ catch (InterruptedException ie)
+ {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply
+ * to destination of this pinger.
+ *
+ * @return The single reply to destination of this pinger, wrapped in a list.
+ */
+ public List<Destination> getReplyDestinations()
+ {
+ _logger.debug("public List<Destination> getReplyDestinations(): called");
+
+ List<Destination> replyDestinations = new ArrayList<Destination>();
+ replyDestinations.add(_replyDestination);
+
+ return replyDestinations;
+ }
+
+ /**
+ * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery
+ * flag is set accoring the ping producer creation options.
+ *
+ * @throws JMSException Any JMSExceptions are allowed to fall through.
+ */
+ public void createProducer() throws JMSException
{
- System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" +
- "-destinationname : queue/topic name\n" +
- "-transacted : (true/false). Default is false\n" +
- "-persistent : (true/false). Default is false\n" +
- "-pubsub : (true/false). Default is false\n" +
- "-selector : selector string\n" +
- "-payload : paylaod size. Default is 0\n" +
- //"-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" +
- "-destinationscount : no of destinations for multi-destinations test\n" +
- "-batchsize : batch size\n" +
- "-rate : thruput rate\n");
+ _logger.debug("public void createProducer(): called");
+
+ _producer = (MessageProducer) _producerSession.createProducer(null);
+ //_producer.setDisableMessageTimestamp(true);
+ _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
}
/**
- * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client
- * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling
- * this a few times, in order to prime the JVMs JIT compilation.
+ * Creates consumers for the specified number of destinations. The destinations themselves are also created by
+ * this method.
*
- * @param x The number of priming loops to run.
- * @throws JMSException All underlying exceptions are allowed to fall through.
+ * @param noOfDestinations The number of destinations to create consumers for.
+ * @param selector The message selector to filter the consumers with.
+ * @param rootName The root of the name, or actual name if only one is being created.
+ * @param unique <tt>true</tt> to make the destinations unique to this pinger, <tt>false</tt> to share
+ * the numbering with all pingers on the same JVM.
+ * @throws JMSException Any JMSExceptions are allowed to fall through.
*/
- public void prime(int x) throws JMSException
+ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique)
+ throws JMSException
{
- for (int i = 0; i < x; i++)
+ _logger.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations
+ + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = "
+ + unique + "): called");
+
+ // Create the desired number of ping destinations and consumers for them.
+ for (int i = 0; i < noOfDestinations; i++)
{
- // Create and send a small message.
- Message first = getTestMessage(_replyDestination, 0, false);
- sendMessage(first);
+ AMQDestination destination;
- commitTx();
+ int id;
- try
+ // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag.
+ if (unique)
{
- Thread.sleep(100);
+ _logger.debug("Creating unique destinations.");
+ id = _queueJVMSequenceID.incrementAndGet();
}
- catch (InterruptedException ignore)
+ else
{
-
+ _logger.debug("Creating shared destinations.");
+ id = _queueSharedId.incrementAndGet();
}
- }
+ // Check if this is a pub/sub pinger, in which case create topics.
+ if (_isPubSub)
+ {
+ _logger.debug("Creating topics.");
+ destination = new AMQTopic(rootName + id);
+ }
+ // Otherwise this is a p2p pinger, in which case create queues.
+ else
+ {
+ _logger.debug("Creating queues.");
+ destination = new AMQQueue(rootName + id);
+ }
+ // Keep the destination.
+ _pingDestinations.add(destination);
+ }
}
/**
@@ -505,60 +727,77 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
*/
public void onMessage(Message message)
{
+ _logger.debug("public void onMessage(Message message): called");
try
{
-
- // Store the reply, if it has a correlation id that is expected.
+ // Extract the messages correlation id.
String correlationID = message.getJMSCorrelationID();
+ _logger.debug("correlationID = " + correlationID);
- if (_verbose)
+ // Countdown on the traffic light if there is one for the matching correlation id.
+ PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID);
+
+ if (perCorrelationId != null)
{
- _logger.info(timestampFormatter.format(new Date()) + ": Got reply with correlation id, " + correlationID);
- //_logger.debug("Received from : " + message.getJMSDestination());
- }
+ CountDownLatch trafficLight = perCorrelationId.trafficLight;
- // Turn the traffic light to green.
- CountDownLatch trafficLight = trafficLights.get(correlationID);
+ // Restart the timeout timer on every message.
+ perCorrelationId.timeOutStart = System.nanoTime();
- if (trafficLight != null)
- {
- if (_messageListener != null)
- {
- synchronized (trafficLight)
- {
- _messageListener.onMessage(message);
- trafficLight.countDown();
- }
- }
- else
+ _logger.debug("Reply was expected, decrementing the latch for the id, " + correlationID);
+
+ // Decrement the countdown latch. Before this point, it is possible that two threads might enter this
+ // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block
+ // ensures that each thread will get a unique value for the remaining messages.
+ long trueCount = -1;
+ long remainingCount = -1;
+
+ synchronized (trafficLight)
{
trafficLight.countDown();
- }
- _logger.trace("Reply was expected, decrementing the latch for the id.");
+ trueCount = trafficLight.getCount();
+ remainingCount = trueCount - 1;
- long remainingCount = trafficLight.getCount();
+ _logger.debug("remainingCount = " + remainingCount);
+ _logger.debug("trueCount = " + trueCount);
- if ((remainingCount % _txBatchSize) == 0)
- {
- commitTx(getConsumerSession());
- }
+ // Commit on transaction batch size boundaries. At this point in time the waiting producer remains
+ // blocked, even on the last message.
+ if ((remainingCount % _txBatchSize) == 0)
+ {
+ commitTx(_consumerSession);
+ }
+ // Forward the message and remaining count to any interested chained message listener.
+ if (_chainedMessageListener != null)
+ {
+ _chainedMessageListener.onMessage(message, (int) remainingCount);
+ }
+
+ // Check if this is the last message, in which case release any waiting producers. This is done
+ // after the transaction has been committed and any listeners notified.
+ if (trueCount == 1)
+ {
+ trafficLight.countDown();
+ }
+ }
}
else
{
- _logger.trace("There was no thread waiting for reply: " + correlationID);
+ _logger.warn("Got unexpected message with correlationId: " + correlationID);
}
+ // Print out ping times for every message in verbose mode only.
if (_verbose)
{
- Long timestamp = message.getLongProperty("timestamp");
+ Long timestamp = message.getLongProperty(MESSAGE_TIMESTAMP_PROPNAME);
if (timestamp != null)
{
- long diff = System.currentTimeMillis() - timestamp;
- _logger.trace("Time for round trip: " + diff);
+ long diff = System.nanoTime() - timestamp;
+ _logger.trace("Time for round trip (nanos): " + diff);
}
}
}
@@ -566,38 +805,101 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
{
_logger.warn("There was a JMSException: " + e.getMessage(), e);
}
+
+ _logger.debug("public void onMessage(Message message): ending");
}
/**
* Sends the specified number of ping message and then waits for all correlating replies. If the wait times out
- * before a reply arrives, then a null reply is returned from this method.
+ * before a reply arrives, then a null reply is returned from this method. This method generates a new unqiue
+ * correlation id for the messages.
*
* @param message The message to send.
* @param numPings The number of ping messages to send.
* @param timeout The timeout in milliseconds.
* @return The number of replies received. This may be less than the number sent if the timeout terminated the
* wait for all prematurely.
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
+ * @throws JMSException All underlying JMSExceptions are allowed to fall through.
+ * @throws InterruptedException When interrupted by a timeout.
*/
public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException
{
- String messageCorrelationId = null;
+ _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = "
+ + timeout + "): called");
+
+ // Create a unique correlation id to put on the messages before sending them.
+ String messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet());
+
+ return pingAndWaitForReply(message, numPings, timeout, messageCorrelationId);
+ }
+
+ /**
+ * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out
+ * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify
+ * the correlation id.
+ *
+ * @param message The message to send.
+ * @param numPings The number of ping messages to send.
+ * @param timeout The timeout in milliseconds.
+ * @param messageCorrelationId The message correlation id.
+ * @return The number of replies received. This may be less than the number sent if the timeout terminated the
+ * wait for all prematurely.
+ * @throws JMSException All underlying JMSExceptions are allowed to fall through.
+ * @throws InterruptedException When interrupted by a timeout
+ */
+ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId)
+ throws JMSException, InterruptedException
+ {
+ _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = "
+ + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");
try
{
- // Put a unique correlation id on the message before sending it.
- messageCorrelationId = Long.toString(getNewID());
+ // Create a count down latch to count the number of replies with. This is created before the messages are
+ // sent so that the replies cannot be received before the count down is created.
+ // One is added to this, so that the last reply becomes a special case. The special case is that the
+ // chained message listener must be called before this sender can be unblocked, but that decrementing the
+ // countdown needs to be done before the chained listener can be called.
+ PerCorrelationId perCorrelationId = new PerCorrelationId();
+
+ perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1);
+ perCorrelationIds.put(messageCorrelationId, perCorrelationId);
+
+ // Set up the current time as the start time for pinging on the correlation id. This is used to determine
+ // timeouts.
+ perCorrelationId.timeOutStart = System.nanoTime();
+ // Send the specifed number of messages.
pingNoWaitForReply(message, numPings, messageCorrelationId);
- CountDownLatch trafficLight = trafficLights.get(messageCorrelationId);
- // Block the current thread until a reply to the message is received, or it times out.
- trafficLight.await(timeout, TimeUnit.MILLISECONDS);
+ boolean timedOut = false;
+ boolean allMessagesReceived = false;
+ int numReplies = 0;
+
+ do
+ {
+ // Block the current thread until replies to all the messages are received, or it times out.
+ perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS);
+
+ // Work out how many replies were receieved.
+ numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount();
- // Work out how many replies were receieved.
- int numReplies = numPings - (int) trafficLight.getCount();
+ allMessagesReceived = numReplies == getExpectedNumPings(numPings);
- if ((numReplies < numPings) && _verbose)
+ _logger.debug("numReplies = " + numReplies);
+ _logger.debug("allMessagesReceived = " + allMessagesReceived);
+
+ // Recheck the timeout condition.
+ long now = System.nanoTime();
+ long lastMessageReceievedAt = perCorrelationId.timeOutStart;
+ timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000);
+
+ _logger.debug("now = " + now);
+ _logger.debug("lastMessageReceievedAt = " + lastMessageReceievedAt);
+ }
+ while (!timedOut && !allMessagesReceived);
+
+ if ((numReplies < getExpectedNumPings(numPings)) && _verbose)
{
_logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId);
}
@@ -606,45 +908,36 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
_logger.info("Got all replies on id, " + messageCorrelationId);
}
- commitTx(getConsumerSession());
+ commitTx(_consumerSession);
+
+ _logger.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending");
return numReplies;
}
+ // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived,
+ // so will be a memory leak if this is not done.
finally
{
- removeLock(messageCorrelationId);
+ perCorrelationIds.remove(messageCorrelationId);
}
}
- public long getNewID()
- {
- return idGenerator.incrementAndGet();
- }
-
- public CountDownLatch removeLock(String correlationID)
- {
- return trafficLights.remove(correlationID);
- }
-
-
- /*
- * Sends the specified ping message but does not wait for a correlating reply.
- *
- * @param message The message to send.
- * @param numPings The number of pings to send.
- * @return The reply, or null if no reply arrives before the timeout.
- * @throws JMSException All underlying JMSExceptions are allowed to fall through.
- */
- public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException
+ /**
+ * Sends the specified number of ping messages and does not wait for correlating replies.
+ *
+ * @param message The message to send.
+ * @param numPings The number of pings to send.
+ * @param messageCorrelationId A correlation id to place on all messages sent.
+ * @throws JMSException All underlying JMSExceptions are allowed to fall through.
+ */
+ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException
{
- // Create a count down latch to count the number of replies with. This is created before the message is sent
- // so that the message is not received before the count down is created.
- CountDownLatch trafficLight = new CountDownLatch(numPings);
- trafficLights.put(messageCorrelationId, trafficLight);
+ _logger.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings
+ + ", String messageCorrelationId = " + messageCorrelationId + "): called");
message.setJMSCorrelationID(messageCorrelationId);
- // Set up a committed flag to detect uncommitted message at the end of the send loop. This may occurr if the
+ // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the
// transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is
// needed.
boolean committed = false;
@@ -652,55 +945,46 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
// Send all of the ping messages.
for (int i = 0; i < numPings; i++)
{
- // Reset the committed flag to indicate that there are uncommitted message.
+ // Reset the committed flag to indicate that there are uncommitted messages.
committed = false;
// Re-timestamp the message.
- message.setLongProperty("timestamp", System.currentTimeMillis());
+ message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
- // Check if the test is with multiple-destinations, in which case round robin the destinations
- // as the messages are sent.
- if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT)
- {
- sendMessage(getDestination(i % getDestinationsCount()), message);
- }
- else
- {
- sendMessage(message);
- }
+ // Round robin the destinations as the messages are sent.
+ //return _destinationCount;
+ sendMessage(_pingDestinations.get(i % _pingDestinations.size()), message);
- // Apply message rate throttling if a rate limit has been set up and the throttling batch limit has been
- // reached. See the comment on the throttle batch size for information about the use of batches here.
- if ((rateLimiter != null) && ((i % _throttleBatchSize) == 0))
+ // Apply message rate throttling if a rate limit has been set up.
+ if (_rateLimiter != null)
{
- rateLimiter.throttle();
+ _rateLimiter.throttle();
}
// Call commit every time the commit batch size is reached.
if ((i % _txBatchSize) == 0)
{
- commitTx();
+ commitTx(_producerSession);
committed = true;
}
+
+ // Spew out per message timings on every message sonly in verbose mode.
+ if (_verbose)
+ {
+ _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, "
+ + messageCorrelationId);
+ }
}
// Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages.
if (!committed)
{
- commitTx();
- }
-
- // Spew out per message timings only in verbose mode.
- if (_verbose)
- {
- _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId);
+ commitTx(_producerSession);
}
-
}
/**
- * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and
- * waits for replies and inserts short pauses in between each.
+ * The ping loop implementation. This sends out pings waits for replies and inserts short pauses in between each.
*/
public void pingLoop()
{
@@ -708,13 +992,13 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
{
// Generate a sample message and time stamp it.
ObjectMessage msg = getTestMessage(_replyDestination, _messageSize, _persistent);
- msg.setLongProperty("timestamp", System.currentTimeMillis());
+ msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
// Send the message and wait for a reply.
- pingAndWaitForReply(msg, DEFAULT_BATCH_SIZE, TIMEOUT);
+ pingAndWaitForReply(msg, DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT);
// Introduce a short pause if desired.
- pause(SLEEP_TIME);
+ pause(DEFAULT_SLEEP_TIME);
}
catch (JMSException e)
{
@@ -728,79 +1012,332 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable,
}
}
- public Destination getReplyDestination()
+ /*public Destination getReplyDestination()
{
return _replyDestination;
+ }*/
+
+ /**
+ * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set
+ * here.
+ *
+ * @param messageListener The chained message listener.
+ */
+ public void setChainedMessageListener(ChainedMessageListener messageListener)
+ {
+ _chainedMessageListener = messageListener;
}
- protected void setReplyDestination(Destination destination)
+ /**
+ * Removes any chained message listeners from this pinger.
+ */
+ public void removeChainedMessageListener()
{
- _replyDestination = destination;
+ _chainedMessageListener = null;
}
- public void setMessageListener(MessageListener messageListener)
+ /**
+ * Generates a test message of the specified size, with the specified reply-to destination and persistence flag.
+ *
+ * @param replyQueue The reply-to destination for the message.
+ * @param messageSize The desired size of the message in bytes.
+ * @param persistent <tt>true</tt> if the message should use persistent delivery, <tt>false</tt> otherwise.
+ * @return A freshly generated test message.
+ * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through.
+ */
+ public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException
{
- _messageListener = messageListener;
+ ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent);
+
+ // Timestamp the message in nanoseconds.
+ msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
+
+ return msg;
}
- public CountDownLatch getEndLock(String correlationID)
+ /**
+ * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this
+ * flag has been cleared.
+ */
+ public void stop()
{
- return trafficLights.get(correlationID);
+ _publish = false;
}
- /*
- * When the test is being performed with multiple queues, then this method will be used, which has a loop to
- * pick up the next queue from the queues list and sends message to it.
- *
- * @param message
- * @param numPings
- * @throws JMSException
- */
- /*private void pingMultipleQueues(Message message, int numPings) throws JMSException
+ /**
+ * Implements a ping loop that repeatedly pings until the publish flag becomes false.
+ */
+ public void run()
{
- int queueIndex = 0;
- for (int i = 0; i < numPings; i++)
+ // Keep running until the publish flag is cleared.
+ while (_publish)
{
- // Re-timestamp the message.
- message.setLongProperty("timestamp", System.currentTimeMillis());
+ pingLoop();
+ }
+ }
- sendMessage(getDestination(queueIndex++), message);
+ /**
+ * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the
+ * connection, this clears the publish flag which in turn will halt the ping loop.
+ *
+ * @param e The exception that triggered this callback method.
+ */
+ public void onException(JMSException e)
+ {
+ _publish = false;
+ _logger.debug("There was a JMSException: " + e.getMessage(), e);
+ }
- // reset the counter to get the first queue
- if (queueIndex == (getDestinationsCount() - 1))
+ /**
+ * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered
+ * with the runtime system as a shutdown hook.
+ *
+ * @return A shutdown hook for the ping loop.
+ */
+ public Thread getShutdownHook()
+ {
+ return new Thread(new Runnable()
+ {
+ public void run()
{
- queueIndex = 0;
+ stop();
}
+ });
+ }
+
+ /**
+ * Gets the underlying connection that this ping client is running on.
+ *
+ * @return The underlying connection that this ping client is running on.
+ */
+ public Connection getConnection()
+ {
+ return _connection;
+ }
+
+ /**
+ * Creates consumers for the specified destinations and registers this pinger to listen to their messages.
+ *
+ * @param destinations The destinations to listen to.
+ * @param selector A selector to filter the messages with.
+ * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through.
+ */
+ public void createReplyConsumers(Collection<Destination> destinations, String selector) throws JMSException
+ {
+ _logger.debug("public void createReplyConsumers(Collection<Destination> destinations = " + destinations
+ + ", String selector = " + selector + "): called");
+
+ for (Destination destination : destinations)
+ {
+ // Create a consumer for the destination and set this pinger to listen to its messages.
+ MessageConsumer consumer =
+ _consumerSession.createConsumer(destination, DEFAULT_PREFETCH, DEFAULT_NO_LOCAL, DEFAULT_EXCLUSIVE,
+ selector);
+ consumer.setMessageListener(this);
}
- }*/
+ }
+
+ /**
+ * Closes the pingers connection.
+ *
+ * @throws JMSException All JMSException are allowed to fall through.
+ */
+ public void close() throws JMSException
+ {
+ _logger.debug("public void close(): called");
+
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
/**
- * A connection listener that logs out any failover complete events. Could do more interesting things with this
- * at some point...
+ * Convenience method to commit the transaction on the specified session. If the session to commit on is not
+ * a transactional session, this method does nothing (unless the failover after send flag is set).
+ * <p/>
+ * <p/>If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit
+ * is applied. This flag applies whether the pinger is transactional or not.
+ * <p/>
+ * <p/>If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the
+ * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker
+ * after the commit is applied. These flags will only apply if using a transactional pinger.
+ *
+ * @param session The session to commit
+ * @throws javax.jms.JMSException If the commit fails and then the rollback fails.
+ * <p/>
+ * //todo @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit
+ * method, because commits only apply to transactional pingers, but fail after send applied to transactional
+ * and non-transactional alike.
*/
- public static class FailoverNotifier implements ConnectionListener
+ protected void commitTx(Session session) throws JMSException
{
- public void bytesSent(long count)
+ _logger.debug("protected void commitTx(Session session): called");
+
+ _logger.trace("Batch time reached");
+ if (_failAfterSend)
{
+ _logger.trace("Batch size reached");
+ if (_failOnce)
+ {
+ _failAfterSend = false;
+ }
+
+ _logger.trace("Failing After Send");
+ doFailover();
}
- public void bytesReceived(long count)
+ if (session.getTransacted())
{
+ try
+ {
+ if (_failBeforeCommit)
+ {
+ if (_failOnce)
+ {
+ _failBeforeCommit = false;
+ }
+
+ _logger.trace("Failing Before Commit");
+ doFailover();
+ }
+
+ session.commit();
+
+ if (_failAfterCommit)
+ {
+ if (_failOnce)
+ {
+ _failAfterCommit = false;
+ }
+
+ _logger.trace("Failing After Commit");
+ doFailover();
+ }
+
+ _logger.trace("Session Commited.");
+ }
+ catch (JMSException e)
+ {
+ _logger.trace("JMSException on commit:" + e.getMessage(), e);
+
+ // Warn that the bounce back client is not available.
+ if (e.getLinkedException() instanceof AMQNoConsumersException)
+ {
+ _logger.debug("No consumers on queue.");
+ }
+
+ try
+ {
+ session.rollback();
+ _logger.trace("Message rolled back.");
+ }
+ catch (JMSException jmse)
+ {
+ _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
+
+ // Both commit and rollback failed. Throw the rollback exception.
+ throw jmse;
+ }
+ }
}
+ }
- public boolean preFailover(boolean redirect)
+ /**
+ * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination
+ * of the ping producer. If an explicit destination is set, this overrides the default.
+ *
+ * @param destination The destination to send to.
+ * @param message The message to send.
+ * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through.
+ */
+ protected void sendMessage(Destination destination, Message message) throws JMSException
+ {
+ if (_failBeforeSend)
{
- return true; //Allow failover
+ if (_failOnce)
+ {
+ _failBeforeSend = false;
+ }
+
+ _logger.trace("Failing Before Send");
+ doFailover();
}
- public boolean preResubscribe()
+ if (destination == null)
{
- return true; // Allow resubscription
+ _producer.send(message);
}
+ else
+ {
+ _producer.send(destination, message);
+ }
+ }
- public void failoverComplete()
+ /**
+ * Prompts the user to terminate the broker, in order to test failover functionality. This method will block
+ * until the user supplied some input on the terminal.
+ */
+ protected void doFailover()
+ {
+ System.out.println("Kill Broker now then press return");
+ try
{
- _logger.info("App got failover complete callback.");
+ System.in.read();
}
+ catch (IOException e)
+ {
+ //ignore
+ }
+
+ System.out.println("Continuing.");
+ }
+
+ /**
+ * This value will be changed by PingClient to represent the number of clients connected to each topic.
+ *
+ * @return int The number of consumers subscribing to each topic.
+ */
+ public int getConsumersPerTopic()
+ {
+ return _consumersPerTopic;
+ }
+
+ public int getExpectedNumPings(int numpings)
+ {
+ return numpings * getConsumersPerTopic();
+ }
+
+
+ /**
+ * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's
+ * {@link PingPongProducer#onMessage} method is called, the chained listener set through the
+ * {@link PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected
+ * count of messages with that correlation id.
+ * <p/>
+ * Provided only one pinger is producing messages with that correlation id, the chained listener will always be
+ * given unique message counts. It will always be called while the producer waiting for all messages to arrive is
+ * still blocked.
+ */
+ public static interface ChainedMessageListener
+ {
+ public void onMessage(Message message, int remainingCount) throws JMSException;
+ }
+
+ /**
+ * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be
+ * added to this: read/write lock to make onMessage more concurrent as described in class header comment.
+ */
+ protected static class PerCorrelationId
+ {
+ /**
+ * Holds a countdown on number of expected messages.
+ */
+ CountDownLatch trafficLight;
+
+ /**
+ * Holds the last timestamp that the timeout was reset to.
+ */
+ Long timeOutStart;
}
}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java
deleted file mode 100644
index bab732e2a6..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java
+++ /dev/null
@@ -1,235 +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.requestreply;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.Session;
-import org.apache.qpid.url.URLSyntaxException;
-
-import javax.jms.*;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-public class ServiceProvidingClient
-{
- private static final Logger _logger = Logger.getLogger(ServiceProvidingClient.class);
-
- private MessageProducer _destinationProducer;
-
- private Destination _responseDest;
-
- private AMQConnection _connection;
-
- private Session _session;
- private Session _producerSession;
-
- private boolean _isTransactional;
-
- public ServiceProvidingClient(String brokerDetails, String username, String password,
- String clientName, String virtualPath, String serviceName,
- final int deliveryMode, boolean transactedMode, String selector)
- throws AMQException, JMSException, URLSyntaxException
- {
- _isTransactional = transactedMode;
-
- _logger.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent")
- + "\t isTransactional: " + _isTransactional);
-
- _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath);
- _connection.setConnectionListener(new ConnectionListener()
- {
-
- public void bytesSent(long count)
- {
- }
-
- public void bytesReceived(long count)
- {
- }
-
- public boolean preFailover(boolean redirect)
- {
- return true;
- }
-
- public boolean preResubscribe()
- {
- return true;
- }
-
- public void failoverComplete()
- {
- _logger.info("App got failover complete callback");
- }
- });
- _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE);
- _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE);
-
- _logger.info("Service (queue) name is '" + serviceName + "'...");
-
- AMQQueue destination = new AMQQueue(serviceName);
-
- MessageConsumer consumer = _session.createConsumer(destination,
- 100, true, false, selector);
-
- consumer.setMessageListener(new MessageListener()
- {
- private int _messageCount;
-
- public void onMessage(Message message)
- {
- //_logger.info("Got message '" + message + "'");
- TextMessage tm = (TextMessage) message;
- try
- {
- Destination responseDest = tm.getJMSReplyTo();
- if (responseDest == null)
- {
- _logger.info("Producer not created because the response destination is null.");
- return;
- }
-
- if (!responseDest.equals(_responseDest))
- {
- _responseDest = responseDest;
-
- _logger.info("About to create a producer");
- _destinationProducer = _producerSession.createProducer(responseDest);
- _destinationProducer.setDisableMessageTimestamp(true);
- _destinationProducer.setDeliveryMode(deliveryMode);
- _logger.info("After create a producer");
- }
- }
- catch (JMSException e)
- {
- _logger.error("Error creating destination");
- }
- _messageCount++;
- if (_messageCount % 1000 == 0)
- {
- _logger.info("Received message total: " + _messageCount);
- _logger.info("Sending response to '" + _responseDest + "'");
- }
-
- try
- {
- String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText();
- TextMessage msg = _producerSession.createTextMessage(payload);
- if (tm.propertyExists("timeSent"))
- {
- _logger.info("timeSent property set on message");
- long timesent = tm.getLongProperty("timeSent");
- _logger.info("timeSent value is: " + timesent);
- msg.setLongProperty("timeSent", timesent);
- }
-
- _destinationProducer.send(msg);
-
- if (_isTransactional)
- {
- _producerSession.commit();
- }
- if (_isTransactional)
- {
- _session.commit();
- }
- if (_messageCount % 1000 == 0)
- {
- _logger.info("Sent response to '" + _responseDest + "'");
- }
- }
- catch (JMSException e)
- {
- _logger.error("Error sending message: " + e, e);
- }
- }
- });
- }
-
- public void run() throws JMSException
- {
- _connection.start();
- _logger.info("Waiting...");
- }
-
- public static void main(String[] args)
- {
- _logger.info("Starting...");
-
- if (args.length < 5)
- {
- System.out.println("Usage: serviceProvidingClient <brokerDetails> <username> <password> <virtual-path> <serviceQueue> [<P[ersistent]|N[onPersistent]> <T[ransacted]|N[onTransacted]>] [selector]");
- System.exit(1);
- }
- String clientId = null;
- try
- {
- InetAddress address = InetAddress.getLocalHost();
- clientId = address.getHostName() + System.currentTimeMillis();
- }
- catch (UnknownHostException e)
- {
- _logger.error("Error: " + e, e);
- }
-
- int deliveryMode = DeliveryMode.NON_PERSISTENT;
- boolean transactedMode = false;
-
- if (args.length > 7)
- {
- deliveryMode = args[args.length - 2].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT
- : DeliveryMode.NON_PERSISTENT;
-
- transactedMode = args[args.length - 1].toUpperCase().charAt(0) == 'T' ? true : false;
- }
-
- String selector = null;
- if ((args.length == 8) || (args.length == 7))
- {
- selector = args[args.length - 1];
- }
-
- try
- {
- ServiceProvidingClient client = new ServiceProvidingClient(args[0], args[1], args[2],
- clientId, args[3], args[4],
- deliveryMode, transactedMode, selector);
- client.run();
- }
- catch (JMSException e)
- {
- _logger.error("Error: " + e, e);
- }
- catch (AMQException e)
- {
- _logger.error("Error: " + e, e);
- }
- catch (URLSyntaxException e)
- {
- _logger.error("Error: " + e, e);
- }
- }
-}
-
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java
deleted file mode 100644
index 57512929c1..0000000000
--- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java
+++ /dev/null
@@ -1,428 +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.requestreply;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.message.TestMessageFactory;
-import org.apache.qpid.client.message.JMSTextMessage;
-import org.apache.qpid.jms.MessageConsumer;
-import org.apache.qpid.jms.MessageProducer;
-import org.apache.qpid.jms.Session;
-import org.apache.qpid.url.URLSyntaxException;
-
-import javax.jms.*;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * A client that behaves as follows:
- * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li>
- * <li>Creates a temporary queue</li>
- * <li>Creates messages containing a property(reply-to) that is the name of the temporary queue</li>
- * <li>Fires off a message on the original queue and registers the callbackHandler to listen to the response on the temporary queue</li>
- * <li>Start the loop to send all messages</li>
- * <li>CallbackHandler keeps listening to the responses and exits if all the messages have been received back or
- * if the waiting time for next message is elapsed</li>
- * </ul>
- */
-public class ServiceRequestingClient implements ExceptionListener
-{
- private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class);
-
- private long _messageIdentifier = 0;
-
- // time for which callbackHandler should wait for a message before exiting. Default time= 60 secs
- private static long _callbackHandlerWaitingTime = 60000;
-
- private String MESSAGE_DATA;
-
- private AMQConnection _connection;
-
- private Session _session;
- private Session _producerSession;
-
- private long _averageLatency;
-
- private int _messageCount;
- private boolean _isTransactional;
-
- private volatile boolean _completed;
-
- private AMQDestination _tempDestination;
-
- private MessageProducer _producer;
-
- private Object _waiter;
-
- private class CallbackHandler implements MessageListener
- {
- private int _actualMessageCount;
-
- private long _startTime;
- // The time when the last message was received by the callbackHandler
- private long _messageReceivedTime = 0;
- private Object _timerCallbackHandler = new Object();
-
- public CallbackHandler(long startTime)
- {
- _startTime = startTime;
- // Start the timer thread, which will keep checking if test should exit because the waiting time has elapsed
- (new Thread(new TimerThread())).start();
- }
-
- public void onMessage(Message m)
- {
- _messageReceivedTime = System.currentTimeMillis();
- if (_log.isDebugEnabled())
- {
- _log.debug("Message received: " + m);
- }
- try
- {
- m.getPropertyNames();
- if (m.propertyExists("timeSent"))
- {
- long timeSent = m.getLongProperty("timeSent");
- if (_averageLatency == 0)
- {
- _averageLatency = _messageReceivedTime - timeSent;
- _log.info("Latency " + _averageLatency);
- }
- else
- {
- _log.info("Individual latency: " + (_messageReceivedTime - timeSent));
- _averageLatency = (_averageLatency + (_messageReceivedTime - timeSent)) / 2;
- _log.info("Average latency now: " + _averageLatency);
- }
- }
- if(_isTransactional)
- {
- _session.commit();
- }
- }
- catch (JMSException e)
- {
- _log.error("Error getting latency data: " + e, e);
- }
- _actualMessageCount++;
- if (_actualMessageCount % 1000 == 0)
- {
- _log.info("Received message count: " + _actualMessageCount);
- }
-
- checkForMessageID(m);
-
- if (_actualMessageCount == _messageCount)
- {
- finishTesting(_actualMessageCount);
- }
- }
-
- /**
- * sets completed flag to true, closes the callbackHandler connection and notifies the waiter thread,
- * so that the callbackHandler can finish listening for messages. This causes the test to finish.
- * @param receivedMessageCount
- */
- private void finishTesting(int receivedMessageCount)
- {
- _completed = true;
- notifyWaiter();
- notifyTimerThread();
-
- long timeTaken = System.currentTimeMillis() - _startTime;
- _log.info("***** Result *****");
- _log.info("Total messages received = " + receivedMessageCount);
- _log.info("Total time taken to receive " + receivedMessageCount + " messages was " +
- timeTaken + "ms, equivalent to " +
- (receivedMessageCount / (timeTaken / 1000.0)) + " messages per second");
-
- try
- {
- _connection.close();
- _log.info("Connection closed");
- }
- catch (JMSException e)
- {
- _log.error("Error closing connection");
- }
- }
-
- private void notifyTimerThread()
- {
- if (_timerCallbackHandler != null)
- {
- synchronized (_timerCallbackHandler)
- {
- _timerCallbackHandler.notify();
- }
- }
- }
-
- /**
- * Thread class implementing the timer for callbackHandler. The thread will exit the test if the waiting time
- * has elapsed before next message is received.
- */
- private class TimerThread implements Runnable
- {
- public void run()
- {
- do
- {
- try
- {
- synchronized(_timerCallbackHandler)
- {
- _timerCallbackHandler.wait(_callbackHandlerWaitingTime);
- }
- }
- catch (InterruptedException ignore)
- {
-
- }
-
- // exit if callbackHandler has received all messages
- if (_completed)
- {
- return;
- }
- }
- while ((System.currentTimeMillis() - _messageReceivedTime) < _callbackHandlerWaitingTime);
-
- // waiting time has elapsed, so exit the test
- _log.info("");
- _log.info("Exited after waiting for " + _callbackHandlerWaitingTime/1000 + " secs");
- finishTesting(_actualMessageCount);
- }
- }
- } // end of CallbackHandler class
-
- /**
- * Checks if the received AMQ Message ID(delivery tag) is in sequence, by comparing it with the AMQ MessageID
- * of previous message.
- * @param receivedMsg
- */
- private void checkForMessageID(Message receivedMsg)
- {
- try
- {
- JMSTextMessage msg = (JMSTextMessage)receivedMsg;
- if (! (msg.getDeliveryTag() == _messageIdentifier + 1))
- {
- _log.info("Out of sequence message received. Previous AMQ MessageID= " + _messageIdentifier +
- ", Received AMQ messageID= " + receivedMsg.getJMSMessageID());
- }
- _messageIdentifier = msg.getDeliveryTag();
- }
- catch (Exception ex)
- {
- _log.error("Error in checking messageID ", ex);
- }
-
- }
-
- private void notifyWaiter()
- {
- if (_waiter != null)
- {
- synchronized (_waiter)
- {
- _waiter.notify();
- }
- }
- }
-
- public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password,
- String vpath, String commandQueueName,
- int deliveryMode, boolean transactedMode,
- final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException
- {
- _isTransactional = transactedMode;
-
- _log.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent"));
- _log.info("isTransactional: " + _isTransactional);
-
- _messageCount = messageCount;
- MESSAGE_DATA = TestMessageFactory.createMessagePayload(messageDataLength);
- try
- {
- createConnection(brokerHosts, clientID, username, password, vpath);
- _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE);
- _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE);
-
- _connection.setExceptionListener(this);
-
- AMQQueue destination = new AMQQueue(commandQueueName);
- _producer = (MessageProducer) _producerSession.createProducer(destination);
- _producer.setDisableMessageTimestamp(true);
- _producer.setDeliveryMode(deliveryMode);
-
- _tempDestination = new AMQQueue("TempResponse" +
- Long.toString(System.currentTimeMillis()), true);
- MessageConsumer messageConsumer = (MessageConsumer) _session.createConsumer(_tempDestination, 100, true,
- true, null);
-
- //Send first message, then wait a bit to allow the provider to get initialised
- TextMessage first = _session.createTextMessage(MESSAGE_DATA);
- first.setJMSReplyTo(_tempDestination);
- _producer.send(first);
- if (_isTransactional)
- {
- _producerSession.commit();
- }
- try
- {
- Thread.sleep(1000);
- }
- catch (InterruptedException ignore)
- {
- }
-
- //now start the clock and the test...
- final long startTime = System.currentTimeMillis();
-
- messageConsumer.setMessageListener(new CallbackHandler(startTime));
- }
- catch (JMSException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
- }
-
- /**
- * Run the test and notify an object upon receipt of all responses.
- *
- * @param waiter the object that will be notified
- * @throws JMSException
- */
- public void run(Object waiter) throws JMSException
- {
- _waiter = waiter;
- _connection.start();
- for (int i = 1; i < _messageCount; i++)
- {
- TextMessage msg = _producerSession.createTextMessage(MESSAGE_DATA + i);
- msg.setJMSReplyTo(_tempDestination);
- if (i % 1000 == 0)
- {
- long timeNow = System.currentTimeMillis();
- msg.setLongProperty("timeSent", timeNow);
- }
- _producer.send(msg);
- if (_isTransactional)
- {
- _producerSession.commit();
- }
-
- }
- _log.info("Finished sending " + _messageCount + " messages");
- }
-
- public boolean isCompleted()
- {
- return _completed;
- }
-
- private void createConnection(String brokerHosts, String clientID, String username, String password,
- String vpath) throws AMQException, URLSyntaxException
- {
- _connection = new AMQConnection(brokerHosts, username, password, clientID, vpath);
- }
-
- /**
- * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank
- * means the server will allocate a name.
- */
- public static void main(String[] args)
- {
- if ((args.length < 6) || (args.length == 8))
- {
- System.err.println("Usage: ServiceRequestingClient <brokerDetails> <username> <password> <vpath> " +
- "<command queue name> <number of messages> [<message size>] " +
- "[<P[ersistent]|N[onPersistent] (Default N)> <T[ransacted]|N[onTransacted] (Default N)>] " +
- "[<waiting time for response in sec (default 60 sec)>]");
- System.exit(1);
- }
- try
- {
- int messageSize = 4096;
- boolean transactedMode = false;
- int deliveryMode = DeliveryMode.NON_PERSISTENT;
-
- if (args.length > 6)
- {
- messageSize = Integer.parseInt(args[6]);
- }
- if (args.length > 7)
- {
- deliveryMode = args[7].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT
- : DeliveryMode.NON_PERSISTENT;
-
- transactedMode = args[8].toUpperCase().charAt(0) == 'T' ? true : false;
- }
-
- if (args.length > 9)
- {
- _callbackHandlerWaitingTime = Long.parseLong(args[9]) * 1000;
- }
-
- _log.info("Each message size = " + messageSize + " bytes");
-
- InetAddress address = InetAddress.getLocalHost();
- String clientID = address.getHostName() + System.currentTimeMillis();
- ServiceRequestingClient client = new ServiceRequestingClient(args[0], clientID, args[1], args[2], args[3],
- args[4], deliveryMode, transactedMode, Integer.parseInt(args[5]),
- messageSize);
- Object waiter = new Object();
- client.run(waiter);
-
- // Start a thread to
- synchronized (waiter)
- {
- while (!client.isCompleted())
- {
- waiter.wait();
- }
- }
- }
- catch (UnknownHostException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
- catch (Exception e)
- {
- System.err.println("Error in client: " + e);
- e.printStackTrace();
- }
- }
-
- /**
- * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException)
- */
- public void onException(JMSException e)
- {
- System.err.println(e.getMessage());
- e.printStackTrace(System.err);
- }
-}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java
index bd39ec34a1..347031ff51 100644
--- a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java
@@ -1,311 +1,306 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ping;
-//import uk.co.thebadgerset.junit.extensions.TimingControllerAware;
-//import uk.co.thebadgerset.junit.extensions.TimingController;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
-import javax.jms.MessageListener;
-import javax.jms.ObjectMessage;
import javax.jms.JMSException;
import javax.jms.Message;
+import javax.jms.ObjectMessage;
-import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
+
import org.apache.log4j.Logger;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.CountDownLatch;
+import org.apache.qpid.requestreply.PingPongProducer;
+import uk.co.thebadgerset.junit.extensions.TimingController;
+import uk.co.thebadgerset.junit.extensions.TimingControllerAware;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-public class PingAsyncTestPerf extends PingTestPerf //implements TimingControllerAware
+/**
+ * PingAsyncTestPerf is a performance test that outputs multiple timings from its test method, using the timing controller
+ * interface supplied by the test runner from a seperate listener thread. It differs from the {@link PingTestPerf} test
+ * that it extends because it can output timings as replies are received, rather than waiting until all expected replies
+ * are received. This is less 'blocky' than the tests in {@link PingTestPerf}, and provides a truer simulation of sending
+ * and recieving clients working asynchronously.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><td> Responsibilities <th> Collaborations
+ * <tr><td> Send many ping messages and output timings asynchronously on batches received.
+ * </table>
+ */
+public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerAware
{
-// private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class);
+ private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class);
+
+ /** Holds the name of the property to get the test results logging batch size. */
+ public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "BatchSize";
+
+ /** Holds the default test results logging batch size. */
+ public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000;
-// private TimingController _timingController;
+ /** Used to hold the timing controller passed from the test runner. */
+ private TimingController _timingController;
-// private AsyncMessageListener _listener;
+ /** Used to generate unique correlation ids for each test run. */
+ private AtomicLong corellationIdGenerator = new AtomicLong();
+ /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */
+ private Map<String, PerCorrelationId> perCorrelationIds =
+ Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
+
+ /** Holds the batched results listener, that does logging on batch boundaries. */
+ private BatchedResultsListener batchedResultsListener = null;
+
+ /**
+ * Creates a new asynchronous ping performance test with the specified name.
+ *
+ * @param name The test name.
+ */
public PingAsyncTestPerf(String name)
{
super(name);
+
+ // Sets up the test parameters with defaults.
+ ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME,
+ Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE));
+ }
+
+ /**
+ * Compile all the tests into a test suite.
+ * @return The test suite to run. Should only contain testAsyncPingOk method.
+ */
+ public static Test suite()
+ {
+ // Build a new test suite
+ TestSuite suite = new TestSuite("Ping Performance Tests");
+
+ // Run performance tests in read committed mode.
+ suite.addTest(new PingAsyncTestPerf("testAsyncPingOk"));
+
+ return suite;
+ }
+
+ /**
+ * Accepts a timing controller from the test runner.
+ *
+ * @param timingController The timing controller to register mutliple timings with.
+ */
+ public void setTimingController(TimingController timingController)
+ {
+ _timingController = timingController;
+ }
+
+ /**
+ * Gets the timing controller passed in by the test runner.
+ *
+ * @return The timing controller passed in by the test runner.
+ */
+ public TimingController getTimingController()
+ {
+ return _timingController;
+ }
+
+ /**
+ * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until
+ * all replies have been received or a time out occurs before exiting this method.
+ *
+ * @param numPings The number of pings to send.
+ * @throws Exception pass all errors out to the test harness
+ */
+ public void testAsyncPingOk(int numPings) throws Exception
+ {
+ _logger.debug("public void testAsyncPingOk(int numPings): called");
+
+ // Ensure that at least one ping was requeusted.
+ if (numPings == 0)
+ {
+ _logger.error("Number of pings requested was zero.");
+ }
+
+ // Get the per thread test setup to run the test through.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+ PingClient pingClient = perThreadSetup._pingClient;
+
+ // Advance the correlation id of messages to send, to make it unique for this run.
+ String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet());
+ _logger.debug("messageCorrelationId = " + messageCorrelationId);
+
+ // Initialize the count and timing controller for the new correlation id.
+ PerCorrelationId perCorrelationId = new PerCorrelationId();
+ TimingController tc = getTimingController().getControllerForCurrentThread();
+ perCorrelationId._tc = tc;
+ perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings);
+ perCorrelationIds.put(messageCorrelationId, perCorrelationId);
+
+ // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these
+ // messages.
+ //pingClient.setChainedMessageListener(batchedResultsListener);
+
+ // Generate a sample message of the specified size.
+ ObjectMessage msg =
+ pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
+ testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
+ testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
+
+ // Send the requested number of messages, and wait until they have all been received.
+ long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
+ int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, messageCorrelationId);
+
+ // Check that all the replies were received and log a fail if they were not.
+ if (numReplies < perCorrelationId._expectedCount)
+ {
+ tc.completeTest(false, numPings - perCorrelationId._expectedCount);
+ }
+
+ // Remove the chained message listener from the ping producer.
+ //pingClient.removeChainedMessageListener();
+
+ // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up.
+ perCorrelationIds.remove(messageCorrelationId);
+ }
+
+ /**
+ * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
+ */
+ public void threadSetUp()
+ {
+ _logger.debug("public void threadSetUp(): called");
+
+ try
+ {
+ // Call the set up method in the super class. This creates a PingClient pinger.
+ super.threadSetUp();
+
+ // Create the chained message listener, only if it has not already been created. This is set up with the
+ // batch size property, to tell it what batch size to output results on. A synchronized block is used to
+ // ensure that only one thread creates this.
+ synchronized (this)
+ {
+ if (batchedResultsListener == null)
+ {
+ int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME));
+ batchedResultsListener = new BatchedResultsListener(batchSize);
+ }
+ }
+
+ // Get the set up that the super class created.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+
+ // Register the chained message listener on the pinger to do its asynchronous test timings from.
+ perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener);
+ }
+ catch (Exception e)
+ {
+ _logger.warn("There was an exception during per thread setup.", e);
+ }
}
-// /**
-// * Compile all the tests into a test suite.
-// */
-// public static Test suite()
-// {
-// // Build a new test suite
-// TestSuite suite = new TestSuite("Ping Performance Tests");
-//
-// // Run performance tests in read committed mode.
-// suite.addTest(new PingAsyncTestPerf("testAsyncPingOk"));
-//
-// return suite;
-// }
-//
-// protected void setUp() throws Exception
-// {
-// // Create the test setups on a per thread basis, only if they have not already been created.
-//
-// if (threadSetup.get() == null)
-// {
-// PerThreadSetup perThreadSetup = new PerThreadSetup();
-//
-// // Extract the test set up paramaeters.
-// String brokerDetails = testParameters.getProperty(BROKER_PROPNAME);
-// String username = "guest";
-// String password = "guest";
-// String virtualpath = testParameters.getProperty(VIRTUAL_PATH_PROPNAME);
-// int destinationscount = Integer.parseInt(testParameters.getProperty(PING_DESTINATION_COUNT_PROPNAME));
-// String destinationname = testParameters.getProperty(PING_DESTINATION_NAME_PROPNAME);
-// boolean persistent = Boolean.parseBoolean(testParameters.getProperty(PERSISTENT_MODE_PROPNAME));
-// boolean transacted = Boolean.parseBoolean(testParameters.getProperty(TRANSACTED_PROPNAME));
-// String selector = null;
-// boolean verbose = Boolean.parseBoolean(testParameters.getProperty(VERBOSE_OUTPUT_PROPNAME));
-// int messageSize = Integer.parseInt(testParameters.getProperty(MESSAGE_SIZE_PROPNAME));
-// int rate = Integer.parseInt(testParameters.getProperty(RATE_PROPNAME));
-// boolean pubsub = Boolean.parseBoolean(testParameters.getProperty(IS_PUBSUB_PROPNAME));
-//
-//
-// boolean afterCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_COMMIT));
-// boolean beforeCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_COMMIT));
-// boolean afterSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_SEND));
-// boolean beforeSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_SEND));
-// boolean failOnce = Boolean.parseBoolean(testParameters.getProperty(FAIL_ONCE));
-//
-// int batchSize = Integer.parseInt(testParameters.getProperty(BATCH_SIZE));
-// int commitbatchSize = Integer.parseInt(testParameters.getProperty(COMMIT_BATCH_SIZE));
-//
-// // This is synchronized because there is a race condition, which causes one connection to sleep if
-// // all threads try to create connection concurrently
-// synchronized (this)
-// {
-// // Establish a client to ping a Queue and listen the reply back from same Queue
-// perThreadSetup._pingItselfClient = new TestPingItself(brokerDetails, username, password, virtualpath,
-// destinationname, selector, transacted, persistent,
-// messageSize, verbose,
-// afterCommit, beforeCommit, afterSend, beforeSend, failOnce,
-// commitbatchSize, destinationscount, rate, pubsub);
-// }
-//
-// // Attach the per-thread set to the thread.
-// threadSetup.set(perThreadSetup);
-//
-// _listener = new AsyncMessageListener(batchSize);
-//
-// perThreadSetup._pingItselfClient.setMessageListener(_listener);
-// // Start the client connection
-// perThreadSetup._pingItselfClient.getConnection().start();
-//
-// }
-// }
-//
-//
-// public void testAsyncPingOk(int numPings)
-// {
-// _timingController = this.getTimingController();
-//
-// _listener.setTotalMessages(numPings);
-//
-// PerThreadSetup perThreadSetup = threadSetup.get();
-// if (numPings == 0)
-// {
-// _logger.error("Number of pings requested was zero.");
-// fail("Number of pings requested was zero.");
-// }
-//
-// // Generate a sample message. This message is already time stamped and has its reply-to destination set.
-// ObjectMessage msg = null;
-//
-// try
-// {
-// msg = perThreadSetup._pingItselfClient.getTestMessage(null,
-// Integer.parseInt(testParameters.getProperty(
-// MESSAGE_SIZE_PROPNAME)),
-// Boolean.parseBoolean(testParameters.getProperty(
-// PERSISTENT_MODE_PROPNAME)));
-// }
-// catch (JMSException e)
-// {
-//
-// }
-//
-// // start the test
-// long timeout = Long.parseLong(testParameters.getProperty(TIMEOUT_PROPNAME));
-//
-// String correlationID = Long.toString(perThreadSetup._pingItselfClient.getNewID());
-//
-// try
-// {
-// _logger.debug("Sending messages");
-//
-// perThreadSetup._pingItselfClient.pingNoWaitForReply(msg, numPings, correlationID);
-//
-// _logger.debug("All sent");
-// }
-// catch (JMSException e)
-// {
-// e.printStackTrace();
-// Assert.fail("JMS Exception Received" + e);
-// }
-// catch (InterruptedException e)
-// {
-// e.printStackTrace();
-// }
-//
-// try
-// {
-// _logger.debug("Awating test finish");
-//
-// perThreadSetup._pingItselfClient.getEndLock(correlationID).await(timeout, TimeUnit.MILLISECONDS);
-//
-// if (perThreadSetup._pingItselfClient.getEndLock(correlationID).getCount() != 0)
-// {
-// _logger.error("Timeout occured");
-// }
-// //Allow the time out to exit the loop.
-// }
-// catch (InterruptedException e)
-// {
-// //ignore
-// _logger.error("Awaiting test end was interrupted.");
-//
-// }
-//
-// // Fail the test if the timeout was exceeded.
-// int numReplies = numPings - (int) perThreadSetup._pingItselfClient.removeLock(correlationID).getCount();
-//
-// _logger.info("Test Finished");
-//
-// if (numReplies != numPings)
-// {
-// try
-// {
-// perThreadSetup._pingItselfClient.commitTx(perThreadSetup._pingItselfClient.getConsumerSession());
-// }
-// catch (JMSException e)
-// {
-// _logger.error("Error commiting received messages", e);
-// }
-// try
-// {
-// if (_timingController != null)
-// {
-// _logger.trace("Logging missing message count");
-// _timingController.completeTest(false, numPings - numReplies);
-// }
-// }
-// catch (InterruptedException e)
-// {
-// //ignore
-// }
-// Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " + numReplies);
-// }
-// }
-//
-// public void setTimingController(TimingController timingController)
-// {
-// _timingController = timingController;
-// }
-//
-// public TimingController getTimingController()
-// {
-// return _timingController;
-// }
-//
-//
-// private class AsyncMessageListener implements MessageListener
-// {
-// private volatile int _totalMessages;
-// private int _batchSize;
-// PerThreadSetup _perThreadSetup;
-//
-// public AsyncMessageListener(int batchSize)
-// {
-// this(batchSize, -1);
-// }
-//
-// public AsyncMessageListener(int batchSize, int totalMessages)
-// {
-// _batchSize = batchSize;
-// _totalMessages = totalMessages;
-// _perThreadSetup = threadSetup.get();
-// }
-//
-// public void setTotalMessages(int newTotal)
-// {
-// _totalMessages = newTotal;
-// }
-//
-// public void onMessage(Message message)
-// {
-// try
-// {
-// _logger.trace("Message Received");
-//
-// CountDownLatch count = _perThreadSetup._pingItselfClient.getEndLock(message.getJMSCorrelationID());
-//
-// if (count != null)
-// {
-// int messagesLeft = (int) count.getCount() - 1;// minus one as we haven't yet counted the current message
-//
-// if ((messagesLeft % _batchSize) == 0)
-// {
-// doDone(_batchSize);
-// }
-// else if (messagesLeft == 0)
-// {
-// doDone(_totalMessages % _batchSize);
-// }
-// }
-//
-// }
-// catch (JMSException e)
-// {
-// _logger.warn("There was a JMSException", e);
-// }
-//
-// }
-//
-// private void doDone(int messageCount)
-// {
-// _logger.trace("Messages received:" + messageCount);
-// _logger.trace("Total Messages :" + _totalMessages);
-//
-// try
-// {
-// if (_timingController != null)
-// {
-// _timingController.completeTest(true, messageCount);
-// }
-// }
-// catch (InterruptedException e)
-// {
-// //ignore
-// }
-// }
-//
-// }
+ /**
+ * BatchedResultsListener is a {@link PingPongProducer.ChainedMessageListener} that can be attached to the
+ * pinger, in order to receive notifications about every message received and the number remaining to be
+ * received. Whenever the number remaining crosses a batch size boundary this results listener outputs
+ * a test timing for the actual number of messages received in the current batch.
+ */
+ private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener
+ {
+ /** The test results logging batch size. */
+ int _batchSize;
+
+ /**
+ * Creates a results listener on the specified batch size.
+ *
+ * @param batchSize The batch size to use.
+ */
+ public BatchedResultsListener(int batchSize)
+ {
+ _batchSize = batchSize;
+ }
+
+ /**
+ * This callback method is called from all of the pingers that this test creates. It uses the correlation id
+ * from the message to identify the timing controller for the test thread that was responsible for sending those
+ * messages.
+ *
+ * @param message The message.
+ * @param remainingCount The count of messages remaining to be received with a particular correlation id.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ public void onMessage(Message message, int remainingCount) throws JMSException
+ {
+ // Check if a batch boundary has been crossed.
+ if ((remainingCount % _batchSize) == 0)
+ {
+ // Extract the correlation id from the message.
+ String correlationId = message.getJMSCorrelationID();
+
+ _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount +
+ "): called on batch boundary for message id: "
+ + correlationId + " with thread id: " + Thread.currentThread().getId());
+
+ // Get the details for the correlation id and check that they are not null. They can become null
+ // if a test times out.
+ PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId);
+ if (perCorrelationId != null)
+ {
+ // Get the timing controller and expected count for this correlation id.
+ TimingController tc = perCorrelationId._tc;
+ int expected = perCorrelationId._expectedCount;
+ // Calculate how many messages were actually received in the last batch. This will be the batch size
+ // except where the number expected is not a multiple of the batch size and this is the first remaining
+ // count to cross a batch size boundary, in which case it will be the number expected modulo the batch
+ // size.
+ int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize;
+
+ // Register a test result for the correlation id.
+ try
+ {
+
+ tc.completeTest(true, receivedInBatch);
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore this. It means the test runner wants to stop as soon as possible.
+ _logger.warn("Got InterruptedException.", e);
+ }
+ }
+ // Else ignore, test timed out. Should log a fail here?
+ }
+ }
+ }
+
+ /**
+ * Holds state specific to each correlation id, needed to output test results. This consists of the count of
+ * the total expected number of messages, and the timing controller for the thread sending those message ids.
+ */
+ private static class PerCorrelationId
+ {
+ public int _expectedCount;
+ public TimingController _tc;
+ }
}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingLatencyTestPerf.java
new file mode 100644
index 0000000000..620ddd13f7
--- /dev/null
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingLatencyTestPerf.java
@@ -0,0 +1,317 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.ping;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.requestreply.PingPongProducer;
+
+import uk.co.thebadgerset.junit.extensions.TimingController;
+import uk.co.thebadgerset.junit.extensions.TimingControllerAware;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+/**
+ * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing
+ * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for
+ * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from
+ * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than
+ * waiting until all expected replies are received.
+ *
+ * <p/>This test does not output timings for every single ping message, as when running at high volume, writing the test
+ * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The frequency
+ * of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the default of every
+ * {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}.
+ *
+ * <p/>The size parameter logged for each individual ping is set to the size of the batch of messages that the individual
+ * timed ping was taken from, rather than 1 for a single message. This is so that the total throughput (messages / time)
+ * can be calculated in order to examine the relationship between throughput and latency.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><td> Responsibilities <th> Collaborations
+ * <tr><td> Send many ping messages and output timings for sampled individual pings.
+ * </table>
+ */
+public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware
+{
+ private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class);
+
+ /** Holds the name of the property to get the test results logging batch size. */
+ public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "BatchSize";
+
+ /** Holds the default test results logging batch size. */
+ public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000;
+
+ /** Used to hold the timing controller passed from the test runner. */
+ private TimingController _timingController;
+
+ /** Used to generate unique correlation ids for each test run. */
+ private AtomicLong corellationIdGenerator = new AtomicLong();
+
+ /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */
+ private Map<String, PerCorrelationId> perCorrelationIds =
+ Collections.synchronizedMap(new HashMap<String, PerCorrelationId>());
+
+ /** Holds the batched results listener, that does logging on batch boundaries. */
+ private BatchedResultsListener batchedResultsListener = null;
+
+ /**
+ * Creates a new asynchronous ping performance test with the specified name.
+ *
+ * @param name The test name.
+ */
+ public PingLatencyTestPerf(String name)
+ {
+ super(name);
+
+ // Sets up the test parameters with defaults.
+ ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME,
+ Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE));
+ }
+
+ /**
+ * Compile all the tests into a test suite.
+ */
+ public static Test suite()
+ {
+ // Build a new test suite
+ TestSuite suite = new TestSuite("Ping Latency Tests");
+
+ // Run performance tests in read committed mode.
+ suite.addTest(new PingLatencyTestPerf("testPingLatency"));
+
+ return suite;
+ }
+
+ /**
+ * Accepts a timing controller from the test runner.
+ *
+ * @param timingController The timing controller to register mutliple timings with.
+ */
+ public void setTimingController(TimingController timingController)
+ {
+ _timingController = timingController;
+ }
+
+ /**
+ * Gets the timing controller passed in by the test runner.
+ *
+ * @return The timing controller passed in by the test runner.
+ */
+ public TimingController getTimingController()
+ {
+ return _timingController;
+ }
+
+ /**
+ * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until
+ * all replies have been received or a time out occurs before exiting this method.
+ *
+ * @param numPings The number of pings to send.
+ */
+ public void testPingLatency(int numPings) throws Exception
+ {
+ _logger.debug("public void testPingLatency(int numPings): called");
+
+ // Ensure that at least one ping was requeusted.
+ if (numPings == 0)
+ {
+ _logger.error("Number of pings requested was zero.");
+ }
+
+ // Get the per thread test setup to run the test through.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+ PingClient pingClient = perThreadSetup._pingClient;
+
+ // Advance the correlation id of messages to send, to make it unique for this run.
+ String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet());
+ _logger.debug("messageCorrelationId = " + messageCorrelationId);
+
+ // Initialize the count and timing controller for the new correlation id.
+ PerCorrelationId perCorrelationId = new PerCorrelationId();
+ TimingController tc = getTimingController().getControllerForCurrentThread();
+ perCorrelationId._tc = tc;
+ perCorrelationId._expectedCount = numPings;
+ perCorrelationIds.put(messageCorrelationId, perCorrelationId);
+
+ // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these
+ // messages.
+ pingClient.setChainedMessageListener(batchedResultsListener);
+
+ // Generate a sample message of the specified size.
+ ObjectMessage msg =
+ pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
+ testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME),
+ testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME));
+
+ // Send the requested number of messages, and wait until they have all been received.
+ long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
+ int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout);
+
+ // Check that all the replies were received and log a fail if they were not.
+ if (numReplies < numPings)
+ {
+ tc.completeTest(false, 0);
+ }
+
+ // Remove the chained message listener from the ping producer.
+ pingClient.removeChainedMessageListener();
+
+ // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up.
+ perCorrelationIds.remove(messageCorrelationId);
+ }
+
+ /**
+ * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
+ */
+ public void threadSetUp()
+ {
+ _logger.debug("public void threadSetUp(): called");
+
+ try
+ {
+ // Call the set up method in the super class. This creates a PingClient pinger.
+ super.threadSetUp();
+
+ // Create the chained message listener, only if it has not already been created. This is set up with the
+ // batch size property, to tell it what batch size to output results on. A synchronized block is used to
+ // ensure that only one thread creates this.
+ synchronized (this)
+ {
+ if (batchedResultsListener == null)
+ {
+ int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME));
+ batchedResultsListener = new BatchedResultsListener(batchSize);
+ }
+ }
+
+ // Get the set up that the super class created.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+
+ // Register the chained message listener on the pinger to do its asynchronous test timings from.
+ perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener);
+ }
+ catch (Exception e)
+ {
+ _logger.warn("There was an exception during per thread setup.", e);
+ }
+ }
+
+ /**
+ * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can
+ * be attached to the pinger, in order to receive notifications about every message received and the number remaining
+ * to be received. Whenever the number remaining crosses a batch size boundary this results listener outputs a test
+ * timing for the actual number of messages received in the current batch.
+ */
+ private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener
+ {
+ /** The test results logging batch size. */
+ int _batchSize;
+
+ /**
+ * Creates a results listener on the specified batch size.
+ *
+ * @param batchSize The batch size to use.
+ */
+ public BatchedResultsListener(int batchSize)
+ {
+ _batchSize = batchSize;
+ }
+
+ /**
+ * This callback method is called from all of the pingers that this test creates. It uses the correlation id
+ * from the message to identify the timing controller for the test thread that was responsible for sending those
+ * messages.
+ *
+ * @param message The message.
+ * @param remainingCount The count of messages remaining to be received with a particular correlation id.
+ *
+ * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through.
+ */
+ public void onMessage(Message message, int remainingCount) throws JMSException
+ {
+ _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called");
+
+ // Check if a batch boundary has been crossed.
+ if ((remainingCount % _batchSize) == 0)
+ {
+ // Extract the correlation id from the message.
+ String correlationId = message.getJMSCorrelationID();
+
+ // Get the details for the correlation id and check that they are not null. They can become null
+ // if a test times out.
+ PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId);
+ if (perCorrelationId != null)
+ {
+ // Get the timing controller and expected count for this correlation id.
+ TimingController tc = perCorrelationId._tc;
+ int expected = perCorrelationId._expectedCount;
+
+ // Extract the send time from the message and work out from the current time, what the ping latency was.
+ // The ping producer time stamps messages in nanoseconds.
+ long startTime = message.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME);
+ long now = System.nanoTime();
+ long pingTime = now - startTime;
+
+ // Calculate how many messages were actually received in the last batch. This will be the batch size
+ // except where the number expected is not a multiple of the batch size and this is the first remaining
+ // count to cross a batch size boundary, in which case it will be the number expected modulo the batch
+ // size.
+ int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize;
+
+ // Register a test result for the correlation id.
+ try
+ {
+
+ tc.completeTest(true, receivedInBatch, pingTime);
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore this. It means the test runner wants to stop as soon as possible.
+ _logger.warn("Got InterruptedException.", e);
+ }
+ }
+ // Else ignore, test timed out. Should log a fail here?
+ }
+ }
+ }
+
+ /**
+ * Holds state specific to each correlation id, needed to output test results. This consists of the count of
+ * the total expected number of messages, and the timing controller for the thread sending those message ids.
+ */
+ private static class PerCorrelationId
+ {
+ public int _expectedCount;
+ public TimingController _tc;
+ }
+}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingTestPerf.java
index fbc67881c2..07d7fad471 100644
--- a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingTestPerf.java
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingTestPerf.java
@@ -1,7 +1,25 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.ping;
-import java.util.Properties;
-
import javax.jms.*;
import junit.framework.Assert;
@@ -10,173 +28,89 @@ import junit.framework.TestSuite;
import org.apache.log4j.Logger;
+import org.apache.qpid.requestreply.PingPongProducer;
+
import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
+import uk.co.thebadgerset.junit.extensions.TestThreadAware;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
/**
* PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times
* simultaneously to simluate many clients/producers/connections.
- * <p/>
+ *
* <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of a single
* full round trip ping. This test may be scaled up using a suitable JUnit test runner.
- * <p/>
+ *
* <p/>The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a
* temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run,
* except if the connection is lost in which case an attempt to re-establish the setup is made.
- * <p/>
+ *
* <p/>The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that
* is the name of the temporary queue, fires off a message on the original queue and waits for a response on the
* temporary queue.
- * <p/>
+ *
* <p/>Configurable test properties: message size, transacted or not, persistent or not. Broker connection details.
- * <p/>
+ *
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* </table>
*
* @author Rupert Smith
*/
-public class PingTestPerf extends AsymptoticTestCase //implements TimingControllerAware
+public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware
{
private static Logger _logger = Logger.getLogger(PingTestPerf.class);
- /**
- * Holds the name of the property to get the test message size from.
- */
- protected static final String MESSAGE_SIZE_PROPNAME = "messagesize";
-
- /**
- * Holds the name of the property to get the ping queue name from.
- */
- protected static final String PING_DESTINATION_NAME_PROPNAME = "destinationname";
-
- /**
- * holds the queue count, if the test is being performed with multiple queues
- */
- protected static final String PING_DESTINATION_COUNT_PROPNAME = "destinationscount";
-
- /**
- * Holds the name of the property to get the test delivery mode from.
- */
- protected static final String PERSISTENT_MODE_PROPNAME = "persistent";
-
- /**
- * Holds the name of the property to get the test transactional mode from.
- */
- protected static final String TRANSACTED_PROPNAME = "transacted";
-
- /**
- * Holds the name of the property to get the test broker url from.
- */
- protected static final String BROKER_PROPNAME = "broker";
-
- /**
- * Holds the name of the property to get the test broker virtual path.
- */
- protected static final String VIRTUAL_PATH_PROPNAME = "virtualPath";
-
- /**
- * Holds the name of the property to get the waiting timeout for response messages.
- */
- protected static final String TIMEOUT_PROPNAME = "timeout";
-
- /** Holds the name of the property to get the message rate from. */
- protected static final String RATE_PROPNAME = "rate";
-
- protected static final String VERBOSE_OUTPUT_PROPNAME = "verbose";
-
- /** Holds the true or false depending on wether it is P2P test or PubSub */
- protected static final String IS_PUBSUB_PROPNAME = "pubsub";
- /**
- * Holds the size of message body to attach to the ping messages.
- */
- protected static final int MESSAGE_SIZE_DEFAULT = 1024;
-
- protected static final int BATCH_SIZE_DEFAULT = 1000;
-
- protected static final int COMMIT_BATCH_SIZE_DEFAULT = BATCH_SIZE_DEFAULT;
-
- /**
- * Holds the name of the queue to which pings are sent.
- */
- private static final String PING_DESTINATION_NAME_DEFAULT = "ping";
-
- /**
- * Holds the message delivery mode to use for the test.
- */
- protected static final boolean PERSISTENT_MODE_DEFAULT = false;
-
- /**
- * Holds the transactional mode to use for the test.
- */
- protected static final boolean TRANSACTED_DEFAULT = false;
-
- /**
- * Holds the default broker url for the test.
- */
- protected static final String BROKER_DEFAULT = "tcp://localhost:5672";
-
- /**
- * Holds the default virtual path for the test.
- */
- protected static final String VIRTUAL_PATH_DEFAULT = "/test";
-
- /**
- * Sets a default ping timeout.
- */
- protected static final long TIMEOUT_DEFAULT = 3000;
-
- /** Holds the default rate. A value of zero means infinity, only values of 1 or greater are meaningfull. */
- private static final int RATE_DEFAULT = 0;
-
- protected static final String FAIL_AFTER_COMMIT = "FailAfterCommit";
- protected static final String FAIL_BEFORE_COMMIT = "FailBeforeCommit";
- protected static final String FAIL_AFTER_SEND = "FailAfterSend";
- protected static final String FAIL_BEFORE_SEND = "FailBeforeSend";
- protected static final String COMMIT_BATCH_SIZE = "CommitBatchSize";
- protected static final String BATCH_SIZE = "BatchSize";
- protected static final String FAIL_ONCE = "FailOnce";
-
- /**
- * Thread local to hold the per-thread test setup fields.
- */
+ /** Thread local to hold the per-thread test setup fields. */
ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
- Object _lock = new Object();
-
- // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in
- // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner
- // of the test parameters to log with the results.
- protected Properties testParameters = System.getProperties();
- //private Properties testParameters = new ContextualProperties(System.getProperties());
+ /** Holds a property reader to extract the test parameters from. */
+ protected ParsedProperties testParameters = new ParsedProperties(System.getProperties());
public PingTestPerf(String name)
{
super(name);
- // Sets up the test parameters with defaults.
-
- setSystemPropertyIfNull(FAIL_AFTER_COMMIT, "false");
- setSystemPropertyIfNull(FAIL_BEFORE_COMMIT, "false");
- setSystemPropertyIfNull(FAIL_AFTER_SEND, "false");
- setSystemPropertyIfNull(FAIL_BEFORE_SEND, "false");
- setSystemPropertyIfNull(FAIL_ONCE, "true");
- setSystemPropertyIfNull(BATCH_SIZE, Integer.toString(BATCH_SIZE_DEFAULT));
- setSystemPropertyIfNull(COMMIT_BATCH_SIZE, Integer.toString(COMMIT_BATCH_SIZE_DEFAULT));
- setSystemPropertyIfNull(MESSAGE_SIZE_PROPNAME, Integer.toString(MESSAGE_SIZE_DEFAULT));
- setSystemPropertyIfNull(PING_DESTINATION_NAME_PROPNAME, PING_DESTINATION_NAME_DEFAULT);
- setSystemPropertyIfNull(PERSISTENT_MODE_PROPNAME, Boolean.toString(PERSISTENT_MODE_DEFAULT));
- setSystemPropertyIfNull(TRANSACTED_PROPNAME, Boolean.toString(TRANSACTED_DEFAULT));
- setSystemPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
- setSystemPropertyIfNull(VIRTUAL_PATH_PROPNAME, VIRTUAL_PATH_DEFAULT);
- setSystemPropertyIfNull(TIMEOUT_PROPNAME, Long.toString(TIMEOUT_DEFAULT));
- setSystemPropertyIfNull(PING_DESTINATION_COUNT_PROPNAME, Integer.toString(0));
- setSystemPropertyIfNull(VERBOSE_OUTPUT_PROPNAME, Boolean.toString(false));
- setSystemPropertyIfNull(RATE_PROPNAME, Integer.toString(RATE_DEFAULT));
- setSystemPropertyIfNull(IS_PUBSUB_PROPNAME, Boolean.toString(false));
+ // Sets up the test parameters with defaults.
+ testParameters.setPropertyIfNull(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_TX_BATCH_SIZE));
+ testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_MESSAGE_SIZE));
+ testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME,
+ PingPongProducer.DEFAULT_PING_DESTINATION_NAME);
+ testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_PERSISTENT_MODE));
+ testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_TRANSACTED));
+ testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.DEFAULT_BROKER);
+ testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.DEFAULT_USERNAME);
+ testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.DEFAULT_PASSWORD);
+ testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_PATH_PROPNAME, PingPongProducer.DEFAULT_VIRTUAL_PATH);
+ testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_OUTPUT_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_VERBOSE));
+ testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.DEFAULT_RATE));
+ testParameters.setPropertyIfNull(PingPongProducer.IS_PUBSUB_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_PUBSUB));
+ testParameters.setPropertyIfNull(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_TX_BATCH_SIZE));
+ testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.DEFAULT_TIMEOUT));
+ testParameters.setPropertyIfNull(PingPongProducer.PING_DESTINATION_COUNT_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_DESTINATION_COUNT));
+ testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_AFTER_COMMIT);
+ testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_BEFORE_COMMIT);
+ testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_AFTER_SEND);
+ testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_BEFORE_SEND);
+ testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.DEFAULT_FAIL_ONCE);
+ testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_PROPNAME, PingPongProducer.DEFAULT_UNIQUE);
}
/**
* Compile all the tests into a test suite.
+ * @return The test method testPingOk.
*/
public static Test suite()
{
@@ -187,120 +121,128 @@ public class PingTestPerf extends AsymptoticTestCase //implements TimingControll
suite.addTest(new PingTestPerf("testPingOk"));
return suite;
- //return new junit.framework.TestSuite(PingTestPerf.class);
}
- protected static void setSystemPropertyIfNull(String propName, String propValue)
+ public void testPingOk(int numPings) throws Exception
{
- if (System.getProperty(propName) == null)
+ if (numPings == 0)
{
- System.setProperty(propName, propValue);
+ Assert.fail("Number of pings requested was zero.");
}
- }
-
- public void testPing(int jim) throws Exception
- {
- testPingOk(1);
- }
- public void testPingOk(int numPings) throws Exception
- {
// Get the per thread test setup to run the test through.
PerThreadSetup perThreadSetup = threadSetup.get();
- if (numPings == 0)
+
+ if (perThreadSetup == null)
{
- _logger.error("Number of pings requested was zero.");
+ Assert.fail("Could not get per thread test setup, it was null.");
}
// Generate a sample message. This message is already time stamped and has its reply-to destination set.
ObjectMessage msg =
- perThreadSetup._pingItselfClient.getTestMessage(null,
- Integer.parseInt(testParameters.getProperty(
- MESSAGE_SIZE_PROPNAME)),
- Boolean.parseBoolean(testParameters.getProperty(
- PERSISTENT_MODE_PROPNAME)));
+ perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0),
+ testParameters.getPropertyAsInteger(
+ PingPongProducer.MESSAGE_SIZE_PROPNAME),
+ testParameters.getPropertyAsBoolean(
+ PingPongProducer.PERSISTENT_MODE_PROPNAME));
// start the test
- long timeout = Long.parseLong(testParameters.getProperty(TIMEOUT_PROPNAME));
- int numReplies = perThreadSetup._pingItselfClient.pingAndWaitForReply(msg, numPings, timeout);
+ long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME));
+ int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout);
// Fail the test if the timeout was exceeded.
- if (numReplies != numPings)
+ if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings))
{
Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = "
+ numReplies);
}
}
-
- protected void setUp() throws Exception
+ /**
+ * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
+ */
+ public void threadSetUp()
{
- // Log4j will propagate the test name as a thread local in all log output.
- // Carefull when using this, it can cause memory leaks when not cleaned up properly.
- //NDC.push(getName());
+ _logger.debug("public void threadSetUp(): called");
- // Create the test setups on a per thread basis, only if they have not already been created.
-
- if (threadSetup.get() == null)
+ try
{
PerThreadSetup perThreadSetup = new PerThreadSetup();
// Extract the test set up paramaeters.
- String brokerDetails = testParameters.getProperty(BROKER_PROPNAME);
- String username = "guest";
- String password = "guest";
- String virtualpath = testParameters.getProperty(VIRTUAL_PATH_PROPNAME);
- int destinationscount = Integer.parseInt(testParameters.getProperty(PING_DESTINATION_COUNT_PROPNAME));
- String destinationname = testParameters.getProperty(PING_DESTINATION_NAME_PROPNAME);
- boolean persistent = Boolean.parseBoolean(testParameters.getProperty(PERSISTENT_MODE_PROPNAME));
- boolean transacted = Boolean.parseBoolean(testParameters.getProperty(TRANSACTED_PROPNAME));
- String selector = null;
- boolean verbose = Boolean.parseBoolean(testParameters.getProperty(VERBOSE_OUTPUT_PROPNAME));
- int messageSize = Integer.parseInt(testParameters.getProperty(MESSAGE_SIZE_PROPNAME));
- int rate = Integer.parseInt(testParameters.getProperty(RATE_PROPNAME));
- boolean pubsub = Boolean.parseBoolean(testParameters.getProperty(IS_PUBSUB_PROPNAME));
-
- boolean afterCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_COMMIT));
- boolean beforeCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_COMMIT));
- boolean afterSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_SEND));
- boolean beforeSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_SEND));
- boolean failOnce = Boolean.parseBoolean(testParameters.getProperty(FAIL_ONCE));
+ String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME);
+ String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME);
+ String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME);
+ String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_PATH_PROPNAME);
+ String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME);
+ boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME);
+ boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME);
+ String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME);
+ boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_OUTPUT_PROPNAME);
+ int messageSize = testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME);
+ int rate = testParameters.getPropertyAsInteger(PingPongProducer.RATE_PROPNAME);
+ boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.IS_PUBSUB_PROPNAME);
+ boolean failAfterCommit = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME);
+ boolean failBeforeCommit = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME);
+ boolean failAfterSend = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_AFTER_SEND_PROPNAME);
+ boolean failBeforeSend = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME);
+ int batchSize = testParameters.getPropertyAsInteger(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME);
+ Boolean failOnce = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_ONCE_PROPNAME);
+ boolean unique = testParameters.getPropertyAsBoolean(PingPongProducer.UNIQUE_PROPNAME);
- int batchSize = Integer.parseInt(testParameters.getProperty(BATCH_SIZE));
+ // Extract the test set up paramaeters.
+ int destinationscount =
+ Integer.parseInt(testParameters.getProperty(PingPongProducer.PING_DESTINATION_COUNT_PROPNAME));
// This is synchronized because there is a race condition, which causes one connection to sleep if
- // all threads try to create connection concurrently
- synchronized (_lock)
+ // all threads try to create connection concurrently.
+ synchronized (this)
{
// Establish a client to ping a Destination and listen the reply back from same Destination
- perThreadSetup._pingItselfClient = new TestPingItself(brokerDetails, username, password, virtualpath,
- destinationname, selector, transacted, persistent,
- messageSize, verbose, afterCommit, beforeCommit,
- afterSend, beforeSend, failOnce, batchSize, destinationscount,
- rate, pubsub);
+ perThreadSetup._pingClient = new PingClient(brokerDetails, username, password, virtualPath, destinationName,
+ selector, transacted, persistent, messageSize, verbose,
+ failAfterCommit, failBeforeCommit, failAfterSend, failBeforeSend,
+ failOnce, batchSize, destinationscount, rate, pubsub, unique);
}
// Start the client connection
- perThreadSetup._pingItselfClient.getConnection().start();
+ perThreadSetup._pingClient.getConnection().start();
// Attach the per-thread set to the thread.
threadSetup.set(perThreadSetup);
}
+ catch (Exception e)
+ {
+ _logger.warn("There was an exception during per thread setup.", e);
+ }
}
- protected void tearDown() throws Exception
+ /**
+ * Performs test fixture clean
+ */
+ public void threadTearDown()
{
+ _logger.debug("public void threadTearDown(): called");
+
try
{
- /*
- if ((_pingItselfClient != null) && (_pingItselfClient.getConnection() != null))
+ // Get the per thread test fixture.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+
+ // Close the pingers so that it cleans up its connection cleanly.
+ synchronized (this)
{
- _pingItselfClient.getConnection().close();
+ if ((perThreadSetup != null) && (perThreadSetup._pingClient != null))
+ {
+ perThreadSetup._pingClient.close();
+ }
}
- */
+
+ // Ensure the per thread fixture is reclaimed.
+ threadSetup.remove();
}
- finally
+ catch (JMSException e)
{
- //NDC.pop();
+ _logger.warn("There was an exception during per thread tear down.");
}
}
@@ -309,6 +251,6 @@ public class PingTestPerf extends AsymptoticTestCase //implements TimingControll
/**
* Holds the test ping client.
*/
- protected TestPingItself _pingItselfClient;
+ protected PingClient _pingClient;
}
}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/ThrottleTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/ThrottleTestPerf.java
deleted file mode 100644
index 274c8b5fc8..0000000000
--- a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/ThrottleTestPerf.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apache.qpid.ping;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
-
-/**
- * Tests the {@link Throttle} implementation. Test timings can be taken using this test class to confirm that the
- * throttle works as it should, and what the maximum rate is that it works reliably.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Enable test timings to be taken to confirm that the throttle works at the correct rate.
- * </table>
- *
- * @author Rupert Smith
- */
-public class ThrottleTestPerf extends AsymptoticTestCase
-{
- ThreadLocal<Throttle> threadSetup = new ThreadLocal<Throttle>();
-
- public ThrottleTestPerf(String name)
- {
- super(name);
- }
-
- /**
- * Compile all the tests into a test suite.
- */
- public static Test suite()
- {
- // Build a new test suite
- TestSuite suite = new TestSuite("Ping-Pong Performance Tests");
-
- // Run performance tests in read committed mode.
- suite.addTest(new ThrottleTestPerf("testThrottle"));
-
- return suite;
- }
-
- public void testThrottle(int opsPerSecond)
- {
- Throttle throttle = threadSetup.get();
-
- // Setting this on every test call won't cause any harm, convenient to use the size parameter for this.
- throttle.setRate(opsPerSecond);
-
- // Run the test at the throttled rate, do this for the num of opsPerSecond, then every test should take 1 second.
- for (int i = 0; i < opsPerSecond; i++)
- {
- throttle.throttle();
- }
- }
-
- protected void setUp()
- {
- if (threadSetup.get() == null)
- {
- threadSetup.set(new Throttle());
- }
- }
-}
diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/requestreply/PingPongTestPerf.java
index fca133c425..3a89b1044e 100644
--- a/qpid/java/perftests/src/test/java/org/apache/qpid/requestreply/PingPongTestPerf.java
+++ b/qpid/java/perftests/src/test/java/org/apache/qpid/requestreply/PingPongTestPerf.java
@@ -1,7 +1,25 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.requestreply;
-import java.util.Properties;
-
import javax.jms.*;
import junit.framework.Assert;
@@ -11,149 +29,88 @@ import junit.framework.TestSuite;
import org.apache.log4j.Logger;
import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
/**
* PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run
* many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from
* a producer to a conumer, then the consumer replies to the message on a temporary queue.
- * <p/>
+ *
* <p/>A single run of the test using the default JUnit test runner will result in the sending and timing of the number
* of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled
- * up using a suitable JUnit test runner. See {@link TKTestRunner} or {@link PPTestRunner} for more information on how
- * to do this.
- * <p/>
+ * up using a suitable JUnit test runner. See {@link uk.co.thebadgerset.junit.extensions.TKTestRunner} for more
+ * information on how to do this.
+ *
* <p/>The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a
* temporary queue for replies. This setup is only established once for all the test repeats, but each test threads
* gets its own connection/producer/consumer, this is only re-established if the connection is lost.
- * <p/>
+ *
* <p/>The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that
* is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come
* back on the temporary queue.
- * <p/>
+ *
* <p/>Configurable test properties: message size, transacted or not, persistent or not. Broker connection details.
- * <p/>
+ *
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* </table>
*
* @author Rupert Smith
*/
-public class PingPongTestPerf extends AsymptoticTestCase //implements TimingControllerAware
+public class PingPongTestPerf extends AsymptoticTestCase
{
private static Logger _logger = Logger.getLogger(PingPongTestPerf.class);
- /**
- * Holds the name of the property to get the test message size from.
- */
- private static final String MESSAGE_SIZE_PROPNAME = "messagesize";
-
- /**
- * Holds the name of the property to get the ping queue name from.
- */
- private static final String PING_QUEUE_NAME_PROPNAME = "destinationname";
-
- /**
- * Holds the name of the property to get the test delivery mode from.
- */
- private static final String PERSISTENT_MODE_PROPNAME = "persistent";
-
- /**
- * Holds the name of the property to get the test transactional mode from.
- */
- private static final String TRANSACTED_PROPNAME = "transacted";
-
- /**
- * Holds the name of the property to get the test broker url from.
- */
- private static final String BROKER_PROPNAME = "broker";
-
- /**
- * Holds the name of the property to get the test broker virtual path.
- */
- private static final String VIRTUAL_PATH_PROPNAME = "virtualPath";
-
- /**
- * Holds the size of message body to attach to the ping messages.
- */
- private static final int MESSAGE_SIZE_DEFAULT = 0;
-
- private static final int BATCH_SIZE_DEFAULT = 2;
-
- /**
- * Holds the name of the queue to which pings are sent.
- */
- private static final String PING_QUEUE_NAME_DEFAULT = "ping";
-
- /**
- * Holds the message delivery mode to use for the test.
- */
- private static final boolean PERSISTENT_MODE_DEFAULT = false;
-
- /**
- * Holds the transactional mode to use for the test.
- */
- private static final boolean TRANSACTED_DEFAULT = false;
-
- /**
- * Holds the default broker url for the test.
- */
- private static final String BROKER_DEFAULT = "tcp://localhost:5672";
-
- /**
- * Holds the default virtual path for the test.
- */
- private static final String VIRTUAL_PATH_DEFAULT = "/test";
-
- /**
- * Sets a default ping timeout.
- */
- private static final long TIMEOUT = 15000;
-
- /** Holds the name of the property to get the message rate from. */
- private static final String RATE_PROPNAME = "rate";
-
- private static final String VERBOSE_OUTPUT_PROPNAME = "verbose";
-
- /** Holds the true or false depending on wether it is P2P test or PubSub */
- private static final String IS_PUBSUB_PROPNAME = "pubsub";
-
- /** Holds the default rate. A value of zero means infinity, only values of 1 or greater are meaningfull. */
- private static final int RATE_DEFAULT = 0;
-
- private static final String FAIL_AFTER_COMMIT = "FailAfterCommit";
- private static final String FAIL_BEFORE_COMMIT = "FailBeforeCommit";
- private static final String FAIL_AFTER_SEND = "FailAfterSend";
- private static final String FAIL_BEFORE_SEND = "FailBeforeSend";
- private static final String BATCH_SIZE = "BatchSize";
- private static final String FAIL_ONCE = "FailOnce";
-
- /**
- * Thread local to hold the per-thread test setup fields.
- */
+ /** Thread local to hold the per-thread test setup fields. */
ThreadLocal<PerThreadSetup> threadSetup = new ThreadLocal<PerThreadSetup>();
- Object _lock = new Object();
// Set up a property reader to extract the test parameters from. Once ContextualProperties is available in
// the project dependencies, use it to get property overrides for configurable tests and to notify the test runner
// of the test parameters to log with the results. It also providers some basic type parsing convenience methods.
- private Properties testParameters = System.getProperties();
- //private Properties testParameters = new ContextualProperties(System.getProperties());
+ //private Properties testParameters = System.getProperties();
+ private ParsedProperties testParameters = new ParsedProperties(System.getProperties());
public PingPongTestPerf(String name)
{
super(name);
// Sets up the test parameters with defaults.
- setSystemPropertyIfNull(BATCH_SIZE, Integer.toString(BATCH_SIZE_DEFAULT));
- setSystemPropertyIfNull(MESSAGE_SIZE_PROPNAME, Integer.toString(MESSAGE_SIZE_DEFAULT));
- setSystemPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT);
- setSystemPropertyIfNull(PERSISTENT_MODE_PROPNAME, Boolean.toString(PERSISTENT_MODE_DEFAULT));
- setSystemPropertyIfNull(TRANSACTED_PROPNAME, Boolean.toString(TRANSACTED_DEFAULT));
- setSystemPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
- setSystemPropertyIfNull(VIRTUAL_PATH_PROPNAME, VIRTUAL_PATH_DEFAULT);
- setSystemPropertyIfNull(VERBOSE_OUTPUT_PROPNAME, Boolean.toString(false));
- setSystemPropertyIfNull(RATE_PROPNAME, Integer.toString(RATE_DEFAULT));
- setSystemPropertyIfNull(IS_PUBSUB_PROPNAME, Boolean.toString(false));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_TX_BATCH_SIZE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_MESSAGE_SIZE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME,
+ PingPongProducer.DEFAULT_PING_DESTINATION_NAME);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_PERSISTENT_MODE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_TRANSACTED));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.DEFAULT_BROKER);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.DEFAULT_USERNAME);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.DEFAULT_PASSWORD);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.VIRTUAL_PATH_PROPNAME, PingPongProducer.DEFAULT_VIRTUAL_PATH);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.VERBOSE_OUTPUT_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_VERBOSE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.RATE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_RATE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.IS_PUBSUB_PROPNAME,
+ Boolean.toString(PingPongProducer.DEFAULT_PUBSUB));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_TX_BATCH_SIZE));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME,
+ Long.toString(PingPongProducer.DEFAULT_TIMEOUT));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.PING_DESTINATION_COUNT_PROPNAME,
+ Integer.toString(PingPongProducer.DEFAULT_DESTINATION_COUNT));
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_AFTER_COMMIT);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_BEFORE_COMMIT);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_AFTER_SEND);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME,
+ PingPongProducer.DEFAULT_FAIL_BEFORE_SEND);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.DEFAULT_FAIL_ONCE);
+ ParsedProperties.setSysPropertyIfNull(PingPongProducer.UNIQUE_PROPNAME, Boolean.toString(PingPongProducer.DEFAULT_UNIQUE));
}
/**
@@ -185,19 +142,15 @@ public class PingPongTestPerf extends AsymptoticTestCase //implements TimingCont
// Generate a sample message. This message is already time stamped and has its reply-to destination set.
ObjectMessage msg =
- perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestination(),
- Integer.parseInt(testParameters.getProperty(
- MESSAGE_SIZE_PROPNAME)),
- Boolean.parseBoolean(testParameters.getProperty(
- PERSISTENT_MODE_PROPNAME)));
-
- // Use the test timing controller to reset the test timer now and obtain the current time.
- // This can be used to remove the message creation time from the test.
- //TestTimingController timingUtils = getTimingController();
- //long startTime = timingUtils.restart();
+ perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0),
+ testParameters.getPropertyAsInteger(
+ PingPongProducer.MESSAGE_SIZE_PROPNAME),
+ testParameters.getPropertyAsBoolean(
+ PingPongProducer.PERSISTENT_MODE_PROPNAME));
// Send the message and wait for a reply.
- int numReplies = perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, TIMEOUT);
+ int numReplies =
+ perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.DEFAULT_TIMEOUT);
// Fail the test if the timeout was exceeded.
if (numReplies != numPings)
@@ -206,82 +159,94 @@ public class PingPongTestPerf extends AsymptoticTestCase //implements TimingCont
}
}
- protected void setUp() throws Exception
+ /**
+ * Performs test fixture creation on a per thread basis. This will only be called once for each test thread.
+ */
+ public void threadSetUp()
{
- // Log4j will propagate the test name as a thread local in all log output.
- // Carefull when using this, it can cause memory leaks when not cleaned up properly.
- //NDC.push(getName());
-
- // Create the test setups on a per thread basis, only if they have not already been created.
- if (threadSetup.get() == null)
+ try
{
PerThreadSetup perThreadSetup = new PerThreadSetup();
// Extract the test set up paramaeters.
- String brokerDetails = testParameters.getProperty(BROKER_PROPNAME);
- String username = "guest";
- String password = "guest";
- String virtualpath = testParameters.getProperty(VIRTUAL_PATH_PROPNAME);
- String queueName = testParameters.getProperty(PING_QUEUE_NAME_PROPNAME);
- boolean persistent = Boolean.parseBoolean(testParameters.getProperty(PERSISTENT_MODE_PROPNAME));
- boolean transacted = Boolean.parseBoolean(testParameters.getProperty(TRANSACTED_PROPNAME));
- String selector = null;
- boolean verbose = Boolean.parseBoolean(testParameters.getProperty(VERBOSE_OUTPUT_PROPNAME));
- int messageSize = Integer.parseInt(testParameters.getProperty(MESSAGE_SIZE_PROPNAME));
- int rate = Integer.parseInt(testParameters.getProperty(RATE_PROPNAME));
- boolean pubsub = Boolean.parseBoolean(testParameters.getProperty(IS_PUBSUB_PROPNAME));
-
- boolean afterCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_COMMIT));
- boolean beforeCommit = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_COMMIT));
- boolean afterSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_AFTER_SEND));
- boolean beforeSend = Boolean.parseBoolean(testParameters.getProperty(FAIL_BEFORE_SEND));
- int batchSize = Integer.parseInt(testParameters.getProperty(BATCH_SIZE));
- Boolean failOnce = Boolean.parseBoolean(testParameters.getProperty(FAIL_ONCE));
-
- synchronized(_lock)
+ String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME);
+ String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME);
+ String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME);
+ String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_PATH_PROPNAME);
+ String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME);
+ boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME);
+ boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME);
+ String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME);
+ boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_OUTPUT_PROPNAME);
+ int messageSize = testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME);
+ int rate = testParameters.getPropertyAsInteger(PingPongProducer.RATE_PROPNAME);
+ boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.IS_PUBSUB_PROPNAME);
+ boolean failAfterCommit = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME);
+ boolean failBeforeCommit = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME);
+ boolean failAfterSend = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_AFTER_SEND_PROPNAME);
+ boolean failBeforeSend = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME);
+ int batchSize = testParameters.getPropertyAsInteger(PingPongProducer.COMMIT_BATCH_SIZE_PROPNAME);
+ Boolean failOnce = testParameters.getPropertyAsBoolean(PingPongProducer.FAIL_ONCE_PROPNAME);
+ boolean unique = testParameters.getPropertyAsBoolean(PingPongProducer.UNIQUE_PROPNAME);
+
+ synchronized (this)
{
// Establish a bounce back client on the ping queue to bounce back the pings.
- perThreadSetup._testPingBouncer = new PingPongBouncer(brokerDetails, username, password, virtualpath,
- queueName, persistent, transacted, selector, verbose, pubsub);
+ perThreadSetup._testPingBouncer = new PingPongBouncer(brokerDetails, username, password, virtualPath,
+ destinationName, persistent, transacted, selector,
+ verbose, pubsub);
// Start the connections for client and producer running.
perThreadSetup._testPingBouncer.getConnection().start();
// Establish a ping-pong client on the ping queue to send the pings with.
- perThreadSetup._testPingProducer = new PingPongProducer(brokerDetails, username, password, virtualpath,
- queueName, selector, transacted, persistent, messageSize,
- verbose, afterCommit, beforeCommit, afterSend,
- beforeSend, failOnce, batchSize, 0, rate, pubsub);
+ perThreadSetup._testPingProducer = new PingPongProducer(brokerDetails, username, password, virtualPath,
+ destinationName, selector, transacted, persistent,
+ messageSize, verbose, failAfterCommit,
+ failBeforeCommit, failAfterSend, failBeforeSend,
+ failOnce, batchSize, 0, rate, pubsub, unique);
perThreadSetup._testPingProducer.getConnection().start();
}
// Attach the per-thread set to the thread.
threadSetup.set(perThreadSetup);
}
+ catch (Exception e)
+ {
+ _logger.warn("There was an exception during per thread setup.", e);
+ }
}
- protected void tearDown() throws Exception
+ /**
+ * Performs test fixture clean
+ */
+ public void threadTearDown()
{
+ _logger.debug("public void threadTearDown(): called");
+
try
{
- /**if ((_testPingBouncer != null) && (_testPingBouncer.getConnection() != null))
- {
- _testPingBouncer.getConnection().close();
- }
-
- if ((_testPingProducer != null) && (_testPingProducer.getConnection() != null))
- {
- _testPingProducer.getConnection().close();
- }*/
+ // Get the per thread test fixture.
+ PerThreadSetup perThreadSetup = threadSetup.get();
+
+ // Close the pingers so that it cleans up its connection cleanly.
+ synchronized (this)
+ {
+ perThreadSetup._testPingProducer.close();
+ //perThreadSetup._testPingBouncer.close();
+ }
+
+ // Ensure the per thread fixture is reclaimed.
+ threadSetup.remove();
}
- finally
+ catch (JMSException e)
{
- //NDC.pop();
+ _logger.warn("There was an exception during per thread tear down.");
}
}
- private static class PerThreadSetup
+ protected static class PerThreadSetup
{
/**
* Holds the test ping-pong producer.
diff --git a/qpid/java/pom.xml b/qpid/java/pom.xml
index e1d9805bbb..2150e61861 100644
--- a/qpid/java/pom.xml
+++ b/qpid/java/pom.xml
@@ -348,13 +348,12 @@
</executions>
</plugin>
- <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository. It will take a day or two from 16/1/2007.
+ <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository. -->
<plugin>
<groupId>uk.co.thebadgerset</groupId>
<artifactId>junit-toolkit-maven-plugin</artifactId>
- <version>0.3</version>
+ <version>0.5-SNAPSHOT</version>
</plugin>
- -->
</plugins>
</pluginManagement>
@@ -459,8 +458,8 @@
<dependency>
<groupId>uk.co.thebadgerset</groupId>
<artifactId>junit-toolkit</artifactId>
- <version>0.3</version>
- <scope>test</scope>
+ <version>0.5-SNAPSHOT</version>
+ <scope>compile</scope>
</dependency>
<!-- Qpid Version Dependencies -->