summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Anthony Giusti <kgiusti@apache.org>2011-02-08 16:16:49 +0000
committerKenneth Anthony Giusti <kgiusti@apache.org>2011-02-08 16:16:49 +0000
commitbe7946e8b700018bf204e11f650f77d188ca10e3 (patch)
treed0953e71c9235e7871cda3ea365ca4cfd7b6cc06
parentf31b86c7d7dc7e76a8008860d28049e609b4a7ab (diff)
downloadqpid-python-be7946e8b700018bf204e11f650f77d188ca10e3.tar.gz
QPID-2935: resync with latest trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid-2935@1068464 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xqpid/bin/release.sh6
-rw-r--r--qpid/cpp/Makefile.am2
-rw-r--r--qpid/cpp/bindings/qmf2/examples/cpp/agent.cpp86
-rw-r--r--qpid/cpp/bindings/qmf2/examples/python/find_agents.py57
-rw-r--r--qpid/cpp/bindings/qmf2/examples/ruby/agent_external.rb84
-rw-r--r--qpid/cpp/bindings/qmf2/examples/ruby/agent_internal.rb77
-rw-r--r--qpid/cpp/bindings/qmf2/examples/ruby/find_agents.rb63
-rw-r--r--qpid/cpp/bindings/qmf2/python/qmf2.py154
-rw-r--r--qpid/cpp/bindings/qmf2/ruby/qmf2.rb347
-rw-r--r--qpid/cpp/bindings/qpid/Makefile.am4
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/README26
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/client.pl66
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/drain.pl98
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/hello_world.pl56
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/hello_xml.pl76
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/map_receiver.pl47
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/map_sender.pl50
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/server.pl62
-rw-r--r--qpid/cpp/bindings/qpid/examples/perl/spout.pl136
-rw-r--r--qpid/cpp/bindings/qpid/perl/Makefile.am42
-rw-r--r--qpid/cpp/bindings/qpid/perl/perl.i35
-rw-r--r--qpid/cpp/bindings/swig_perl_typemaps.i330
-rw-r--r--qpid/cpp/bindings/swig_python_typemaps.i4
-rw-r--r--qpid/cpp/configure.ac14
-rw-r--r--qpid/cpp/include/qmf/AgentSession.h12
-rw-r--r--qpid/cpp/include/qmf/ConsoleEvent.h2
-rw-r--r--qpid/cpp/include/qmf/ConsoleSession.h4
-rw-r--r--qpid/cpp/include/qpid/client/ConnectionSettings.h5
-rw-r--r--qpid/cpp/src/Makefile.am1
-rw-r--r--qpid/cpp/src/qmf/Agent.cpp72
-rw-r--r--qpid/cpp/src/qmf/AgentImpl.h3
-rw-r--r--qpid/cpp/src/qmf/AgentSession.cpp82
-rw-r--r--qpid/cpp/src/qmf/ConsoleEvent.cpp2
-rw-r--r--qpid/cpp/src/qmf/ConsoleEventImpl.h6
-rw-r--r--qpid/cpp/src/qmf/ConsoleSession.cpp47
-rw-r--r--qpid/cpp/src/qmf/ConsoleSessionImpl.h3
-rw-r--r--qpid/cpp/src/qmf/SchemaId.cpp3
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp72
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.h19
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp11
-rw-r--r--qpid/cpp/src/qpid/broker/LinkRegistry.cpp11
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp3
-rw-r--r--qpid/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp2
-rw-r--r--qpid/cpp/src/qpid/client/ConnectionSettings.cpp9
-rw-r--r--qpid/cpp/src/qpid/client/SslConnector.cpp23
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp14
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h4
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateClient.cpp7
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateClient.h2
-rw-r--r--qpid/cpp/src/qpid/framing/Buffer.cpp5
-rw-r--r--qpid/cpp/src/qpid/framing/ResizableBuffer.h60
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp165
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.h27
-rw-r--r--qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp2
-rw-r--r--qpid/cpp/src/qpid/sys/Socket.h21
-rw-r--r--qpid/cpp/src/qpid/sys/SslPlugin.cpp2
-rw-r--r--qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp2
-rw-r--r--qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h1
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp47
-rw-r--r--qpid/cpp/src/qpid/sys/ssl/SslSocket.h32
-rw-r--r--qpid/cpp/src/tests/brokertest.py (renamed from qpid/python/qpid/brokertest.py)0
-rwxr-xr-xqpid/cpp/src/tests/cli_tests.py2
-rw-r--r--qpid/cpp/src/tests/cluster.mk3
-rwxr-xr-xqpid/cpp/src/tests/cluster_test_logs.py79
-rwxr-xr-xqpid/cpp/src/tests/cluster_tests.py43
-rwxr-xr-xqpid/cpp/src/tests/ssl_test40
-rwxr-xr-x[-rw-r--r--]qpid/cpp/src/tests/store.py2
-rw-r--r--qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml29
-rw-r--r--qpid/doc/book/src/Programming-In-Apache-Qpid.xml374
-rw-r--r--qpid/doc/book/src/Security.xml1197
-rw-r--r--qpid/doc/book/src/Starting-a-cluster.xml87
-rw-r--r--qpid/java/broker/etc/config.xml2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java2
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java60
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java25
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java3
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java172
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java143
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java76
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java28
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java3
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java97
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java264
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java15
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java20
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java23
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java442
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java557
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockAction.java56
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java114
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java136
-rw-r--r--qpid/java/build.xml4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java170
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java4
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java22
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java12
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java39
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java29
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java16
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java17
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java8
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java3
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java147
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java5
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java29
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java5
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java39
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java5
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java6
-rw-r--r--qpid/java/common/Composite.tpl8
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java57
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java21
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/thread/LoggingUncaughtExceptionHandler.java60
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java6
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java25
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java8
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolError.java5
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolEvent.java1
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java5
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java49
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java6
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java16
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java159
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java63
-rwxr-xr-xqpid/java/genpom51
-rw-r--r--qpid/java/lib/maven-ant-tasks-2.1.1.jarbin0 -> 1314262 bytes
-rw-r--r--qpid/java/lib/poms/backport-util-concurrent-2.2.pom25
-rw-r--r--qpid/java/lib/poms/backport-util-concurrent-2.2.xml22
-rw-r--r--qpid/java/lib/poms/commons-beanutils-core-1.8.0.xml (renamed from qpid/java/lib/poms/commons-beanutils-core-1.8.0.pom)64
-rw-r--r--qpid/java/lib/poms/commons-cli-1.0.pom76
-rw-r--r--qpid/java/lib/poms/commons-cli-1.0.xml22
-rw-r--r--qpid/java/lib/poms/commons-codec-1.3.pom178
-rw-r--r--qpid/java/lib/poms/commons-codec-1.3.xml22
-rw-r--r--qpid/java/lib/poms/commons-collections-3.2.pom420
-rw-r--r--qpid/java/lib/poms/commons-collections-3.2.xml22
-rw-r--r--qpid/java/lib/poms/commons-configuration-1.6.pom419
-rw-r--r--qpid/java/lib/poms/commons-configuration-1.6.xml22
-rw-r--r--qpid/java/lib/poms/commons-digester-1.8.1.pom316
-rw-r--r--qpid/java/lib/poms/commons-digester-1.8.1.xml22
-rw-r--r--qpid/java/lib/poms/commons-lang-2.2.pom414
-rw-r--r--qpid/java/lib/poms/commons-lang-2.2.xml22
-rw-r--r--qpid/java/lib/poms/commons-logging-1.0.4.pom165
-rw-r--r--qpid/java/lib/poms/commons-logging-1.0.4.xml22
-rw-r--r--qpid/java/lib/poms/commons-pool-1.4.pom209
-rw-r--r--qpid/java/lib/poms/commons-pool-1.4.xml22
-rw-r--r--qpid/java/lib/poms/derby-10.3.2.1.pom43
-rw-r--r--qpid/java/lib/poms/derby-10.6.1.0.xml22
-rw-r--r--qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom6
-rw-r--r--qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.xml22
-rw-r--r--qpid/java/lib/poms/junit-3.8.1.pom29
-rw-r--r--qpid/java/lib/poms/junit-3.8.1.xml22
-rw-r--r--qpid/java/lib/poms/log4j-1.2.12.pom6
-rw-r--r--qpid/java/lib/poms/log4j-1.2.12.xml22
-rw-r--r--qpid/java/lib/poms/mina-core-1.0.1.pom34
-rw-r--r--qpid/java/lib/poms/mina-core-1.0.1.xml22
-rw-r--r--qpid/java/lib/poms/mina-filter-ssl-1.0.1.pom27
-rw-r--r--qpid/java/lib/poms/mina-filter-ssl-1.0.1.xml22
-rw-r--r--qpid/java/lib/poms/org.apache.felix.framework-1.0.0.pom66
-rw-r--r--qpid/java/lib/poms/org.apache.felix.framework-2.0.5.xml22
-rw-r--r--qpid/java/lib/poms/org.osgi.core-1.0.0.pom56
-rw-r--r--qpid/java/lib/poms/org.osgi.core-1.0.0.xml22
-rw-r--r--qpid/java/lib/poms/slf4j-api-1.4.0.pom73
-rw-r--r--qpid/java/lib/poms/slf4j-api-1.6.1.xml22
-rw-r--r--qpid/java/lib/poms/slf4j-log4j12-1.4.0.pom44
-rw-r--r--qpid/java/lib/poms/slf4j-log4j12-1.6.1.xml22
-rw-r--r--qpid/java/lib/poms/xalan-2.7.0.pom19
-rw-r--r--qpid/java/lib/poms/xalan-2.7.0.xml22
-rw-r--r--qpid/java/module.xml49
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java106
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java75
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java1
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java10
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java20
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java5
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java13
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java9
-rw-r--r--qpid/java/test-profiles/08StandaloneExcludes2
-rwxr-xr-xqpid/java/test-profiles/Java010Excludes21
-rwxr-xr-xqpid/tools/src/py/qmf-tool14
-rwxr-xr-xqpid/tools/src/py/qpid-config112
-rwxr-xr-xqpid/tools/src/py/qpid-route91
196 files changed, 7668 insertions, 3978 deletions
diff --git a/qpid/bin/release.sh b/qpid/bin/release.sh
index 0154484c7f..913bbc7334 100755
--- a/qpid/bin/release.sh
+++ b/qpid/bin/release.sh
@@ -208,7 +208,7 @@ fi
if [ "JAVA" == "$JAVA" ] ; then
pushd qpid-${VER}/java
- ant build release release-bin -Dsvnversion.output=${REV}
+ ant build release release-bin release-mvn -Dsvnversion.output=${REV}
popd
cp qpid-${VER}/java/release/*.tar.gz artifacts/qpid-java-${VER}.tar.gz
@@ -216,6 +216,10 @@ if [ "JAVA" == "$JAVA" ] ; then
cp qpid-${VER}/java/client/release/*.tar.gz artifacts/qpid-java-client-${VER}.tar.gz
#cp qpid-${VER}/java/client/example/release/*.tar.gz
cp qpid-${VER}/java/management/eclipse-plugin/release/*.tar.gz qpid-${VER}/java/management/eclipse-plugin/release/*.zip artifacts/
+
+ # copy the Maven artifacts
+ cp qpid-${VER}/java/client/release/maven artifacts/
+ cp qpid-${VER}/java/common/release/maven artifacts/
fi
if [ "DOTNET" == "$DOTNET" ] ; then
diff --git a/qpid/cpp/Makefile.am b/qpid/cpp/Makefile.am
index f5f4a95be6..01b8507454 100644
--- a/qpid/cpp/Makefile.am
+++ b/qpid/cpp/Makefile.am
@@ -26,7 +26,7 @@ EXTRA_DIST = \
LICENSE NOTICE README.txt SSL RELEASE_NOTES DESIGN \
xml/cluster.xml INSTALL-WINDOWS CMakeLists.txt BuildInstallSettings.cmake \
packaging/NSIS QPID_VERSION.txt bindings/swig_python_typemaps.i \
- bindings/swig_ruby_typemaps.i
+ bindings/swig_ruby_typemaps.i bindings/swig_perl_typemaps.i
SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf bindings/qpid bindings/qmf2
diff --git a/qpid/cpp/bindings/qmf2/examples/cpp/agent.cpp b/qpid/cpp/bindings/qmf2/examples/cpp/agent.cpp
index 51643e203a..00554539eb 100644
--- a/qpid/cpp/bindings/qmf2/examples/cpp/agent.cpp
+++ b/qpid/cpp/bindings/qmf2/examples/cpp/agent.cpp
@@ -49,6 +49,7 @@ private:
Schema sch_exception;
Schema sch_control;
Schema sch_child;
+ Schema sch_event;
Data control;
DataAddr controlAddr;
@@ -115,6 +116,11 @@ void ExampleAgent::setupSchema()
echoMethod.addArgument(SchemaProperty("map", SCHEMA_DATA_MAP, "{dir:INOUT}"));
sch_control.addMethod(echoMethod);
+ SchemaMethod eventMethod("event", "{desc:'Raise an Event'}");
+ eventMethod.addArgument(SchemaProperty("text", SCHEMA_DATA_STRING, "{dir:IN}"));
+ eventMethod.addArgument(SchemaProperty("severity", SCHEMA_DATA_INT, "{dir:IN}"));
+ sch_control.addMethod(eventMethod);
+
SchemaMethod failMethod("fail", "{desc:'Expected to Fail'}");
failMethod.addArgument(SchemaProperty("useString", SCHEMA_DATA_BOOL, "{dir:IN}"));
failMethod.addArgument(SchemaProperty("stringVal", SCHEMA_DATA_STRING, "{dir:IN}"));
@@ -133,11 +139,18 @@ void ExampleAgent::setupSchema()
sch_child.addProperty(SchemaProperty("name", SCHEMA_DATA_STRING));
//
+ // Declare the event class
+ //
+ sch_event = Schema(SCHEMA_TYPE_EVENT, package, "event");
+ sch_event.addProperty(SchemaProperty("text", SCHEMA_DATA_STRING));
+
+ //
// Register our schemata with the agent session.
//
session.registerSchema(sch_exception);
session.registerSchema(sch_control);
session.registerSchema(sch_child);
+ session.registerSchema(sch_event);
}
void ExampleAgent::populateData()
@@ -173,40 +186,55 @@ bool ExampleAgent::method(AgentEvent& event)
const string& name(event.getMethodName());
control.setProperty("methodCount", control.getProperty("methodCount").asUint32() + 1);
- if (controlAddr == event.getDataAddr()) {
- if (name == "stop") {
- cout << "Stopping: message=" << event.getArguments()["message"] << endl;
- session.methodSuccess(event);
- return false;
- }
+ try {
+ if (controlAddr == event.getDataAddr()) {
+ if (name == "stop") {
+ cout << "Stopping: message=" << event.getArguments()["message"] << endl;
+ session.methodSuccess(event);
+ return false;
+ }
- if (name == "echo") {
- event.addReturnArgument("sequence", event.getArguments()["sequence"]);
- event.addReturnArgument("map", event.getArguments()["map"]);
- session.methodSuccess(event);
- return true;
- }
+ if (name == "echo") {
+ event.addReturnArgument("sequence", event.getArguments()["sequence"]);
+ event.addReturnArgument("map", event.getArguments()["map"]);
+ session.methodSuccess(event);
+ return true;
+ }
- if (name == "fail") {
- if (event.getArguments()["useString"])
- session.raiseException(event, event.getArguments()["stringVal"]);
- else {
- Data ex(sch_exception);
- ex.setProperty("whatHappened", "It Failed");
- ex.setProperty("howBad", 75);
- ex.setProperty("details", event.getArguments()["details"]);
- session.raiseException(event, ex);
+ if (name == "event") {
+ Data ev(sch_event);
+ ev.setProperty("text", event.getArguments()["text"]);
+ session.raiseEvent(ev, event.getArguments()["severity"]);
+ session.methodSuccess(event);
+ return true;
}
- }
- if (name == "create_child") {
- const string& name(event.getArguments()["name"]);
- Data child(sch_child);
- child.setProperty("name", name);
- DataAddr addr(session.addData(child, name));
- event.addReturnArgument("childAddr", addr.asMap());
- session.methodSuccess(event);
+ if (name == "fail") {
+ if (event.getArguments()["useString"])
+ session.raiseException(event, event.getArguments()["stringVal"]);
+ else {
+ Data ex(sch_exception);
+ ex.setProperty("whatHappened", "It Failed");
+ ex.setProperty("howBad", 75);
+ ex.setProperty("details", event.getArguments()["details"]);
+ session.raiseException(event, ex);
+ }
+ }
+
+ if (name == "create_child") {
+ const string& name(event.getArguments()["name"]);
+ Data child(sch_child);
+ child.setProperty("name", name);
+ DataAddr addr(session.addData(child, name));
+ event.addReturnArgument("childAddr", addr.asMap());
+ session.methodSuccess(event);
+ }
}
+ } catch (const exception& e) {
+ //
+ // Pass the exception on to the caller.
+ //
+ session.raiseException(event, e.what());
}
return true;
diff --git a/qpid/cpp/bindings/qmf2/examples/python/find_agents.py b/qpid/cpp/bindings/qmf2/examples/python/find_agents.py
new file mode 100644
index 0000000000..5fd71b3f1c
--- /dev/null
+++ b/qpid/cpp/bindings/qmf2/examples/python/find_agents.py
@@ -0,0 +1,57 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import cqpid
+import qmf2
+
+class FindAgents(qmf2.ConsoleHandler):
+
+ def __init__(self, session):
+ qmf2.ConsoleHandler.__init__(self, session)
+
+ def agentAdded(self, agent):
+ print "Agent Added: %r" % agent
+
+ def agentDeleted(self, agent, reason):
+ print "Agent Deleted: %r reason: %s" % (agent, reason)
+
+ def agentRestarted(self, agent):
+ print "Agent Restarted: %r" % agent
+
+ def agentSchemaUpdated(self, agent):
+ print "Agent Schema Updated: %r" % agent
+
+ def eventRaised(self, agent, data, timestamp, severity):
+ print "Event: data=%r time=%d sev=%d" % (data.getProperties(), timestamp, severity)
+
+
+
+url = "localhost"
+options = ""
+
+connection = cqpid.Connection(url, options)
+connection.open()
+
+session = qmf2.ConsoleSession(connection)
+session.open()
+session.setAgentFilter("[]")
+
+main = FindAgents(session)
+main.run()
+
diff --git a/qpid/cpp/bindings/qmf2/examples/ruby/agent_external.rb b/qpid/cpp/bindings/qmf2/examples/ruby/agent_external.rb
new file mode 100644
index 0000000000..75171931ed
--- /dev/null
+++ b/qpid/cpp/bindings/qmf2/examples/ruby/agent_external.rb
@@ -0,0 +1,84 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'cqpid'
+require 'qmf2'
+
+class MyAgent < Qmf2::AgentHandler
+
+ def initialize(session, data)
+ super(session)
+ @data = data
+ end
+
+ def authorize_query(query, user_id)
+ puts "Authorizing #{user_id}"
+ return true
+ end
+
+ def get_query(context, query, user_id)
+ puts "Get Query"
+ context.response(@data)
+ context.complete
+ end
+
+ def method_call(context, method_name, data_addr, args, user_id)
+ puts "Method: #{method_name}"
+ context._success
+ end
+
+end
+
+
+class Program
+
+ def initialize(url)
+ @url = url
+ @sess_options = "{allow-queries:False, external:True}"
+ end
+
+ def setup_schema(agent)
+ @cls_control = Qmf2::Schema.new(Qmf2::SCHEMA_TYPE_DATA, "org.package", "control")
+ @cls_control.add_property(Qmf2::SchemaProperty.new("state", Qmf2::SCHEMA_DATA_STRING))
+ agent.register_schema(@cls_control)
+ end
+
+ def run
+ connection = Cqpid::Connection.new(@url)
+ connection.open
+
+ session = Qmf2::AgentSession.new(connection, @sess_options)
+ session.set_vendor("package.org")
+ session.set_product("external_agent")
+ setup_schema(session)
+ session.open
+
+ @control = Qmf2::Data.new(@cls_control)
+ @control.state = "OPERATIONAL-EXTERNAL"
+ @control.set_addr(Qmf2::DataAddr.new("singleton"))
+
+ main = MyAgent.new(session, @control)
+ main.run
+ end
+end
+
+prog = Program.new("localhost")
+prog.run
+
+
diff --git a/qpid/cpp/bindings/qmf2/examples/ruby/agent_internal.rb b/qpid/cpp/bindings/qmf2/examples/ruby/agent_internal.rb
new file mode 100644
index 0000000000..fc49a885f7
--- /dev/null
+++ b/qpid/cpp/bindings/qmf2/examples/ruby/agent_internal.rb
@@ -0,0 +1,77 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'cqpid'
+require 'qmf2'
+
+class MyAgent < Qmf2::AgentHandler
+
+ def initialize(session)
+ super(session)
+ end
+
+ def authorize_query(query, user_id)
+ puts "Authorizing #{user_id}"
+ return true
+ end
+
+ def method_call(context, method_name, data_addr, args, user_id)
+ puts "Method: #{method_name}"
+ context._success
+ end
+
+end
+
+
+class Program
+
+ def initialize(url)
+ @url = url
+ @sess_options = "{allow-queries:False}"
+ end
+
+ def setup_schema(agent)
+ @cls_control = Qmf2::Schema.new(Qmf2::SCHEMA_TYPE_DATA, "org.package", "control")
+ @cls_control.add_property(Qmf2::SchemaProperty.new("state", Qmf2::SCHEMA_DATA_STRING))
+ agent.register_schema(@cls_control)
+ end
+
+ def run
+ connection = Cqpid::Connection.new(@url)
+ connection.open
+
+ session = Qmf2::AgentSession.new(connection, @sess_options)
+ session.set_vendor("package.org")
+ session.set_product("internal_agent")
+ setup_schema(session)
+ session.open
+
+ control = Qmf2::Data.new(@cls_control)
+ control.state = "OPERATIONAL"
+ session.add_data(control)
+
+ main = MyAgent.new(session)
+ main.run
+ end
+end
+
+prog = Program.new("localhost")
+prog.run
+
+
diff --git a/qpid/cpp/bindings/qmf2/examples/ruby/find_agents.rb b/qpid/cpp/bindings/qmf2/examples/ruby/find_agents.rb
new file mode 100644
index 0000000000..712e5007be
--- /dev/null
+++ b/qpid/cpp/bindings/qmf2/examples/ruby/find_agents.rb
@@ -0,0 +1,63 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'cqpid'
+require 'qmf2'
+
+class FindAgents < Qmf2::ConsoleHandler
+
+ def initialize(session)
+ super(session)
+ end
+
+ def agent_added(agent)
+ puts "Agent Added: #{agent.to_s}"
+ end
+
+ def agent_deleted(agent, reason)
+ puts "Agent Deleted: #{agent.to_s} reason: #{reason}"
+ end
+
+ def agent_restarted(agent)
+ puts "Agent Restarted: #{agent.to_s} epoch: #{agent.epoch}"
+ end
+
+ def agent_schema_updated(agent)
+ puts "Agent with new Schemata: #{agent.to_s}"
+ end
+
+ def event_raised(agent, data, timestamp, severity)
+ puts "Event Raised time=#{timestamp} sev=#{severity} data=#{data.properties}"
+ end
+end
+
+
+url = "localhost"
+options = ""
+
+connection = Cqpid::Connection.new(url, options)
+connection.open
+
+session = Qmf2::ConsoleSession.new(connection)
+session.open
+session.set_agent_filter("[]")
+
+main = FindAgents.new(session)
+main.run
+
diff --git a/qpid/cpp/bindings/qmf2/python/qmf2.py b/qpid/cpp/bindings/qmf2/python/qmf2.py
index 37efb8708b..61a5453f8e 100644
--- a/qpid/cpp/bindings/qmf2/python/qmf2.py
+++ b/qpid/cpp/bindings/qmf2/python/qmf2.py
@@ -137,6 +137,90 @@ class AgentHandler(Thread):
pass
+#===================================================================================================
+# CONSOLE HANDLER
+#===================================================================================================
+class ConsoleHandler(Thread):
+
+ def __init__(self, consoleSession):
+ Thread.__init__(self)
+ self.__session = consoleSession
+ self.__running = True
+
+ def cancel(self):
+ """
+ Stop the handler thread.
+ """
+ self.__running = None
+
+ def run(self):
+ event = cqmf2.ConsoleEvent()
+ while self.__running:
+ valid = self.__session._impl.nextEvent(event, cqpid.Duration.SECOND)
+ if valid and self.__running:
+ if event.getType() == cqmf2.CONSOLE_AGENT_ADD:
+ self.agentAdded(Agent(event.getAgent()))
+
+ elif event.getType() == cqmf2.CONSOLE_AGENT_DEL:
+ reason = 'filter'
+ if event.getAgentDelReason() == cqmf2.AGENT_DEL_AGED:
+ reason = 'aged'
+ self.agentDeleted(Agent(event.getAgent(), reason))
+
+ elif event.getType() == cqmf2.CONSOLE_AGENT_RESTART:
+ self.agentRestarted(Agent(event.getAgent()))
+
+ elif event.getType() == cqmf2.CONSOLE_AGENT_SCHEMA_UPDATE:
+ self.agentSchemaUpdated(Agent(event.getAgent()))
+
+ elif event.getType() == cqmf2.CONSOLE_EVENT:
+ self.eventRaised(Agent(event.getAgent()), Data(event.getData(0)), event.getTimestamp(), event.getSeverity())
+
+ ##
+ ## The following methods are intended to be overridden in a sub-class. They are
+ ## handlers for events that occur on QMF consoles.
+ ##
+
+ #
+ # A new agent, whose attributes match the console's agent filter, has been discovered.
+ #
+ def agentAdded(self, agent):
+ pass
+
+ #
+ # A known agent has been removed from the agent list. There are two possible reasons
+ # for agent deletion:
+ #
+ # 1) 'aged' - The agent hasn't been heard from for the maximum age interval and is
+ # presumed dead.
+ # 2) 'filter' - The agent no longer matches the console's agent-filter and has been
+ # effectively removed from the agent list. Such occurrences are likely
+ # to be seen immediately after setting the filter to a new value.
+ #
+ def agentDeleted(self, agent, reason):
+ pass
+
+ #
+ # An agent-restart was detected. This occurs when the epoch number advertised by the
+ # agent changes. It indicates that the agent in question was shut-down/crashed and
+ # restarted.
+ #
+ def agentRestarted(self, agent):
+ pass
+
+ #
+ # The agent has registered new schema information which can now be queried, if desired.
+ #
+ def agentSchemaUpdated(self, agent):
+ pass
+
+ #
+ # An agent raised an event. The 'data' argument is a Data object that contains the
+ # content of the event.
+ #
+ def eventRaised(self, agent, data, timestamp, severity):
+ pass
+
#===================================================================================================
# CONSOLE SESSION
@@ -147,6 +231,16 @@ class ConsoleSession(object):
def __init__(self, connection, options=""):
"""
+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
+ ##
+ ## domain:NAME - QMF Domain to join [default: "default"]
+ ## max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
+ ## an agent before deleting it [default: 5]
+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ ## If False: Listen only on the routable direct address
+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
+ ##
"""
self._impl = cqmf2.ConsoleSession(connection, options)
@@ -195,6 +289,24 @@ class AgentSession(object):
def __init__(self, connection, options=""):
"""
+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
+ ##
+ ## interval:N - Heartbeat interval in seconds [default: 60]
+ ## external:{True,False} - Use external data storage (queries and subscriptions are pass-through) [default: False]
+ ## allow-queries:{True,False} - If True: automatically allow all queries [default]
+ ## If False: generate an AUTH_QUERY event to allow per-query authorization
+ ## allow-methods:{True,False} - If True: automatically allow all methods [default]
+ ## If False: generate an AUTH_METHOD event to allow per-method authorization
+ ## max-subscriptions:N - Maximum number of concurrent subscription queries permitted [default: 64]
+ ## min-sub-interval:N - Minimum publish interval (in milliseconds) permitted for a subscription [default: 3000]
+ ## sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
+ ## public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
+ ## If False: QMF events are only sent to authorized subscribers
+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ ## If False: Listen only on the routable direct address
+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
+ ##
"""
self._impl = cqmf2.AgentSession(connection, options)
@@ -261,8 +373,6 @@ class AgentSession(object):
else:
self._impl.raiseException(handle, data)
- ## TODO: async and external operations
-
#===================================================================================================
# AGENT PROXY
@@ -372,6 +482,29 @@ class Query(object):
if arg1.__class__ == DataAddr:
self._impl = cqmf2.Query(arg1._impl)
+ def getAddr(self):
+ """
+ """
+ return DataAddr(self._impl.getDataAddr())
+
+ def getSchemaId(self):
+ """
+ """
+ return SchemaId(self._impl.getSchemaId())
+
+ def getPredicate(self):
+ """
+ """
+ return self._impl.getPredicate()
+
+ def matches(self, data):
+ """
+ """
+ m = data
+ if data.__class__ == Data:
+ m = data.getProperties()
+ return self._impl.matchesPredicate(m)
+
#===================================================================================================
# DATA
#===================================================================================================
@@ -411,6 +544,17 @@ class Data(object):
"""
return Agent(self._impl.getAgent())
+ def update(self, timeout=5):
+ dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout)
+ agent = self._impl.getAgent()
+ query = cqmf2.Query(self._impl.getAddr())
+ result = agent.query(query, dur)
+ if result.getType() != cqmf2.CONSOLE_QUERY_RESPONSE:
+ raise "Update query failed"
+ if result.getDataCount == 0:
+ raise "Object no longer exists on agent"
+ self._impl = cqmf2.Data(result.getData(0))
+
def getProperties(self):
"""
"""
@@ -519,11 +663,13 @@ class DataAddr(object):
"""
"""
- def __init__(self, arg):
+ def __init__(self, arg, agentName=""):
if arg.__class__ == dict:
self._impl = cqmf2.DataAddr(arg)
- else:
+ elif arg.__class__ == cqmf2.DataAddr:
self._impl = arg
+ else:
+ self._impl = cqmf2.DataAddr(arg, agentName)
def __repr__(self):
return "%s:%s" % (self.getAgentName(), self.getName())
diff --git a/qpid/cpp/bindings/qmf2/ruby/qmf2.rb b/qpid/cpp/bindings/qmf2/ruby/qmf2.rb
index 86ba72cc0b..6d1741ebc0 100644
--- a/qpid/cpp/bindings/qmf2/ruby/qmf2.rb
+++ b/qpid/cpp/bindings/qmf2/ruby/qmf2.rb
@@ -78,12 +78,273 @@ module Qmf2
end
##==============================================================================
- ## AGENT HANDLER TODO
+ ## AGENT HANDLER
##==============================================================================
class AgentHandler
- def get_query(context, query, userId); end
- def method_call(context, name, object_id, args, userId); end
+
+ def initialize(session)
+ @_session = session
+ @_running = false
+ @_thread = nil
+ end
+
+ ##
+ ## Call the "start" method to run the handler on a new thread.
+ ##
+ def start
+ @_thread = Thread.new do
+ run
+ end
+ end
+
+ ##
+ ## Request that the running thread complete and exit.
+ ##
+ def cancel
+ @_running = false
+ @_thread.join if @_thread
+ @_thread = nil
+ end
+
+ ##
+ ## Call the "run" method only if you want the handler to run on your own thread.
+ ##
+ def run
+ @_running = true
+ event = Cqmf2::AgentEvent.new
+ while @_running do
+ valid = @_session.impl.nextEvent(event, Cqpid::Duration.SECOND)
+ if valid and @_running
+ case event.getType
+ when Cqmf2::AGENT_AUTH_QUERY
+ yes = authorize_query(Query.new(event.getQuery()), event.getUserId())
+ if yes == true
+ @_session.impl.authAccept(event)
+ else
+ @_session.impl.authReject(event)
+ end
+
+ when Cqmf2::AGENT_QUERY
+ context = QueryContext.new(@_session, event)
+ get_query(context, Query.new(event.getQuery()), event.getUserId())
+
+ when Cqmf2::AGENT_METHOD
+ context = MethodContext.new(@_session, event)
+ begin
+ method_call(context, event.getMethodName(), event.getDataAddr(), event.getArguments(), event.getUserId())
+ rescue Exception => ex
+ @_session.impl.raiseException(event, "#{ex}")
+ end
+
+ end
+ end
+ end
+ end
+
+
+ ##
+ ## The following methods are intended to be overridden in a sub-class. They are
+ ## handlers for events that occur on QMF consoles.
+ ##
+
+ #
+ # This method will only be invoked if the "allow-queries" option is enabled on the
+ # agent session. When invoked, it provides the query and the authenticated user-id
+ # of the querying client.
+ #
+ # This method must return true if the query is permitted, false otherwise.
+ #
+ def authorize_query(query, user_id); end
+
+ #
+ # This method will only be invoked if the "external" option is "True" on the agent
+ # session. When invoked, the method should begin the process of responding to a data
+ # query. The authenticated user-id of the requestor is provided for informational
+ # purposes. The 'context' variable is used to provide the results back to the requestor.
+ #
+ # For each matching Data object, call context.response(data). When the query is complete,
+ # call context.complete(). After completing the query, you should not use 'context' any
+ # longer.
+ #
+ # Note: It is not necessary to process the query synchronously. If desired, this method
+ # may store the context for asynchronous processing or pass it to another thread for
+ # processing. There is no restriction on the number of contexts that may be in-flight
+ # concurrently.
+ #
+ def get_query(context, query, user_id); end
+
+ #
+ # This method is invoked when a console calls a QMF method on the agent. Supplied are
+ # a context for the response, the method name, the data address of the data object being
+ # called, the input arguments (a dictionary), and the caller's authenticated user-id.
+ #
+ # A method call can end one of two ways: Successful completion, in which the output
+ # arguments (if any) are supplied; and Exceptional completion if there is an error.
+ #
+ # Successful Completion:
+ # For each output argument, assign the value directly to context (context.arg1 = "value")
+ # Once arguments are assigned, call context._success().
+ #
+ # Exceptional Completion:
+ # Method 1: Call context._exception(data) where 'data' is a string or a Data object.
+ # Method 2: Raise an exception (raise "Error Text") synchronously in the method body.
+ #
+ # Note: Like get_query, method_call may process methods synchronously or asynchronously.
+ # This method may store the context for later asynchronous processing. There is no
+ # restriction on the number of contexts that may be in-flight concurrently.
+ #
+ # However, "Method 2" for Exceptional Completion can only be done synchronously.
+ #
+ def method_call(context, method_name, data_addr, args, user_id); end
+ end
+
+ class QueryContext
+ def initialize(agent, context)
+ @agent = agent
+ @context = context
+ end
+
+ def response(data)
+ @agent.impl.response(@context, data.impl)
+ end
+
+ def complete
+ @agent.impl.complete(@context)
+ end
+ end
+
+ class MethodContext
+ def initialize(agent, context)
+ @agent = agent
+ @context = context
+ end
+
+ def _success
+ @agent.impl.methodSuccess(@context)
+ end
+
+ def _exception(ex)
+ if ex.class == Data
+ @agent.impl.raiseException(@context, ex.impl)
+ else
+ @agent.impl.raiseException(@context, ex)
+ end
+ end
+
+ def method_missing(name_in, *args)
+ name = name_in.to_s
+ if name[name.length - 1] == 61
+ name = name[0..name.length - 2]
+ @context.impl.addReturnArgument(name, args[0])
+ else
+ super.method_missing(name_in, args)
+ end
+ end
+ end
+
+ ##==============================================================================
+ ## CONSOLE HANDLER
+ ##==============================================================================
+
+ class ConsoleHandler
+
+ def initialize(session)
+ @_session = session
+ @_running = false
+ @_thread = nil
+ end
+
+ ##
+ ## Call the "start" method to run the handler on a new thread.
+ ##
+ def start
+ @_thread = Thread.new do
+ run
+ end
+ end
+
+ ##
+ ## Request that the running thread complete and exit.
+ ##
+ def cancel
+ @_running = false
+ @_thread.join if @_thread
+ @_thread = nil
+ end
+
+ ##
+ ## Call the "run" method only if you want the handler to run on your own thread.
+ ##
+ def run
+ @_running = true
+ event = Cqmf2::ConsoleEvent.new
+ while @_running do
+ valid = @_session.impl.nextEvent(event, Cqpid::Duration.SECOND)
+ if valid and @_running
+ case event.getType
+ when Cqmf2::CONSOLE_AGENT_ADD
+ agent_added(Agent.new(event.getAgent))
+
+ when Cqmf2::CONSOLE_AGENT_DEL
+ reason = :filter
+ reason = :aged if event.getAgentDelReason == Cqmf2::AGENT_DEL_AGED
+ agent_deleted(Agent.new(event.getAgent), reason)
+
+ when Cqmf2::CONSOLE_AGENT_RESTART
+ agent_restarted(Agent.new(event.getAgent))
+
+ when Cqmf2::CONSOLE_AGENT_SCHEMA_UPDATE
+ agent_schema_updated(Agent.new(event.getAgent))
+
+ when Cqmf2::CONSOLE_EVENT
+ event_raised(Agent.new(event.getAgent), Data.new(event.getData(0)), event.getTimestamp, event.getSeverity)
+
+ end
+ end
+ end
+ end
+
+
+ ##
+ ## The following methods are intended to be overridden in a sub-class. They are
+ ## handlers for events that occur on QMF consoles.
+ ##
+
+ #
+ # A new agent, whose attributes match the console's agent filter, has been discovered.
+ #
+ def agent_added(agent); end
+
+ #
+ # A known agent has been removed from the agent list. There are two possible reasons
+ # for agent deletion:
+ #
+ # 1) :aged - The agent hasn't been heard from for the maximum age interval and is
+ # presumed dead.
+ # 2) :filter - The agent no longer matches the console's agent-filter and has been
+ # effectively removed from the agent list. Such occurrences are likely
+ # to be seen immediately after setting the filter to a new value.
+ #
+ def agent_deleted(agent, reason); end
+
+ #
+ # An agent-restart was detected. This occurs when the epoch number advertised by the
+ # agent changes. It indicates that the agent in question was shut-down/crashed and
+ # restarted.
+ #
+ def agent_restarted(agent); end
+
+ #
+ # The agent has registered new schema information which can now be queried, if desired.
+ #
+ def agent_schema_updated(agent); end
+
+ #
+ # An agent raised an event. The 'data' argument is a Data object that contains the
+ # content of the event.
+ #
+ def event_raised(agent, data, timestamp, severity); end
end
##==============================================================================
@@ -93,6 +354,16 @@ module Qmf2
class ConsoleSession
attr_reader :impl
+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
+ ##
+ ## domain:NAME - QMF Domain to join [default: "default"]
+ ## max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
+ ## an agent before deleting it [default: 5]
+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ ## If False: Listen only on the routable direct address
+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
+ ##
def initialize(connection, options="")
@impl = Cqmf2::ConsoleSession.new(connection, options)
end
@@ -124,6 +395,24 @@ module Qmf2
class AgentSession
attr_reader :impl
+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
+ ##
+ ## interval:N - Heartbeat interval in seconds [default: 60]
+ ## external:{True,False} - Use external data storage (queries and subscriptions are pass-through) [default: False]
+ ## allow-queries:{True,False} - If True: automatically allow all queries [default]
+ ## If False: generate an AUTH_QUERY event to allow per-query authorization
+ ## allow-methods:{True,False} - If True: automatically allow all methods [default]
+ ## If False: generate an AUTH_METHOD event to allow per-method authorization
+ ## max-subscriptions:N - Maximum number of concurrent subscription queries permitted [default: 64]
+ ## min-sub-interval:N - Minimum publish interval (in milliseconds) permitted for a subscription [default: 3000]
+ ## sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
+ ## public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
+ ## If False: QMF events are only sent to authorized subscribers
+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ ## If False: Listen only on the routable direct address
+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
+ ##
def initialize(connection, options="")
@impl = Cqmf2::AgentSession.new(connection, options)
end
@@ -137,25 +426,13 @@ module Qmf2
def close() @impl.close end
def register_schema(cls) @impl.registerSchema(cls.impl) end
- def add_data(data, name="", persistent=:false)
+ def add_data(data, name="", persistent=false)
DataAddr.new(@impl.addData(data.impl, name, persistent))
end
def del_data(addr)
@impl.del_data(addr.impl)
end
-
- def method_success(handle)
- @impl.methodSuccess(handle)
- end
-
- def raise_exception(handle, data)
- if data.class == Data
- @impl.raiseException(handle, data.impl)
- else
- @impl.raiseException(handle, data)
- end
- end
end
##==============================================================================
@@ -228,7 +505,7 @@ module Qmf2
end
##==============================================================================
- ## QUERY TODO
+ ## QUERY
##==============================================================================
class Query
@@ -238,6 +515,16 @@ module Qmf2
@impl = Cqmf2::Query.new(arg1.impl)
end
end
+
+ def addr() DataAddr.new(@impl.getDataAddr()) end
+ def schema_id() SchemaId.new(@impl.getSchemaId()) end
+ def predicate() @impl.getPredicate() end
+
+ def matches?(data)
+ map = data
+ map = data.properties if data.class == Data
+ @impl.matchesPredicate(map)
+ end
end
##==============================================================================
@@ -248,16 +535,17 @@ module Qmf2
attr_reader :impl
def initialize(arg=nil)
+ @schema = nil
if arg == nil
@impl = Cqmf2::Data.new
elsif arg.class == Cqmf2::Data
@impl = arg
elsif arg.class == Schema
- @impl = Cqmf2::Data(arg.impl)
+ @impl = Cqmf2::Data.new(arg.impl)
+ @schema = arg
else
raise "Unsupported initializer for Data"
end
- @schema = nil
end
def to_s
@@ -271,6 +559,10 @@ module Qmf2
return nil
end
+ def set_addr(addr)
+ @impl.setAddr(addr.impl)
+ end
+
def addr
if @impl.hasAddr
return DataAddr.new(@impl.getAddr)
@@ -282,6 +574,17 @@ module Qmf2
return Agent.new(@impl.getAgent)
end
+ def update(timeout=5)
+ dur = Cqpid::Duration.new(Cqpid::Duration.SECOND.getMilliseconds * timeout)
+ agent = @impl.getAgent
+ query = Cqmf2::Query.new(@impl.getAddr)
+ result = agent.query(query, dur)
+ raise "Update query failed" if result.getType != Cqmf2::CONSOLE_QUERY_RESPONSE
+ raise "Object no longer exists on agent" if result.getDataCount == 0
+ @impl = Cqmf2::Data.new(result.getData(0))
+ return nil
+ end
+
def properties
return @impl.getProperties
end
@@ -392,11 +695,13 @@ module Qmf2
class DataAddr
attr_reader :impl
- def initialize(arg)
+ def initialize(arg, agentName="")
if arg.class == Hash
@impl = Cqmf2::DataAddr.new(arg)
- else
+ elsif arg.class == Cqmf2::DataAddr
@impl = arg
+ else
+ @impl = Cqmf2::DataAddr.new(arg, agentName)
end
end
diff --git a/qpid/cpp/bindings/qpid/Makefile.am b/qpid/cpp/bindings/qpid/Makefile.am
index 13ec310a9e..07b51e6c64 100644
--- a/qpid/cpp/bindings/qpid/Makefile.am
+++ b/qpid/cpp/bindings/qpid/Makefile.am
@@ -30,4 +30,8 @@ if HAVE_PYTHON_DEVEL
SUBDIRS += python
endif
+if HAVE_PERL_DEVEL
+SUBDIRS += perl
+endif
+
endif
diff --git a/qpid/cpp/bindings/qpid/examples/perl/README b/qpid/cpp/bindings/qpid/examples/perl/README
new file mode 100644
index 0000000000..1e113f1fa0
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/README
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+The examples in this directory are written against the raw Perl
+binding ("cqpid"). This binding is identical to the C++ messaging (in
+namespace qpid::messaging).
+
+It is desired that a layer will be written over this interface (called
+"qpid") that provides a more Perl-specific API. When this occurs,
+these examples will be changed to use the new Perl API.
+
diff --git a/qpid/cpp/bindings/qpid/examples/perl/client.pl b/qpid/cpp/bindings/qpid/examples/perl/client.pl
new file mode 100644
index 0000000000..93eec88e07
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/client.pl
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+
+use cqpid;
+
+my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672";
+my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : "";
+
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+$connection->open();
+my $session = $connection->createSession();
+
+my $sender = $session->createSender("service_queue");
+
+#create temp queue & receiver...
+my $responseQueue = new cqpid::Address("#response-queue; {create:always, delete:always}");
+my $receiver = $session->createReceiver($responseQueue);
+
+#Now send some messages...
+
+my @s = (
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe."
+ );
+
+my $request = new cqpid::Message();
+$request->setReplyTo($responseQueue);
+for (my $i=0; $i<4; $i++) {
+ $request->setContent($s[$i]);
+ $sender->send($request);
+ my $response = $receiver->fetch();
+ print $request->getContent() . " -> " . $response->getContent() . "\n";
+}
+
+$connection->close();
+};
+
+if ($@) {
+ die $@;
+}
+
+
diff --git a/qpid/cpp/bindings/qpid/examples/perl/drain.pl b/qpid/cpp/bindings/qpid/examples/perl/drain.pl
new file mode 100644
index 0000000000..8010b7c95b
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/drain.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+
+use cqpid;
+use Getopt::Long;
+
+my $url = "127.0.0.1";
+my $timeout = 60;
+my $forever = 0;
+my $count = 1;
+my $connectionOptions = "";
+my $address = "amq.direct";
+
+my $result = GetOptions(
+ "broker|b=s" => \ $url,
+ "timeout|t=i" => \ $timeout,
+ "forever|f" => \ $forever,
+ "connection-options=s" => \ $connectionOptions,
+ "count|c=i" => \ $count,
+);
+
+if (! $result) {
+ print "Usage: perl drain.pl [OPTIONS]\n";
+}
+
+if ($#ARGV ge 0) {
+ $address = $ARGV[0]
+}
+
+sub getTimeout {
+ return ($forever) ? $cqpid::Duration::FOREVER : new cqpid::Duration($timeout*1000);
+}
+
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+ my $receiver = $session->createReceiver($address);
+ my $timeout = getTimeout();
+
+ my $message = new cqpid::Message();
+ my $i = 0;
+
+ while($receiver->fetch($message, $timeout)) {
+ print "Message(properties=" . $message->getProperties() . ",content='";
+ if ($message->getContentType() eq "amqp/map") {
+ my $content = cqpid::decodeMap($message);
+ map{ print "\n$_ => $content->{$_}"; } keys %{$content};
+ }
+ else {
+ print $message->getContent();
+ }
+ print "')\n";
+
+ my $replyto = $message->getReplyTo();
+ if ($replyto->getName()) {
+ print "Replying to " . $message->getReplyTo()->str() . "...\n";
+ my $sender = $session->createSender($replyto);
+ my $response = new cqpid::Message("received by the server.");
+ $sender->send($response);
+ }
+ $session->acknowledge();
+
+ if ($count and (++$i ==$count)) {
+ last;
+ }
+ }
+ $receiver->close();
+ $session->close();
+ $connection->close();
+};
+
+if ($@) {
+ $connection->close();
+ die $@;
+}
+
diff --git a/qpid/cpp/bindings/qpid/examples/perl/hello_world.pl b/qpid/cpp/bindings/qpid/examples/perl/hello_world.pl
new file mode 100644
index 0000000000..cf2f05f8b7
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/hello_world.pl
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+use Data::Dumper;
+
+use cqpid;
+
+my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672";
+my $address = ( @ARGV > 1 ) ? $ARGV[0] : "amq.topic";
+my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : "";
+
+my $connection = new cqpid::Connection($broker, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+
+ my $receiver = $session->createReceiver($address);
+ my $sender = $session->createSender($address);
+
+ $sender->send(new cqpid::Message("Hello world!"));
+
+ #my $duration = new cqpid::Duration(1000);
+ #print ">>>" . $duration->getMilliseconds() . "\n";
+
+ my $message = $receiver->fetch($cqpid::Duration::SECOND);
+
+ #$message->setDurable(1);
+ #print "Durable: " . $message->getDurable() . "\n";
+ #print Dumper($message->getProperties());
+
+ print $message->getContent() . "\n";
+ $session->acknowledge();
+
+ $connection->close();
+};
+
+die $@ if ($@);
diff --git a/qpid/cpp/bindings/qpid/examples/perl/hello_xml.pl b/qpid/cpp/bindings/qpid/examples/perl/hello_xml.pl
new file mode 100644
index 0000000000..c48a5225c2
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/hello_xml.pl
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+
+use cqpid;
+
+my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672";
+my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : "";
+
+my $query = <<END;
+ let \$w := ./weather
+ return \$w/station = 'Raleigh-Durham International Airport (KRDU)'
+ and \$w/temperature_f > 50
+ and \$w/temperature_f - \$w/dewpoint > 5
+ and \$w/wind_speed_mph > 7
+ and \$w/wind_speed_mph < 20
+END
+
+my $address = <<END;
+xml-exchange; {
+create: always,
+node: { type: topic, x-declare: { type: xml } },
+link: {
+x-bindings: [{ exchange: xml-exchange, key: weather, arguments: { xquery:" $query" } }]
+}}
+END
+
+
+my $connection = new cqpid::Connection($broker, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+
+ my $receiver = $session->createReceiver($address);
+
+ my $message = new cqpid::Message();
+
+ my $content = <<END;
+ <weather>
+ <station>Raleigh-Durham International Airport (KRDU)</station>
+ <wind_speed_mph>16</wind_speed_mph>
+ <temperature_f>70</temperature_f>
+ <dewpoint>35</dewpoint>
+ </weather>
+END
+
+ $message->setContent($content);
+ my $sender = $session->createSender('xml-exchange/weather');
+ $sender->send($message);
+
+ my $response = $receiver->fetch();
+ print $response->getContent() . "\n";
+
+ $connection->close();
+};
+
+die $@ if ($@);
diff --git a/qpid/cpp/bindings/qpid/examples/perl/map_receiver.pl b/qpid/cpp/bindings/qpid/examples/perl/map_receiver.pl
new file mode 100644
index 0000000000..e3e8a201dd
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/map_receiver.pl
@@ -0,0 +1,47 @@
+#! /usr/bin/perl5
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+use Data::Dumper;
+
+use cqpid;
+
+my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672";
+my $address = ( @ARGV > 1 ) ? $ARGV[0] : "message_queue; {create: always}";
+my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : "";
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+ my $receiver = $session->createReceiver($address);
+
+ my $content = cqpid::decodeMap($receiver->fetch());
+ #my $content = cqpid::decodeList($receiver->fetch());
+
+ print Dumper($content);
+
+ $session->acknowledge();
+ $receiver->close();
+ $connection->close();
+};
+
+die $@ if ($@);
diff --git a/qpid/cpp/bindings/qpid/examples/perl/map_sender.pl b/qpid/cpp/bindings/qpid/examples/perl/map_sender.pl
new file mode 100644
index 0000000000..095acce0ab
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/map_sender.pl
@@ -0,0 +1,50 @@
+#! /usr/bin/perl5
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+use Data::Dumper;
+
+use cqpid;
+
+my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672";
+my $address = ( @ARGV > 1 ) ? $ARGV[1] : "message_queue; {create: always}";
+my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[2] : "";
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+ $connection->open();
+
+ my $session = $connection->createSession();
+ my $sender = $session->createSender($address);
+
+ my $message = new cqpid::Message();
+ my $content = { id => 987654321,
+ name => "Widget",
+ percent => sprintf("%.2f", 0.99),
+ colours => [ qw (red green white) ],
+ };
+ cqpid::encode($content, $message);
+ $sender->send($message, 1);
+
+ $connection->close();
+};
+
+die $@ if ($@);
diff --git a/qpid/cpp/bindings/qpid/examples/perl/server.pl b/qpid/cpp/bindings/qpid/examples/perl/server.pl
new file mode 100644
index 0000000000..0c64f15c66
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/server.pl
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+
+use cqpid;
+
+my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672";
+my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : "";
+
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+
+ my $receiver = $session->createReceiver("service_queue; {create: always}");
+
+ while (1) {
+ my $request = $receiver->fetch();
+ my $address = $request->getReplyTo();
+ if ($address) {
+ my $sender = $session->createSender($address);
+ my $s = $request->getContent();
+ $s = uc($s);
+ my $response = new cqpid::Message($s);
+ $sender->send($response);
+ print "Processed request: " . $request->getContent() . " -> " . $response->getContent() . "\n";
+ $session->acknowledge();
+ }
+ else {
+ print "Error: no reply address specified for request: " . $request->getContent() . "\n";
+ $session->reject($request);
+ }
+ }
+
+$connection->close();
+};
+
+if ($@) {
+ die $@;
+}
+
+
diff --git a/qpid/cpp/bindings/qpid/examples/perl/spout.pl b/qpid/cpp/bindings/qpid/examples/perl/spout.pl
new file mode 100644
index 0000000000..50773a4fe2
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/examples/perl/spout.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+use strict;
+use warnings;
+
+use cqpid;
+use Getopt::Long;
+use Time::Local;
+
+my $url = "127.0.0.1";
+my $timeout = 0;
+my $count = 1;
+my $id = "";
+my $replyto = "";
+my @properties;
+my @entries;
+my $content = "";
+my $connectionOptions = "";
+my $address = "amq.direct";
+
+my $result = GetOptions(
+ "broker|b=s" => \ $url,
+ "timeout|t=i" => \ $timeout,
+ "count|c=i" => \ $count,
+ "id|i=s" => \ $id,
+ "replyto=s" => \ $replyto,
+ "property|p=s@" => \ @properties,
+ "map|m=s@" => \ @entries,
+ "content=s" => \ $content,
+ "connection-options=s" => \ $connectionOptions,
+);
+
+
+if (! $result) {
+ print "Usage: perl drain.pl [OPTIONS]\n";
+}
+
+
+if ($#ARGV ge 0) {
+ $address = $ARGV[0]
+}
+
+
+sub setEntries {
+ my ($content) = @_;
+
+ foreach (@entries) {
+ my ($name, $value) = split("=", $_);
+ $content->{$name} = $value;
+ }
+}
+
+
+sub setProperties {
+ my ($message) = @_;
+
+ foreach (@properties) {
+ my ($name, $value) = split("=", $_);
+ $message->getProperties()->{$name} = $value;
+ }
+}
+
+my $connection = new cqpid::Connection($url, $connectionOptions);
+
+eval {
+ $connection->open();
+ my $session = $connection->createSession();
+ my $sender = $session->createSender($address);
+
+ my $message = new cqpid::Message();
+ setProperties($message) if (@properties);
+ if (@entries) {
+ my $content = {};
+ setEntries($content);
+ cqpid::encode($content, $message);
+ }
+ elsif ($content) {
+ $message->setContent($content);
+ $message->setContentType("text/plain");
+ }
+
+ my $receiver;
+ if ($replyto) {
+ my $responseQueue = new cqpid::Address($replyto);
+ $receiver = $session->createReceiver($responseQueue);
+ $message->setReplyTo($responseQueue);
+ }
+
+ my $start = localtime;
+ my @s = split(/[:\s]/, $start);
+ my $s = "$s[3]$s[4]$s[5]";
+ my $n = $s;
+
+ for (my $i = 0;
+ ($i < $count || $count == 0) and
+ ($timeout == 0 || abs($n - $s) < $timeout);
+ $i++) {
+
+ $sender->send($message);
+
+ if ($receiver) {
+ my $response = $receiver->fetch();
+ print "$i -> " . $response->getContent() . "\n";
+ }
+
+ my $now = localtime;
+ my @n = split(/[:\s]/, $now);
+ my $n = "$n[3]$n[4]$n[5]";
+ }
+ $session->sync();
+ $connection->close();
+};
+
+if ($@) {
+ $connection->close();
+ die $@;
+}
+
+
diff --git a/qpid/cpp/bindings/qpid/perl/Makefile.am b/qpid/cpp/bindings/qpid/perl/Makefile.am
new file mode 100644
index 0000000000..982d493ba0
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/perl/Makefile.am
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_PERL_DEVEL
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC)
+
+EXTRA_DIST = perl.i
+BUILT_SOURCES = cqpid.cpp
+SWIG_FLAGS = -w362,401
+
+cqpid.cpp: $(srcdir)/perl.i $(srcdir)/../qpid.i $(srcdir)/../../swig_perl_typemaps.i
+ $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid.cpp $(srcdir)/perl.i
+
+lib_LTLIBRARIES = cqpid.la
+cqpid_PERL = cqpid.pm
+
+cqpid_la_LDFLAGS = -avoid-version -module -shared
+cqpid_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \
+ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la
+cqpid_la_CXXFLAGS = $(INCLUDES)
+nodist_cqpid_la_SOURCES = cqpid.cpp
+
+CLEANFILES = cqpid.cpp cqpid.pm
+
+endif # HAVE_PERL_DEVEL
diff --git a/qpid/cpp/bindings/qpid/perl/perl.i b/qpid/cpp/bindings/qpid/perl/perl.i
new file mode 100644
index 0000000000..b7ae0568b6
--- /dev/null
+++ b/qpid/cpp/bindings/qpid/perl/perl.i
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%module cqpid
+%include "std_string.i"
+%include "../../swig_perl_typemaps.i"
+
+/* Define the general-purpose exception handling */
+%exception {
+ try {
+ $action
+ }
+ catch (qpid::messaging::MessagingException& mex) {
+ Perl_croak(aTHX_ mex.what());
+ }
+}
+
+%include "../qpid.i"
+
diff --git a/qpid/cpp/bindings/swig_perl_typemaps.i b/qpid/cpp/bindings/swig_perl_typemaps.i
new file mode 100644
index 0000000000..831576a7d4
--- /dev/null
+++ b/qpid/cpp/bindings/swig_perl_typemaps.i
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%wrapper %{
+
+#include <stdarg.h>
+
+ SV* MapToPerl(const qpid::types::Variant::Map*);
+ SV* ListToPerl(const qpid::types::Variant::List*);
+ void PerlToMap(SV*, qpid::types::Variant::Map*);
+ void PerlToList(SV*, qpid::types::Variant::List*);
+
+ qpid::types::Variant PerlToVariant(SV* value) {
+ if (SvROK(value)) {
+ if (SvTYPE(SvRV(value)) == SVt_PVHV) {
+ qpid::types::Variant::Map map;
+ PerlToMap(value, &map);
+ return qpid::types::Variant(map);
+ }
+ else if (SvTYPE(SvRV(value)) == SVt_PVAV) {
+ qpid::types::Variant::List list;
+ PerlToList(value, &list);
+ return qpid::types::Variant(list);
+ }
+ }
+ else {
+ if (SvIOK(value)) {
+ return qpid::types::Variant((int64_t) SvIV(value));
+ }
+ else if (SvNOK(value)) {
+ return qpid::types::Variant((float)SvNV(value));
+ }
+ else if (SvPOK(value)) {
+ return qpid::types::Variant(std::string(SvPV_nolen(value)));
+ }
+ }
+ return qpid::types::Variant();
+ }
+
+ SV* VariantToPerl(const qpid::types::Variant* v) {
+ SV* result = newSV(0);
+ try {
+ switch (v->getType()) {
+ case qpid::types::VAR_VOID: {
+ sv_setiv(result, (IV)0);
+ break;
+ }
+ case qpid::types::VAR_BOOL : {
+ result = boolSV(v->asBool());
+ break;
+ }
+ case qpid::types::VAR_UINT8 :
+ case qpid::types::VAR_UINT16 :
+ case qpid::types::VAR_UINT32 : {
+ sv_setuv(result, (UV)v->asUint32());
+ break;
+ }
+ case qpid::types::VAR_UINT64 : {
+ sv_setuv(result, (UV)v->asUint64());
+ break;
+ }
+ case qpid::types::VAR_INT8 :
+ case qpid::types::VAR_INT16 :
+ case qpid::types::VAR_INT32 : {
+ sv_setiv(result, (IV)v->asInt32());
+ break;
+ }
+ case qpid::types::VAR_INT64 : {
+ sv_setiv(result, (IV)v->asInt64());
+ break;
+ }
+ case qpid::types::VAR_FLOAT : {
+ sv_setnv(result, (double)v->asFloat());
+ break;
+ }
+ case qpid::types::VAR_DOUBLE : {
+ sv_setnv(result, (double)v->asDouble());
+ break;
+ }
+ case qpid::types::VAR_STRING : {
+ const std::string val(v->asString());
+ result = newSVpvn(val.c_str(), val.size());
+ break;
+ }
+ case qpid::types::VAR_MAP : {
+ result = MapToPerl(&(v->asMap()));
+ break;
+ }
+ case qpid::types::VAR_LIST : {
+ result = ListToPerl(&(v->asList()));
+ break;
+ }
+ case qpid::types::VAR_UUID : {
+ }
+ }
+ } catch (qpid::types::Exception& ex) {
+ Perl_croak(aTHX_ ex.what());
+ }
+
+ return result;
+ }
+
+ SV* MapToPerl(const qpid::types::Variant::Map* map) {
+ SV *result = newSV(0);
+ HV *hv = (HV *)sv_2mortal((SV *)newHV());
+ qpid::types::Variant::Map::const_iterator iter;
+ for (iter = map->begin(); iter != map->end(); iter++) {
+ const std::string key(iter->first);
+ SV* perlval = VariantToPerl(&(iter->second));
+ hv_store(hv, key.c_str(), key.size(), perlval, 0);
+ }
+ SvSetSV(result, newRV_noinc((SV *)hv));
+ return result;
+ }
+
+ SV* ListToPerl(const qpid::types::Variant::List* list) {
+ SV* result = newSV(0);
+ AV* av = (AV *)sv_2mortal((SV *)newAV());
+ qpid::types::Variant::List::const_iterator iter;
+ for (iter = list->begin(); iter != list->end(); iter++) {
+ SV* perlval = VariantToPerl(&(*iter));
+ av_push(av, perlval);
+ }
+ SvSetSV(result, newRV_noinc((SV *)av));
+ return result;
+ }
+
+ void PerlToMap(SV* hash, qpid::types::Variant::Map* map) {
+ map->clear();
+ HV* hv = (HV *)SvRV(hash);
+ HE* he;
+ while((he = hv_iternext(hv)) != NULL) {
+ SV* svkey = HeSVKEY_force(he);
+ SV* svval = HeVAL(he);
+ (*map)[std::string(SvPV_nolen(svkey))] = PerlToVariant(svval);
+ }
+ }
+
+ void PerlToList(SV* ary, qpid::types::Variant::List* list) {
+ list->clear();
+ AV * av = (AV *)SvRV(ary);
+ I32 len = av_len(av) + 1;
+ if (len > 0) {
+ for (I32 i = 0; i < len; i++) {
+ list->push_back(PerlToVariant(*av_fetch(av, i, 0)));
+ }
+ }
+ }
+%}
+
+%typemap (in) void * {
+ $1 = (void *)SvIV($input);
+}
+
+%typemap (out) void * {
+ sv_setiv($result, (IV)$1);
+ argvi++;
+}
+
+%typemap (in) uint16_t, uint32_t, uint64_t {
+ if (SvIOK($input)) {
+ $1 = ($1_ltype)SvUV($input);
+ }
+ else {
+ SWIG_exception_fail(SWIG_ValueError, "not an integer");
+ }
+}
+
+%typemap (out) uint16_t, uint32_t, uint64_t {
+ sv_setuv($result, (UV)$1);
+ argvi++;
+}
+
+%typemap (in) int32_t, int64_t {
+ if (SvIOK($input)) {
+ $1 = ($1_ltype)SvIV($input);
+ }
+ else {
+ SWIG_exception_fail(SWIG_ValueError, "not an integer");
+ }
+}
+
+%typemap (out) int32_t, int64_t {
+ sv_setiv($result, (IV)$1);
+ argvi++;
+}
+
+%typemap(in) bool {
+ $1 = (bool)SvTRUE($input);
+}
+
+%typemap (out) bool {
+ $result = boolSV($1);
+ argvi++;
+}
+
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT64) uint64_t {
+ $1 = SvIOK($input) ? 1 : 0;
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT32) uint32_t {
+ $1 = SvIOK($input) ? 1 : 0;
+}
+
+
+/*
+ * Variant types: C++ --> Perl
+ */
+%typemap(out) qpid::types::Variant::Map {
+ $result = MapToPerl(&$1);
+ argvi++;
+}
+
+%typemap(out) qpid::types::Variant::Map& {
+ $result = MapToPerl($1);
+ argvi++;
+}
+
+%typemap(out) qpid::types::Variant::List {
+ $result = ListToPerl(&$1);
+ argvi++;
+}
+
+%typemap(out) qpid::types::Variant::List& {
+ $result = ListToPerl($1);
+ argvi++;
+}
+
+%typemap(out) qpid::types::Variant& {
+ $result = VariantToPerl($1);
+ argvi++;
+}
+
+
+/*
+ * Variant types: Perl --> C++
+ */
+%typemap(in) qpid::types::Variant& {
+ $1 = new qpid::types::Variant(PerlToVariant($input));
+}
+
+%typemap(in) qpid::types::Variant::Map& {
+ $1 = new qpid::types::Variant::Map();
+ PerlToMap($input, $1);
+
+}
+
+%typemap(in) qpid::types::Variant::List& {
+ $1 = new qpid::types::Variant::List();
+ PerlToList($input, $1);
+
+}
+
+%typemap(in) const qpid::types::Variant::Map const & {
+ $1 = new qpid::types::Variant::Map();
+ PerlToMap($input, $1);
+}
+
+%typemap(in) const qpid::types::Variant::List const & {
+ $1 = new qpid::types::Variant::List();
+ PerlToList($input, $1);
+}
+
+%typemap(freearg) qpid::types::Variant& {
+ delete $1;
+}
+
+%typemap(freearg) qpid::types::Variant::Map& {
+ delete $1;
+}
+
+%typemap(freearg) qpid::types::Variant::List& {
+ delete $1;
+}
+
+
+/*
+ * Variant types: typecheck maps
+ */
+%typemap(typecheck) qpid::types::Variant::Map& {
+ $1 = (SvTYPE(SvRV($input)) == SVt_PVHV) ? 1 : 0;
+}
+
+%typemap(typecheck) qpid::types::Variant::List& {
+ $1 = (SvTYPE(SvRV($input)) == SVt_PVAV) ? 1 : 0;
+}
+
+%typemap(typecheck) qpid::types::Variant& {
+ $1 = (SvIOK($input) ||
+ SvNOK($input) ||
+ SvPOK($input) ) ? 1 : 0;
+}
+
+%typemap(typecheck) const qpid::types::Variant::Map const & {
+ $1 = (SvTYPE(SvRV($input)) == SVt_PVHV) ? 1 : 0;
+}
+
+%typemap(typecheck) const qpid::types::Variant::List const & {
+ $1 = (SvTYPE(SvRV($input)) == SVt_PVAV) ? 1 : 0;
+}
+
+%typemap(typecheck) const qpid::types::Variant const & {
+ $1 = (SvIOK($input) ||
+ SvNOK($input) ||
+ SvPOK($input) ) ? 1 : 0;
+}
+
+/* No boolean type for perl.
+ Boolean is simply and integer in perl
+*/
+%typecheck(SWIG_TYPECHECK_BOOL) bool {
+ $1 = (SvIOK($input)) ? 1 : 0;
+}
diff --git a/qpid/cpp/bindings/swig_python_typemaps.i b/qpid/cpp/bindings/swig_python_typemaps.i
index a233641940..b69784a6de 100644
--- a/qpid/cpp/bindings/swig_python_typemaps.i
+++ b/qpid/cpp/bindings/swig_python_typemaps.i
@@ -32,11 +32,11 @@ typedef int Py_ssize_t;
void PyToList(PyObject*, qpid::types::Variant::List*);
qpid::types::Variant PyToVariant(PyObject* value) {
+ if (PyBool_Check(value)) return qpid::types::Variant(bool(PyInt_AS_LONG(value) ? true : false));
if (PyFloat_Check(value)) return qpid::types::Variant(PyFloat_AS_DOUBLE(value));
- if (PyString_Check(value)) return qpid::types::Variant(std::string(PyString_AS_STRING(value)));
if (PyInt_Check(value)) return qpid::types::Variant(int64_t(PyInt_AS_LONG(value)));
if (PyLong_Check(value)) return qpid::types::Variant(int64_t(PyLong_AsLongLong(value)));
- if (PyBool_Check(value)) return qpid::types::Variant(bool(PyInt_AS_LONG(value) ? true : false));
+ if (PyString_Check(value)) return qpid::types::Variant(std::string(PyString_AS_STRING(value)));
if (PyDict_Check(value)) {
qpid::types::Variant::Map map;
PyToMap(value, &map);
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
index 546dd0d280..ee1bade1c9 100644
--- a/qpid/cpp/configure.ac
+++ b/qpid/cpp/configure.ac
@@ -198,7 +198,7 @@ if test -n "$RUBY" ; then
fi
AM_CONDITIONAL([HAVE_RUBY_DEVEL], [test -f $RUBY_INC/ruby.h && test -n "$SWIG"])
-# Python bindings: To build python wrappers, the ruby-devel files must be present.
+# Python bindings: To build python wrappers, the python-devel files must be present.
AM_PATH_PYTHON()
if test -n "$PYTHON" ; then
@@ -228,6 +228,17 @@ if test -n "$PYTHON" ; then
fi
AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test -f $PYTHON_INC/Python.h && test -n "$SWIG"])
+
+# Perl bindings:
+
+AC_CHECK_PROG([PERL], [perl], [perl])
+if test -n "$PERL"; then
+ PERL_ARCHLIB=`perl -MConfig -e 'print "$Config{archlib}";'`
+ AC_CHECK_FILE( ["$PERL_ARCHLIB/CORE/perl.h"],
+ [AC_SUBST([PERL_INC], ["$PERL_ARCHLIB/CORE"])] )
+fi
+AM_CONDITIONAL([HAVE_PERL_DEVEL], [test -n "$PERL" && test -n "$SWIG" && test -n "$PERL_INC"])
+
specdir=`pwd`/$srcdir/../specs
AMQP_FINAL_XML=$specdir/amqp.0-10-qpid-errata.xml
AC_SUBST(AMQP_FINAL_XML)
@@ -526,6 +537,7 @@ AC_CONFIG_FILES([
bindings/qpid/Makefile
bindings/qpid/ruby/Makefile
bindings/qpid/python/Makefile
+ bindings/qpid/perl/Makefile
bindings/qmf/Makefile
bindings/qmf/ruby/Makefile
bindings/qmf/python/Makefile
diff --git a/qpid/cpp/include/qmf/AgentSession.h b/qpid/cpp/include/qmf/AgentSession.h
index 090017779f..9e29d6b54b 100644
--- a/qpid/cpp/include/qmf/AgentSession.h
+++ b/qpid/cpp/include/qmf/AgentSession.h
@@ -67,6 +67,10 @@ namespace qmf {
* sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
* public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
* If False: QMF events are only sent to authorized subscribers
+ * listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ * If False: Listen only on the routable direct address
+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
*/
QMF_EXTERN AgentSession(qpid::messaging::Connection&, const std::string& options="");
@@ -161,8 +165,14 @@ namespace qmf {
/**
* Raise an event to be sent into the QMF network.
+ *
+ * @param data - A data object that contains the event contents.
+ * @param severity - Explicit severity (from qmf/SchemaTypes.h). If omitted, the severity is set to
+ * the default severity for the data's schema. If the data has no schema, the severity defaults
+ * to SEV_NOTICE.
*/
- QMF_EXTERN void raiseEvent(const Data&);
+ QMF_EXTERN void raiseEvent(const Data& data);
+ QMF_EXTERN void raiseEvent(const Data& data, int severity);
#ifndef SWIG
private:
diff --git a/qpid/cpp/include/qmf/ConsoleEvent.h b/qpid/cpp/include/qmf/ConsoleEvent.h
index 54272334a4..b836b629af 100644
--- a/qpid/cpp/include/qmf/ConsoleEvent.h
+++ b/qpid/cpp/include/qmf/ConsoleEvent.h
@@ -74,6 +74,8 @@ namespace qmf {
QMF_EXTERN Data getData(uint32_t) const;
QMF_EXTERN bool isFinal() const;
QMF_EXTERN const qpid::types::Variant::Map& getArguments() const;
+ QMF_EXTERN int getSeverity() const;
+ QMF_EXTERN uint64_t getTimestamp() const;
#ifndef SWIG
private:
diff --git a/qpid/cpp/include/qmf/ConsoleSession.h b/qpid/cpp/include/qmf/ConsoleSession.h
index ba8b3de92f..0c73e7a6db 100644
--- a/qpid/cpp/include/qmf/ConsoleSession.h
+++ b/qpid/cpp/include/qmf/ConsoleSession.h
@@ -57,6 +57,10 @@ namespace qmf {
* domain:NAME - QMF Domain to join [default: "default"]
* max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
* an agent before deleting it [default: 5]
+ * listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
+ * If False: Listen only on the routable direct address
+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
*/
QMF_EXTERN ConsoleSession(qpid::messaging::Connection&, const std::string& options="");
QMF_EXTERN void setDomain(const std::string&);
diff --git a/qpid/cpp/include/qpid/client/ConnectionSettings.h b/qpid/cpp/include/qpid/client/ConnectionSettings.h
index bf060e73bb..1c2ee28b1b 100644
--- a/qpid/cpp/include/qpid/client/ConnectionSettings.h
+++ b/qpid/cpp/include/qpid/client/ConnectionSettings.h
@@ -122,6 +122,11 @@ struct ConnectionSettings {
* layer. 0 means no security layer allowed.
*/
unsigned int maxSsf;
+ /**
+ * SSL cert-name for the connection. Overrides global SSL
+ * settings. Used only when a client connects to the broker.
+ */
+ std::string sslCertName;
};
}} // namespace qpid::client
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index b197017327..8f00cefb33 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -373,6 +373,7 @@ libqpidcommon_la_SOURCES += \
qpid/framing/BodyHandler.cpp \
qpid/framing/BodyHandler.h \
qpid/framing/Buffer.cpp \
+ qpid/framing/ResizableBuffer.h \
qpid/framing/ChannelHandler.h \
qpid/framing/Endian.cpp \
qpid/framing/Endian.h \
diff --git a/qpid/cpp/src/qmf/Agent.cpp b/qpid/cpp/src/qmf/Agent.cpp
index 3a385b3741..176cadf0c1 100644
--- a/qpid/cpp/src/qmf/Agent.cpp
+++ b/qpid/cpp/src/qmf/Agent.cpp
@@ -71,8 +71,8 @@ Schema Agent::getSchema(const SchemaId& s, Duration t) { return impl->getSchema(
AgentImpl::AgentImpl(const std::string& n, uint32_t e, ConsoleSessionImpl& s) :
- name(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0),
- nextCorrelator(1), schemaCache(s.schemaCache)
+ name(n), directSubject(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0),
+ sender(session.directSender), nextCorrelator(1), schemaCache(s.schemaCache)
{
}
@@ -83,6 +83,11 @@ void AgentImpl::setAttribute(const std::string& k, const qpid::types::Variant& v
try {
capability = v.asUint32();
} catch (std::exception&) {}
+ if (k == "_direct_subject")
+ try {
+ directSubject = v.asString();
+ sender = session.topicSender;
+ } catch (std::exception&) {}
}
const Variant& AgentImpl::getAttribute(const string& k) const
@@ -114,7 +119,9 @@ ConsoleEvent AgentImpl::query(const Query& query, Duration timeout)
context->cond.wait(context->lock,
qpid::sys::AbsTime(qpid::sys::now(),
qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
- if (context->response.isValid() && context->response.isFinal())
+ if (context->response.isValid() &&
+ ((context->response.getType() == CONSOLE_QUERY_RESPONSE && context->response.isFinal()) ||
+ (context->response.getType() == CONSOLE_EXCEPTION)))
result = context->response;
else {
auto_ptr<ConsoleEventImpl> impl(new ConsoleEventImpl(CONSOLE_EXCEPTION));
@@ -370,9 +377,43 @@ void AgentImpl::handleMethodResponse(const Variant::Map& response, const Message
}
-void AgentImpl::handleDataIndication(const Variant::List&, const Message&)
+void AgentImpl::handleDataIndication(const Variant::List& list, const Message& msg)
{
- // TODO
+ Variant::Map::const_iterator aIter;
+ const Variant::Map& props(msg.getProperties());
+ boost::shared_ptr<SyncContext> context;
+
+ aIter = props.find("qmf.content");
+ if (aIter == props.end())
+ return;
+
+ string content_type(aIter->second.asString());
+ if (content_type != "_event")
+ return;
+
+ for (Variant::List::const_iterator lIter = list.begin(); lIter != list.end(); lIter++) {
+ const Variant::Map& eventMap(lIter->asMap());
+ Data data(new DataImpl(eventMap, this));
+ int severity(SEV_NOTICE);
+ uint64_t timestamp(0);
+
+ aIter = eventMap.find("_severity");
+ if (aIter != eventMap.end())
+ severity = int(aIter->second.asInt8());
+
+ aIter = eventMap.find("_timestamp");
+ if (aIter != eventMap.end())
+ timestamp = aIter->second.asUint64();
+
+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_EVENT));
+ eventImpl->setAgent(this);
+ eventImpl->addData(data);
+ eventImpl->setSeverity(severity);
+ eventImpl->setTimestamp(timestamp);
+ if (data.hasSchema())
+ learnSchemaId(data.getSchemaId());
+ session.enqueueEvent(eventImpl.release());
+ }
}
@@ -514,9 +555,12 @@ void AgentImpl::sendQuery(const Query& query, uint32_t correlator)
msg.setReplyTo(session.replyAddress);
msg.setCorrelationId(boost::lexical_cast<string>(correlator));
- msg.setSubject(name);
+ msg.setSubject(directSubject);
+ if (!session.authUser.empty())
+ msg.setUserId(session.authUser);
encode(QueryImplAccess::get(query).asMap(), msg);
- session.directSender.send(msg);
+ if (sender.isValid())
+ sender.send(msg);
QPID_LOG(trace, "SENT QueryRequest to=" << name);
}
@@ -538,9 +582,12 @@ void AgentImpl::sendMethod(const string& method, const Variant::Map& args, const
msg.setReplyTo(session.replyAddress);
msg.setCorrelationId(boost::lexical_cast<string>(correlator));
- msg.setSubject(name);
+ msg.setSubject(directSubject);
+ if (!session.authUser.empty())
+ msg.setUserId(session.authUser);
encode(map, msg);
- session.directSender.send(msg);
+ if (sender.isValid())
+ sender.send(msg);
QPID_LOG(trace, "SENT MethodRequest method=" << method << " to=" << name);
}
@@ -578,8 +625,11 @@ void AgentImpl::sendSchemaRequest(const SchemaId& id)
Message msg;
msg.setReplyTo(session.replyAddress);
msg.setContent(content);
- msg.setSubject(name);
- session.directSender.send(msg);
+ msg.setSubject(directSubject);
+ if (!session.authUser.empty())
+ msg.setUserId(session.authUser);
+ if (sender.isValid())
+ sender.send(msg);
QPID_LOG(trace, "SENT V1SchemaRequest to=" << name);
}
diff --git a/qpid/cpp/src/qmf/AgentImpl.h b/qpid/cpp/src/qmf/AgentImpl.h
index b852570418..7fa4f4373a 100644
--- a/qpid/cpp/src/qmf/AgentImpl.h
+++ b/qpid/cpp/src/qmf/AgentImpl.h
@@ -29,6 +29,7 @@
#include "qmf/SchemaCache.h"
#include "qpid/messaging/Session.h"
#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Sender.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/Condition.h"
#include <boost/shared_ptr.hpp>
@@ -90,11 +91,13 @@ namespace qmf {
mutable qpid::sys::Mutex lock;
std::string name;
+ std::string directSubject;
uint32_t epoch;
ConsoleSessionImpl& session;
bool touched;
uint32_t untouchedCount;
uint32_t capability;
+ qpid::messaging::Sender sender;
qpid::types::Variant::Map attributes;
uint32_t nextCorrelator;
std::map<uint32_t, boost::shared_ptr<SyncContext> > contextMap;
diff --git a/qpid/cpp/src/qmf/AgentSession.cpp b/qpid/cpp/src/qmf/AgentSession.cpp
index 24356519d7..30176a8c01 100644
--- a/qpid/cpp/src/qmf/AgentSession.cpp
+++ b/qpid/cpp/src/qmf/AgentSession.cpp
@@ -85,6 +85,7 @@ namespace qmf {
void complete(AgentEvent& e);
void methodSuccess(AgentEvent& e);
void raiseEvent(const Data& d);
+ void raiseEvent(const Data& d, int s);
private:
typedef map<DataAddr, Data, DataAddrCompare> DataIndex;
@@ -116,6 +117,8 @@ namespace qmf {
uint32_t minSubInterval;
uint32_t subLifetime;
bool publicEvents;
+ bool listenOnDirect;
+ bool strictSecurity;
uint64_t schemaUpdateTime;
string directBase;
string topicBase;
@@ -169,6 +172,7 @@ void AgentSession::response(AgentEvent& e, const Data& d) { impl->response(e, d)
void AgentSession::complete(AgentEvent& e) { impl->complete(e); }
void AgentSession::methodSuccess(AgentEvent& e) { impl->methodSuccess(e); }
void AgentSession::raiseEvent(const Data& d) { impl->raiseEvent(d); }
+void AgentSession::raiseEvent(const Data& d, int s) { impl->raiseEvent(d, s); }
//========================================================================================
// Impl Method Bodies
@@ -179,6 +183,7 @@ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) :
bootSequence(1), interval(60), lastHeartbeat(0), lastVisit(0), forceHeartbeat(false),
externalStorage(false), autoAllowQueries(true), autoAllowMethods(true),
maxSubscriptions(64), minSubInterval(3000), subLifetime(300), publicEvents(true),
+ listenOnDirect(true), strictSecurity(false),
schemaUpdateTime(uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now())))
{
//
@@ -231,6 +236,14 @@ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) :
iter = optMap.find("public-events");
if (iter != optMap.end())
publicEvents = iter->second.asBool();
+
+ iter = optMap.find("listen-on-direct");
+ if (iter != optMap.end())
+ listenOnDirect = iter->second.asBool();
+
+ iter = optMap.find("strict-security");
+ if (iter != optMap.end())
+ strictSecurity = iter->second.asBool();
}
}
@@ -248,6 +261,8 @@ void AgentSessionImpl::open()
throw QmfException("The session is already open");
const string addrArgs(";{create:never,node:{type:topic}}");
+ const string routableAddr("direct-agent.route." + qpid::types::Uuid(true).str());
+ attributes["_direct_subject"] = routableAddr;
// Establish messaging addresses
setAgentName();
@@ -256,13 +271,20 @@ void AgentSessionImpl::open()
// Create AMQP session, receivers, and senders
session = connection.createSession();
- Receiver directRx = session.createReceiver(directBase + "/" + agentName + addrArgs);
+ Receiver directRx;
+ Receiver routableDirectRx = session.createReceiver(topicBase + "/" + routableAddr + addrArgs);
Receiver topicRx = session.createReceiver(topicBase + "/console.#" + addrArgs);
- directRx.setCapacity(64);
+ if (listenOnDirect && !strictSecurity) {
+ directRx = session.createReceiver(directBase + "/" + agentName + addrArgs);
+ directRx.setCapacity(64);
+ }
+
+ routableDirectRx.setCapacity(64);
topicRx.setCapacity(64);
- directSender = session.createSender(directBase + addrArgs);
+ if (!strictSecurity)
+ directSender = session.createSender(directBase + addrArgs);
topicSender = session.createSender(topicBase + addrArgs);
// Start the receiver thread
@@ -506,24 +528,50 @@ void AgentSessionImpl::methodSuccess(AgentEvent& event)
void AgentSessionImpl::raiseEvent(const Data& data)
{
+ int severity(SEV_NOTICE);
+ if (data.hasSchema()) {
+ const Schema& schema(DataImplAccess::get(data).getSchema());
+ if (schema.isValid())
+ severity = schema.getDefaultSeverity();
+ }
+
+ raiseEvent(data, severity);
+}
+
+
+void AgentSessionImpl::raiseEvent(const Data& data, int severity)
+{
Message msg;
Variant::Map map;
Variant::Map& headers(msg.getProperties());
+ string subject("agent.ind.event");
- // TODO: add severity.package.class to key
- // or modify to send only to subscriptions with matching queries
+ if (data.hasSchema()) {
+ const SchemaId& schemaId(data.getSchemaId());
+ if (schemaId.getType() != SCHEMA_TYPE_EVENT)
+ throw QmfException("Cannot call raiseEvent on data that is not an Event");
+ subject = subject + "." + schemaId.getPackageName() + "." + schemaId.getName();
+ }
+
+ if (severity < SEV_EMERG || severity > SEV_DEBUG)
+ throw QmfException("Invalid severity value");
headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_INDICATION;
headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_DATA_INDICATION;
headers[protocol::HEADER_KEY_CONTENT] = protocol::HEADER_CONTENT_EVENT;
headers[protocol::HEADER_KEY_AGENT] = agentName;
headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
- msg.setSubject("agent.ind.event");
-
- encode(DataImplAccess::get(data).asMap(), msg);
+ msg.setSubject(subject);
+
+ Variant::List list;
+ Variant::Map dataAsMap(DataImplAccess::get(data).asMap());
+ dataAsMap["_severity"] = severity;
+ dataAsMap["_timestamp"] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
+ list.push_back(dataAsMap);
+ encode(list, msg);
topicSender.send(msg);
- QPID_LOG(trace, "SENT EventIndication to=agent.ind.event");
+ QPID_LOG(trace, "SENT EventIndication to=" << subject);
}
@@ -794,6 +842,17 @@ void AgentSessionImpl::dispatch(Message msg)
const Variant::Map& properties(msg.getProperties());
Variant::Map::const_iterator iter;
+ //
+ // If strict-security is enabled, make sure that reply-to address complies with the
+ // strict-security addressing pattern (i.e. start with 'qmf.<domain>.topic/direct-console.').
+ //
+ if (strictSecurity && msg.getReplyTo()) {
+ if (msg.getReplyTo().getName() != topicBase || msg.getReplyTo().getSubject().find("direct-console.") != 0) {
+ QPID_LOG(warning, "Reply-to violates strict-security policy: " << msg.getReplyTo().str());
+ return;
+ }
+ }
+
iter = properties.find(protocol::HEADER_KEY_APP_ID);
if (iter != properties.end() && iter->second.asString() == protocol::HEADER_APP_ID_QMF) {
//
@@ -892,6 +951,11 @@ void AgentSessionImpl::send(Message msg, const Address& to)
{
Sender sender;
+ if (strictSecurity && to.getName() != topicBase) {
+ QPID_LOG(warning, "Address violates strict-security policy: " << to);
+ return;
+ }
+
if (to.getName() == directBase) {
msg.setSubject(to.getSubject());
sender = directSender;
diff --git a/qpid/cpp/src/qmf/ConsoleEvent.cpp b/qpid/cpp/src/qmf/ConsoleEvent.cpp
index b76abc83c6..b2a5e321c7 100644
--- a/qpid/cpp/src/qmf/ConsoleEvent.cpp
+++ b/qpid/cpp/src/qmf/ConsoleEvent.cpp
@@ -44,6 +44,8 @@ uint32_t ConsoleEvent::getDataCount() const { return impl->getDataCount(); }
Data ConsoleEvent::getData(uint32_t i) const { return impl->getData(i); }
bool ConsoleEvent::isFinal() const { return impl->isFinal(); }
const Variant::Map& ConsoleEvent::getArguments() const { return impl->getArguments(); }
+int ConsoleEvent::getSeverity() const { return impl->getSeverity(); }
+uint64_t ConsoleEvent::getTimestamp() const { return impl->getTimestamp(); }
SchemaId ConsoleEventImpl::getSchemaId(uint32_t i) const
diff --git a/qpid/cpp/src/qmf/ConsoleEventImpl.h b/qpid/cpp/src/qmf/ConsoleEventImpl.h
index e7acb54152..9843971456 100644
--- a/qpid/cpp/src/qmf/ConsoleEventImpl.h
+++ b/qpid/cpp/src/qmf/ConsoleEventImpl.h
@@ -42,6 +42,8 @@ namespace qmf {
void addSchemaId(const SchemaId& s) { newSchemaIds.push_back(SchemaId(s)); }
void setFinal() { final = true; }
void setArguments(const qpid::types::Variant::Map& a) { arguments = a; }
+ void setSeverity(int s) { severity = s; }
+ void setTimestamp(uint64_t t) { timestamp = t; }
//
// Methods from API handle
@@ -56,6 +58,8 @@ namespace qmf {
Data getData(uint32_t i) const;
bool isFinal() const { return final; }
const qpid::types::Variant::Map& getArguments() const { return arguments; }
+ int getSeverity() const { return severity; }
+ uint64_t getTimestamp() const { return timestamp; }
private:
const ConsoleEventCode eventType;
@@ -66,6 +70,8 @@ namespace qmf {
std::list<Data> dataList;
std::list<SchemaId> newSchemaIds;
qpid::types::Variant::Map arguments;
+ int severity;
+ uint64_t timestamp;
};
struct ConsoleEventImplAccess
diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
index f327170c5e..bb4458a0b9 100644
--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
+++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
@@ -36,6 +36,7 @@ using namespace qmf;
using qpid::messaging::Address;
using qpid::messaging::Connection;
using qpid::messaging::Receiver;
+using qpid::messaging::Sender;
using qpid::messaging::Duration;
using qpid::messaging::Message;
using qpid::types::Variant;
@@ -64,9 +65,9 @@ Subscription ConsoleSession::subscribe(const string& q, const string& f, const s
//========================================================================================
ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
- connection(c), domain("default"), maxAgentAgeMinutes(5), opened(false),
- thread(0), threadCanceled(false),
- lastVisit(0), lastAgePass(0), connectedBrokerInAgentList(false), schemaCache(new SchemaCache())
+ connection(c), domain("default"), authUser(c.getAuthenticatedUsername()), maxAgentAgeMinutes(5),
+ opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
+ connectedBrokerInAgentList(false), schemaCache(new SchemaCache())
{
if (!options.empty()) {
qpid::messaging::AddressParser parser(options);
@@ -82,6 +83,14 @@ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
iter = optMap.find("max-agent-age");
if (iter != optMap.end())
maxAgentAgeMinutes = iter->second.asUint32();
+
+ iter = optMap.find("listen-on-direct");
+ if (iter != optMap.end())
+ listenOnDirect = iter->second.asBool();
+
+ iter = optMap.find("strict-security");
+ if (iter != optMap.end())
+ strictSecurity = iter->second.asBool();
}
}
@@ -148,24 +157,26 @@ void ConsoleSessionImpl::open()
directBase = "qmf." + domain + ".direct";
topicBase = "qmf." + domain + ".topic";
- string myKey("qmf-console-" + qpid::types::Uuid(true).str());
+ string myKey("direct-console." + qpid::types::Uuid(true).str());
- replyAddress = Address(directBase + "/" + myKey + ";{node:{type:topic}}");
+ replyAddress = Address(topicBase + "/" + myKey + ";{node:{type:topic}}");
// Create AMQP session, receivers, and senders
session = connection.createSession();
Receiver directRx = session.createReceiver(replyAddress);
Receiver topicRx = session.createReceiver(topicBase + "/agent.#"); // TODO: be more discriminating
- Receiver legacyRx = session.createReceiver("amq.direct/" + myKey + ";{node:{type:topic}}");
+ if (!strictSecurity) {
+ Receiver legacyRx = session.createReceiver("amq.direct/" + myKey + ";{node:{type:topic}}");
+ legacyRx.setCapacity(64);
+ directSender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
+ directSender.setCapacity(128);
+ }
directRx.setCapacity(64);
topicRx.setCapacity(128);
- legacyRx.setCapacity(64);
- directSender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
topicSender = session.createSender(topicBase + ";{create:never,node:{type:topic}}");
- directSender.setCapacity(64);
topicSender.setCapacity(128);
// Start the receiver thread
@@ -371,7 +382,9 @@ void ConsoleSessionImpl::sendBrokerLocate()
msg.setCorrelationId("broker-locate");
msg.setSubject("broker");
- directSender.send(msg);
+ Sender sender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
+ sender.send(msg);
+ sender.close();
QPID_LOG(trace, "SENT AgentLocate to broker");
}
@@ -468,6 +481,7 @@ void ConsoleSessionImpl::handleAgentUpdate(const string& agentName, const Varian
//
// This is a refresh of an agent we are already tracking.
//
+ bool detectedRestart(false);
agent = aIter->second;
AgentImpl& impl(AgentImplAccess::get(agent));
impl.touch();
@@ -480,6 +494,7 @@ void ConsoleSessionImpl::handleAgentUpdate(const string& agentName, const Varian
auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_RESTART));
eventImpl->setAgent(agent);
enqueueEventLH(ConsoleEvent(eventImpl.release()));
+ detectedRestart = true;
}
iter = attrs.find(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP);
@@ -488,12 +503,14 @@ void ConsoleSessionImpl::handleAgentUpdate(const string& agentName, const Varian
if (ts > impl.getAttribute(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP).asUint64()) {
//
// The agent has added new schema entries since we last heard from it.
- // Enqueue a notification.
+ // Update the attribute and, if this doesn't accompany a restart, enqueue a notification.
//
- auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_SCHEMA_UPDATE));
- eventImpl->setAgent(agent);
- impl.setAttribute(iter->first, iter->second);
- enqueueEventLH(ConsoleEvent(eventImpl.release()));
+ if (!detectedRestart) {
+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_SCHEMA_UPDATE));
+ eventImpl->setAgent(agent);
+ enqueueEventLH(ConsoleEvent(eventImpl.release()));
+ }
+ impl.setAttribute(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP, iter->second);
}
}
}
diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
index 85ddc820f4..e495c1c1e8 100644
--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
@@ -72,7 +72,10 @@ namespace qmf {
qpid::messaging::Sender directSender;
qpid::messaging::Sender topicSender;
std::string domain;
+ std::string authUser;
uint32_t maxAgentAgeMinutes;
+ bool listenOnDirect;
+ bool strictSecurity;
Query agentQuery;
bool opened;
std::queue<ConsoleEvent> eventQueue;
diff --git a/qpid/cpp/src/qmf/SchemaId.cpp b/qpid/cpp/src/qmf/SchemaId.cpp
index 110a2553fd..25fa9915ae 100644
--- a/qpid/cpp/src/qmf/SchemaId.cpp
+++ b/qpid/cpp/src/qmf/SchemaId.cpp
@@ -78,7 +78,8 @@ Variant::Map SchemaIdImpl::asMap() const
result["_type"] = "_data";
else
result["_type"] = "_event";
- result["_hash"] = hash;
+ if (!hash.isNull())
+ result["_hash"] = hash;
return result;
}
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index 35011db38e..593d403a11 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -362,7 +362,7 @@ uint32_t ManagementAgentImpl::pollCallbacks(uint32_t callLimit)
methodQueue.pop_front();
{
sys::Mutex::ScopedUnlock unlock(agentLock);
- invokeMethodRequest(item->body, item->cid, item->replyTo, item->userId);
+ invokeMethodRequest(item->body, item->cid, item->replyToExchange, item->replyToKey, item->userId);
delete item;
}
}
@@ -497,7 +497,7 @@ void ManagementAgentImpl::sendHeartbeat()
QPID_LOG(trace, "SENT AgentHeartbeat name=" << name_address);
}
-void ManagementAgentImpl::sendException(const string& replyToKey, const string& cid,
+void ManagementAgentImpl::sendException(const string& rte, const string& rtk, const string& cid,
const string& text, uint32_t code)
{
Variant::Map map;
@@ -514,12 +514,12 @@ void ManagementAgentImpl::sendException(const string& replyToKey, const string&
map["_values"] = values;
MapCodec::encode(map, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyToKey);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
QPID_LOG(trace, "SENT Exception code=" << code <<" text=" << text);
}
-void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& replyTo)
+void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& rte, const string& rtk)
{
sys::Mutex::ScopedLock lock(agentLock);
string packageName;
@@ -546,7 +546,7 @@ void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequenc
outBuffer.putRawData(body);
outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+ connThreadBody.sendBuffer(outBuffer, outLen, rte, rtk);
QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name);
}
@@ -561,7 +561,7 @@ void ManagementAgentImpl::handleConsoleAddedIndication()
QPID_LOG(trace, "RCVD ConsoleAddedInd");
}
-void ManagementAgentImpl::invokeMethodRequest(const string& body, const string& cid, const string& replyTo, const string& userId)
+void ManagementAgentImpl::invokeMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId)
{
string methodName;
bool failed = false;
@@ -572,11 +572,9 @@ void ManagementAgentImpl::invokeMethodRequest(const string& body, const string&
MapCodec::decode(body, inMap);
- outMap["_values"] = Variant::Map();
-
if ((oid = inMap.find("_object_id")) == inMap.end() ||
(mid = inMap.find("_method_name")) == inMap.end()) {
- sendException(replyTo, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
+ sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
Manageable::STATUS_PARAMETER_INVALID);
failed = true;
} else {
@@ -595,6 +593,8 @@ void ManagementAgentImpl::invokeMethodRequest(const string& body, const string&
inArgs = (mid->second).asMap();
}
+ QPID_LOG(trace, "Invoking Method: name=" << methodName << " args=" << inArgs);
+
boost::shared_ptr<ManagementObject> oPtr;
{
sys::Mutex::ScopedLock lock(agentLock);
@@ -604,7 +604,7 @@ void ManagementAgentImpl::invokeMethodRequest(const string& body, const string&
}
if (oPtr.get() == 0) {
- sendException(replyTo, cid, Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT),
+ sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT),
Manageable::STATUS_UNKNOWN_OBJECT);
failed = true;
} else {
@@ -617,13 +617,13 @@ void ManagementAgentImpl::invokeMethodRequest(const string& body, const string&
if (iter->first != "_status_code" && iter->first != "_status_text")
outMap["_arguments"].asMap()[iter->first] = iter->second;
} else {
- sendException(replyTo, cid, callMap["_status_text"], callMap["_status_code"]);
+ sendException(rte, rtk, cid, callMap["_status_text"], callMap["_status_code"]);
failed = true;
}
}
} catch(types::InvalidConversion& e) {
- sendException(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION);
+ sendException(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION);
failed = true;
}
}
@@ -635,11 +635,11 @@ void ManagementAgentImpl::invokeMethodRequest(const string& body, const string&
headers["qmf.opcode"] = "_method_response";
QPID_LOG(trace, "SENT MethodResponse map=" << outMap);
MapCodec::encode(outMap, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
}
}
-void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid, const string& replyTo)
+void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid, const string& rte, const string& rtk)
{
moveNewObjectsLH();
@@ -666,12 +666,12 @@ void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid,
*/
i = inMap.find("_what");
if (i == inMap.end()) {
- sendException(replyTo, cid, "_what element missing in Query");
+ sendException(rte, rtk, cid, "_what element missing in Query");
return;
}
if (i->second.getType() != qpid::types::VAR_STRING) {
- sendException(replyTo, cid, "_what element is not a string");
+ sendException(rte, rtk, cid, "_what element is not a string");
return;
}
@@ -709,8 +709,8 @@ void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid,
headers.erase("partial");
ListCodec::encode(list_, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
- QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
+ QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << rte << "/" << rtk);
return;
}
} else { // match using schema_id, if supplied
@@ -771,8 +771,8 @@ void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid,
if (++objCount >= maxV2ReplyObjs) {
objCount = 0;
ListCodec::encode(list_, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
- QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
+ QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << rte << "/" << rtk);
content.clear();
list_.clear();
}
@@ -784,8 +784,8 @@ void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid,
// Send last "non-partial" message to indicate CommandComplete
headers.erase("partial");
ListCodec::encode(list_, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
- QPID_LOG(trace, "SENT QueryResponse (empty with no 'partial' indicator) to=" << replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
+ QPID_LOG(trace, "SENT QueryResponse (last message, no 'partial' indicator) to=" << rte << "/" << rtk);
} else if (i->second.asString() == "SCHEMA_ID") {
headers["qmf.content"] = "_schema_id";
@@ -806,16 +806,16 @@ void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid,
headers.erase("partial");
ListCodec::encode(list_, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
- QPID_LOG(trace, "SENT QueryResponse (SchemaId) to=" << replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
+ QPID_LOG(trace, "SENT QueryResponse (SchemaId) to=" << rte << "/" << rtk);
} else {
// Unknown query target
- sendException(replyTo, cid, "Query for _what => '" + i->second.asString() + "' not supported");
+ sendException(rte, rtk, cid, "Query for _what => '" + i->second.asString() + "' not supported");
}
}
-void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid, const string& replyTo)
+void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid, const string& rte, const string& rtk)
{
QPID_LOG(trace, "RCVD AgentLocateRequest");
@@ -829,9 +829,9 @@ void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid,
getHeartbeatContent(map);
MapCodec::encode(map, content);
- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo);
+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
- QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << replyTo);
+ QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << rte << "/" << rtk);
{
sys::Mutex::ScopedLock lock(agentLock);
@@ -839,12 +839,12 @@ void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid,
}
}
-void ManagementAgentImpl::handleMethodRequest(const string& body, const string& cid, const string& replyTo, const string& userId)
+void ManagementAgentImpl::handleMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId)
{
if (extThread) {
sys::Mutex::ScopedLock lock(agentLock);
- methodQueue.push_back(new QueuedMethod(cid, replyTo, body, userId));
+ methodQueue.push_back(new QueuedMethod(cid, rte, rtk, body, userId));
if (pipeHandle != 0) {
pipeHandle->write("X", 1);
} else if (notifyable != 0) {
@@ -863,7 +863,7 @@ void ManagementAgentImpl::handleMethodRequest(const string& body, const string&
inCallback = false;
}
} else {
- invokeMethodRequest(body, cid, replyTo, userId);
+ invokeMethodRequest(body, cid, rte, rtk, userId);
}
QPID_LOG(trace, "RCVD MethodRequest");
@@ -871,10 +871,12 @@ void ManagementAgentImpl::handleMethodRequest(const string& body, const string&
void ManagementAgentImpl::received(Message& msg)
{
+ string replyToExchange;
string replyToKey;
framing::MessageProperties mp = msg.getMessageProperties();
if (mp.hasReplyTo()) {
const framing::ReplyTo& rt = mp.getReplyTo();
+ replyToExchange = rt.getExchange();
replyToKey = rt.getRoutingKey();
}
@@ -887,9 +889,9 @@ void ManagementAgentImpl::received(Message& msg)
string opcode = mp.getApplicationHeaders().getAsString("qmf.opcode");
string cid = msg.getMessageProperties().getCorrelationId();
- if (opcode == "_agent_locate_request") handleLocateRequest(msg.getData(), cid, replyToKey);
- else if (opcode == "_method_request") handleMethodRequest(msg.getData(), cid, replyToKey, userId);
- else if (opcode == "_query_request") handleGetQuery(msg.getData(), cid, replyToKey);
+ if (opcode == "_agent_locate_request") handleLocateRequest(msg.getData(), cid, replyToExchange, replyToKey);
+ else if (opcode == "_method_request") handleMethodRequest(msg.getData(), cid, replyToExchange, replyToKey, userId);
+ else if (opcode == "_query_request") handleGetQuery(msg.getData(), cid, replyToExchange, replyToKey);
else {
QPID_LOG(warning, "Support for QMF V2 Opcode [" << opcode << "] TBD!!!");
}
@@ -906,7 +908,7 @@ void ManagementAgentImpl::received(Message& msg)
if (checkHeader(inBuffer, &opcode, &sequence))
{
- if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToKey);
+ if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
else if (opcode == 'x') handleConsoleAddedIndication();
else
QPID_LOG(warning, "Ignoring old-format QMF Request! opcode=" << char(opcode));
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
index 09d98d237b..bf340777d1 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h
@@ -128,11 +128,12 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
};
struct QueuedMethod {
- QueuedMethod(const std::string& _cid, const std::string& _reply, const std::string& _body, const std::string& _uid) :
- cid(_cid), replyTo(_reply), body(_body), userId(_uid) {}
+ QueuedMethod(const std::string& _cid, const std::string& _rte, const std::string& _rtk, const std::string& _body, const std::string& _uid) :
+ cid(_cid), replyToExchange(_rte), replyToKey(_rtk), body(_body), userId(_uid) {}
std::string cid;
- std::string replyTo;
+ std::string replyToExchange;
+ std::string replyToKey;
std::string body;
std::string userId;
};
@@ -278,16 +279,16 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
uint8_t type=ManagementItem::CLASS_KIND_TABLE);
bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
void sendHeartbeat();
- void sendException(const std::string& replyToKey, const std::string& cid,
+ void sendException(const std::string& replyToExchange, const std::string& replyToKey, const std::string& cid,
const std::string& text, uint32_t code=1);
void handlePackageRequest (qpid::framing::Buffer& inBuffer);
void handleClassQuery (qpid::framing::Buffer& inBuffer);
- void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, const std::string& replyTo);
- void invokeMethodRequest (const std::string& body, const std::string& cid, const std::string& replyTo, const std::string& userId);
+ void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, const std::string& rte, const std::string& rtk);
+ void invokeMethodRequest (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk, const std::string& userId);
- void handleGetQuery (const std::string& body, const std::string& cid, const std::string& replyTo);
- void handleLocateRequest (const std::string& body, const std::string& sequence, const std::string& replyTo);
- void handleMethodRequest (const std::string& body, const std::string& sequence, const std::string& replyTo, const std::string& userId);
+ void handleGetQuery (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk);
+ void handleLocateRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk);
+ void handleMethodRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk, const std::string& userId);
void handleConsoleAddedIndication();
void getHeartbeatContent (qpid::types::Variant::Map& map);
};
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
index 680d0c7adf..460799280e 100644
--- a/qpid/cpp/src/qpid/broker/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -160,7 +160,10 @@ void Connection::received(framing::AMQFrame& frame) {
if (frame.getChannel() == 0 && frame.getMethod()) {
adapter.handle(frame);
} else {
- getChannel(frame.getChannel()).in(frame);
+ if (adapter.isOpen())
+ getChannel(frame.getChannel()).in(frame);
+ else
+ close(connection::CLOSE_CODE_FRAMING_ERROR, "Connection not yet open, invalid frame received.");
}
if (isLink) //i.e. we are acting as the client to another broker
@@ -184,7 +187,8 @@ bool isMessage(const AMQMethodBody* method)
void Connection::recordFromServer(const framing::AMQFrame& frame)
{
- if (mgmtObject != 0)
+ // Don't record management stats in cluster-unsafe contexts
+ if (mgmtObject != 0 && isClusterSafe())
{
mgmtObject->inc_framesToClient();
mgmtObject->inc_bytesToClient(frame.encodedSize());
@@ -196,7 +200,8 @@ void Connection::recordFromServer(const framing::AMQFrame& frame)
void Connection::recordFromClient(const framing::AMQFrame& frame)
{
- if (mgmtObject != 0)
+ // Don't record management stats in cluster-unsafe contexts
+ if (mgmtObject != 0 && isClusterSafe())
{
mgmtObject->inc_framesFromClient();
mgmtObject->inc_bytesFromClient(frame.encodedSize());
diff --git a/qpid/cpp/src/qpid/broker/LinkRegistry.cpp b/qpid/cpp/src/qpid/broker/LinkRegistry.cpp
index 82f1f0ea24..7b1c75db74 100644
--- a/qpid/cpp/src/qpid/broker/LinkRegistry.cpp
+++ b/qpid/cpp/src/qpid/broker/LinkRegistry.cpp
@@ -255,8 +255,17 @@ MessageStore* LinkRegistry::getStore() const {
return store;
}
-Link::shared_ptr LinkRegistry::findLink(const std::string& key)
+Link::shared_ptr LinkRegistry::findLink(const std::string& keyOrMgmtId)
{
+ // Convert keyOrMgmtId to a host:port key.
+ //
+ // TODO aconway 2011-02-01: centralize code that constructs/parses
+ // connection management IDs. Currently sys:: protocol factories
+ // and IO plugins construct the IDs and LinkRegistry parses them.
+ size_t separator = keyOrMgmtId.find('-');
+ if (separator == std::string::npos) separator = 0;
+ std::string key = keyOrMgmtId.substr(separator+1, std::string::npos);
+
Mutex::ScopedLock locker(lock);
LinkMap::iterator l = links.find(key);
if (l != links.end()) return l->second;
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
index 3a98d52d15..e06e5d1aa0 100644
--- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -372,7 +372,8 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
}
//apply settings & create persistent record if required
- queue_created.first->create(arguments);
+ try { queue_created.first->create(arguments); }
+ catch (...) { getBroker().getQueues().destroy(name); throw; }
//add default binding:
getBroker().getExchanges().getDefault()->bind(queue, name, 0);
diff --git a/qpid/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp b/qpid/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
index 2de4a4d914..fd0e537192 100644
--- a/qpid/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
+++ b/qpid/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
@@ -194,7 +194,7 @@ void SslProtocolFactory::established(sys::Poller::shared_ptr poller,
const qpid::sys::Socket& s,
sys::ConnectionCodec::Factory* f,
bool isClient) {
- sys::AsynchIOHandler* async = new sys::AsynchIOHandler(s.getPeerAddress(), f);
+ sys::AsynchIOHandler* async = new sys::AsynchIOHandler(s.getFullAddress(), f);
if (tcpNoDelay) {
s.setTcpNoDelay();
diff --git a/qpid/cpp/src/qpid/client/ConnectionSettings.cpp b/qpid/cpp/src/qpid/client/ConnectionSettings.cpp
index 60b2eac2e8..822e4af269 100644
--- a/qpid/cpp/src/qpid/client/ConnectionSettings.cpp
+++ b/qpid/cpp/src/qpid/client/ConnectionSettings.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,7 +30,7 @@ namespace client {
ConnectionSettings::ConnectionSettings() :
protocol("tcp"),
- host("localhost"),
+ host("localhost"),
port(5672),
locale("en_US"),
heartbeat(0),
@@ -40,7 +40,8 @@ ConnectionSettings::ConnectionSettings() :
tcpNoDelay(false),
service(qpid::saslName),
minSsf(0),
- maxSsf(256)
+ maxSsf(256),
+ sslCertName("")
{}
ConnectionSettings::~ConnectionSettings() {}
diff --git a/qpid/cpp/src/qpid/client/SslConnector.cpp b/qpid/cpp/src/qpid/client/SslConnector.cpp
index e82fc2f8da..35c7e6bdf6 100644
--- a/qpid/cpp/src/qpid/client/SslConnector.cpp
+++ b/qpid/cpp/src/qpid/client/SslConnector.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -130,7 +130,7 @@ class SslConnector : public Connector
public:
SslConnector(Poller::shared_ptr p, framing::ProtocolVersion pVersion,
- const ConnectionSettings&,
+ const ConnectionSettings&,
ConnectionImpl*);
};
@@ -170,7 +170,7 @@ SslConnector::SslConnector(Poller::shared_ptr p,
const ConnectionSettings& settings,
ConnectionImpl* cimpl)
: maxFrameSize(settings.maxFrameSize),
- version(ver),
+ version(ver),
initiated(false),
closed(true),
shutdownHandler(0),
@@ -179,8 +179,11 @@ SslConnector::SslConnector(Poller::shared_ptr p,
poller(p)
{
QPID_LOG(debug, "SslConnector created for " << version.toString());
- //TODO: how do we want to handle socket configuration with ssl?
- //settings.configureSocket(socket);
+
+ if (settings.sslCertName != "") {
+ QPID_LOG(debug, "ssl-cert-name = " << settings.sslCertName);
+ socket.setCertName(settings.sslCertName);
+ }
}
SslConnector::~SslConnector() {
@@ -244,14 +247,14 @@ void SslConnector::setShutdownHandler(ShutdownHandler* handler){
}
OutputHandler* SslConnector::getOutputHandler() {
- return this;
+ return this;
}
sys::ShutdownHandler* SslConnector::getShutdownHandler() const {
return shutdownHandler;
}
-const std::string& SslConnector::getIdentifier() const {
+const std::string& SslConnector::getIdentifier() const {
return identifier;
}
@@ -271,7 +274,7 @@ void SslConnector::Writer::init(std::string id, sys::ssl::SslIO* a) {
aio = a;
newBuffer();
}
-void SslConnector::Writer::handle(framing::AMQFrame& frame) {
+void SslConnector::Writer::handle(framing::AMQFrame& frame) {
Mutex::ScopedLock l(lock);
frames.push_back(frame);
if (frame.getEof() || (bounds && bounds->getCurrentSize() >= maxFrameSize)) {
@@ -372,7 +375,7 @@ const SecuritySettings* SslConnector::getSecuritySettings()
{
securitySettings.ssf = socket.getKeyLen();
securitySettings.authid = "dummy";//set to non-empty string to enable external authentication
- return &securitySettings;
+ return &securitySettings;
}
}} // namespace qpid::client
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
index a60177a5d8..5a545c1f6a 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -42,7 +42,7 @@ using qpid::framing::Uuid;
void convert(const Variant::List& from, std::vector<std::string>& to)
{
for (Variant::List::const_iterator i = from.begin(); i != from.end(); ++i) {
- to.push_back(i->asString());
+ to.push_back(i->asString());
}
}
@@ -108,9 +108,11 @@ void convert(const Variant::Map& from, ConnectionSettings& to)
setIfFound(from, "bounds", to.bounds);
setIfFound(from, "transport", to.protocol);
+
+ setIfFound(from, "ssl-cert-name", to.sslCertName);
}
-ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options) :
+ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options) :
reconnect(false), timeout(-1), limit(-1),
minReconnectInterval(3), maxReconnectInterval(60),
retries(0), reconnectOnLimitExceeded(true)
@@ -135,7 +137,7 @@ void ConnectionImpl::setOptions(const Variant::Map& options)
setIfFound(options, "reconnect-interval-max", maxReconnectInterval);
}
setIfFound(options, "reconnect-urls", urls);
- setIfFound(options, "x-reconnect-on-limit-exceeded", reconnectOnLimitExceeded);
+ setIfFound(options, "x-reconnect-on-limit-exceeded", reconnectOnLimitExceeded);
}
void ConnectionImpl::setOption(const std::string& name, const Variant& value)
@@ -216,7 +218,7 @@ qpid::messaging::Session ConnectionImpl::newSession(bool transactional, const st
} catch (const qpid::SessionException& e) {
throw qpid::messaging::SessionError(e.what());
} catch (const std::exception& e) {
- throw qpid::messaging::MessagingException(e.what());
+ throw qpid::messaging::MessagingException(e.what());
}
}
return impl;
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
index 8562add6b1..09f2038312 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
index e5d20c85e6..4f6488a28a 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
+++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -497,7 +497,7 @@ void UpdateClient::updateConsumer(
ci->isNotifyEnabled(),
ci->position
);
- consumerNumbering.add(ci);
+ consumerNumbering.add(ci.get());
QPID_LOG(debug, *this << " updated consumer " << ci->getName()
<< " on " << shadowSession.getId());
@@ -584,10 +584,9 @@ void UpdateClient::updateQueueListeners(const boost::shared_ptr<broker::Queue>&
}
void UpdateClient::updateQueueListener(std::string& q,
- const boost::shared_ptr<broker::Consumer>& c)
+ const boost::shared_ptr<broker::Consumer>& c)
{
- const boost::shared_ptr<SemanticState::ConsumerImpl> ci =
- boost::dynamic_pointer_cast<SemanticState::ConsumerImpl>(c);
+ SemanticState::ConsumerImpl* ci = dynamic_cast<SemanticState::ConsumerImpl*>(c.get());
size_t n = consumerNumbering[ci];
if (n >= consumerNumbering.size())
throw Exception(QPID_MSG("Unexpected listener on queue " << q));
diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.h b/qpid/cpp/src/qpid/cluster/UpdateClient.h
index 156fa112df..7520bb82cb 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateClient.h
+++ b/qpid/cpp/src/qpid/cluster/UpdateClient.h
@@ -106,7 +106,7 @@ class UpdateClient : public sys::Runnable {
void updateBridge(const boost::shared_ptr<broker::Bridge>&);
- Numbering<broker::SemanticState::ConsumerImpl::shared_ptr> consumerNumbering;
+ Numbering<broker::SemanticState::ConsumerImpl*> consumerNumbering;
MemberId updaterId;
MemberId updateeId;
Url updateeUrl;
diff --git a/qpid/cpp/src/qpid/framing/Buffer.cpp b/qpid/cpp/src/qpid/framing/Buffer.cpp
index 7506cdca7b..5a5bc0325e 100644
--- a/qpid/cpp/src/qpid/framing/Buffer.cpp
+++ b/qpid/cpp/src/qpid/framing/Buffer.cpp
@@ -246,6 +246,7 @@ void Buffer::putShortString(const string& s){
size_t slen = s.length();
if (slen <= std::numeric_limits<uint8_t>::max()) {
uint8_t len = (uint8_t) slen;
+ checkAvailable(slen + 1);
putOctet(len);
s.copy(data + position, len);
position += len;
@@ -258,6 +259,7 @@ void Buffer::putMediumString(const string& s){
size_t slen = s.length();
if (slen <= std::numeric_limits<uint16_t>::max()) {
uint16_t len = (uint16_t) slen;
+ checkAvailable(slen + 2);
putShort(len);
s.copy(data + position, len);
position += len;
@@ -268,6 +270,7 @@ void Buffer::putMediumString(const string& s){
void Buffer::putLongString(const string& s){
uint32_t len = s.length();
+ checkAvailable(len + 4);
putLong(len);
s.copy(data + position, len);
position += len;
@@ -301,6 +304,7 @@ void Buffer::getBin128(uint8_t* b){
void Buffer::putRawData(const string& s){
uint32_t len = s.length();
+ checkAvailable(len);
s.copy(data + position, len);
position += len;
}
@@ -312,6 +316,7 @@ void Buffer::getRawData(string& s, uint32_t len){
}
void Buffer::putRawData(const uint8_t* s, size_t len){
+ checkAvailable(len);
memcpy(data + position, s, len);
position += len;
}
diff --git a/qpid/cpp/src/qpid/framing/ResizableBuffer.h b/qpid/cpp/src/qpid/framing/ResizableBuffer.h
new file mode 100644
index 0000000000..0abc5ba7f4
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/ResizableBuffer.h
@@ -0,0 +1,60 @@
+#ifndef QPID_FRAMING_RESIZABLEBUFFER_H
+#define QPID_FRAMING_RESIZABLEBUFFER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/Buffer.h"
+#include <vector>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * A buffer that maintains its own storage and can be resized,
+ * keeping any data already written to the buffer.
+ */
+class ResizableBuffer : public Buffer
+{
+ public:
+ ResizableBuffer(size_t initialSize) : store(initialSize) {
+ static_cast<Buffer&>(*this) = Buffer(&store[0], store.size());
+ }
+
+ void resize(size_t newSize) {
+ size_t oldPos = getPosition();
+ store.resize(newSize);
+ static_cast<Buffer&>(*this) = Buffer(&store[0], store.size());
+ setPosition(oldPos);
+ }
+
+ /** Make sure at least n bytes are available */
+ void makeAvailable(size_t n) {
+ if (n > available())
+ resize(getSize() + n - available());
+ }
+
+ private:
+ std::vector<char> store;
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_RESIZABLEBUFFER_H*/
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index 7459ac9416..23c999a98a 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -106,7 +106,8 @@ ManagementAgent::ManagementAgent (const bool qmfV1, const bool qmfV2) :
startTime(sys::now()),
suppressed(false), disallowAllV1Methods(false),
vendorNameKey(defaultVendorName), productNameKey(defaultProductName),
- qmf1Support(qmfV1), qmf2Support(qmfV2), maxV2ReplyObjs(100)
+ qmf1Support(qmfV1), qmf2Support(qmfV2), maxReplyObjs(100),
+ msgBuffer(MA_BUFFER_SIZE)
{
nextObjectId = 1;
brokerBank = 1;
@@ -502,7 +503,7 @@ bool ManagementAgent::checkHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
void ManagementAgent::sendBufferLH(Buffer& buf,
uint32_t length,
qpid::broker::Exchange::shared_ptr exchange,
- string routingKey)
+ const string& routingKey)
{
if (suppressed) {
QPID_LOG(debug, "Suppressing management message to " << routingKey);
@@ -547,6 +548,17 @@ void ManagementAgent::sendBufferLH(Buffer& buf,
}
+void ManagementAgent::sendBufferLH(Buffer& buf,
+ uint32_t length,
+ const string& exchange,
+ const string& routingKey)
+{
+ qpid::broker::Exchange::shared_ptr ex(broker->getExchanges().get(exchange));
+ if (ex.get() != 0)
+ sendBufferLH(buf, length, ex, routingKey);
+}
+
+
// NOTE WELL: assumes userLock is held by caller (LH)
// NOTE EVEN WELLER: drops this lock when delivering the message!!!
void ManagementAgent::sendBufferLH(const string& data,
@@ -611,6 +623,20 @@ void ManagementAgent::sendBufferLH(const string& data,
}
+void ManagementAgent::sendBufferLH(const string& data,
+ const string& cid,
+ const Variant::Map& headers,
+ const string& content_type,
+ const string& exchange,
+ const string& routingKey,
+ uint64_t ttl_msec)
+{
+ qpid::broker::Exchange::shared_ptr ex(broker->getExchanges().get(exchange));
+ if (ex.get() != 0)
+ sendBufferLH(data, cid, headers, content_type, ex, routingKey, ttl_msec);
+}
+
+
/** Objects that have been added since the last periodic poll are temporarily
* saved in the newManagementObjects list. This allows objects to be
* added without needing to block on the userLock (addLock is used instead).
@@ -663,7 +689,6 @@ void ManagementAgent::periodicProcessing (void)
#define HEADROOM 4096
debugSnapshot("Management agent periodic processing");
sys::Mutex::ScopedLock lock (userLock);
- char msgChars[BUFSIZE];
uint32_t contentSize;
string routingKey;
string sBuf;
@@ -704,7 +729,7 @@ void ManagementAgent::periodicProcessing (void)
for (PendingDeletedObjsMap::iterator mIter = tmp.begin(); mIter != tmp.end(); mIter++) {
std::string packageName;
std::string className;
- Buffer msgBuffer(msgChars, BUFSIZE);
+ msgBuffer.reset();
uint32_t v1Objs = 0;
uint32_t v2Objs = 0;
Variant::List list_;
@@ -715,6 +740,7 @@ void ManagementAgent::periodicProcessing (void)
for (DeletedObjectList::iterator lIter = mIter->second.begin();
lIter != mIter->second.end(); lIter++) {
+ msgBuffer.makeAvailable(HEADROOM); // Make sure there's buffer space.
std::string oid = (*lIter)->objectId;
if (!(*lIter)->encodedV1Config.empty()) {
encodeHeader(msgBuffer, 'c');
@@ -730,9 +756,9 @@ void ManagementAgent::periodicProcessing (void)
<< " len=" << (*lIter)->encodedV1Inst.size());
v1Objs++;
}
- if (v1Objs && msgBuffer.available() < HEADROOM) {
+ if (v1Objs >= maxReplyObjs) {
v1Objs = 0;
- contentSize = BUFSIZE - msgBuffer.available();
+ contentSize = msgBuffer.getSize();
stringstream key;
key << "console.obj.1.0." << packageName << "." << className;
msgBuffer.reset();
@@ -744,7 +770,7 @@ void ManagementAgent::periodicProcessing (void)
if (!(*lIter)->encodedV2.empty()) {
QPID_LOG(trace, "Deleting V2 " << "map=" << (*lIter)->encodedV2);
list_.push_back((*lIter)->encodedV2);
- if (++v2Objs >= maxV2ReplyObjs) {
+ if (++v2Objs >= maxReplyObjs) {
v2Objs = 0;
string content;
@@ -815,11 +841,11 @@ void ManagementAgent::periodicProcessing (void)
// sendBuffer() call, so always restart the search after a sendBuffer() call
//
while (1) {
- Buffer msgBuffer(msgChars, BUFSIZE);
+ msgBuffer.reset();
Variant::List list_;
uint32_t pcount;
uint32_t scount;
- uint32_t v2Objs;
+ uint32_t v1Objs, v2Objs;
ManagementObjectMap::iterator baseIter;
std::string packageName;
std::string className;
@@ -842,6 +868,7 @@ void ManagementAgent::periodicProcessing (void)
break; // done - all objects processed
pcount = scount = 0;
+ v1Objs = 0;
v2Objs = 0;
list_.clear();
msgBuffer.reset();
@@ -849,6 +876,7 @@ void ManagementAgent::periodicProcessing (void)
for (ManagementObjectMap::iterator iter = baseIter;
iter != managementObjects.end();
iter++) {
+ msgBuffer.makeAvailable(HEADROOM); // Make sure there's buffer space
ManagementObject* baseObject = baseIter->second;
ManagementObject* object = iter->second;
bool send_stats, send_props;
@@ -875,6 +903,7 @@ void ManagementAgent::periodicProcessing (void)
QPID_LOG(trace, "Changed V1 properties "
<< object->getObjectId().getV2Key()
<< " len=" << msgBuffer.getPosition()-pos);
+ ++v1Objs;
}
if (send_stats && qmf1Support) {
@@ -886,7 +915,7 @@ void ManagementAgent::periodicProcessing (void)
QPID_LOG(trace, "Changed V1 statistics "
<< object->getObjectId().getV2Key()
<< " len=" << msgBuffer.getPosition()-pos);
-
+ ++v1Objs;
}
if ((send_stats || send_props) && qmf2Support) {
@@ -916,8 +945,8 @@ void ManagementAgent::periodicProcessing (void)
object->setForcePublish(false);
- if ((qmf1Support && (msgBuffer.available() < HEADROOM)) ||
- (qmf2Support && (v2Objs >= maxV2ReplyObjs)))
+ if ((qmf1Support && (v1Objs >= maxReplyObjs)) ||
+ (qmf2Support && (v2Objs >= maxReplyObjs)))
break; // have enough objects, send an indication...
}
}
@@ -1102,7 +1131,7 @@ void ManagementAgent::sendCommandCompleteLH(const string& replyToKey, uint32_t s
replyToKey << " seq=" << sequence);
}
-void ManagementAgent::sendExceptionLH(const string& replyToKey, const string& cid,
+void ManagementAgent::sendExceptionLH(const string& rte, const string& rtk, const string& cid,
const string& text, uint32_t code, bool viaLocal)
{
static const string addr_exchange("qmf.default.direct");
@@ -1121,7 +1150,7 @@ void ManagementAgent::sendExceptionLH(const string& replyToKey, const string& ci
map["_values"] = values;
MapCodec::encode(map, content);
- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyToKey);
+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
QPID_LOG(debug, "SENT Exception code=" << code <<" text=" << text);
}
@@ -1291,7 +1320,7 @@ void ManagementAgent::handleMethodRequestLH(Buffer& inBuffer, const string& repl
}
-void ManagementAgent::handleMethodRequestLH (const string& body, const string& replyTo,
+void ManagementAgent::handleMethodRequestLH (const string& body, const string& rte, const string& rtk,
const string& cid, const ConnectionToken* connToken, bool viaLocal)
{
moveNewObjectsLH();
@@ -1313,7 +1342,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
if ((oid = inMap.find("_object_id")) == inMap.end() ||
(mid = inMap.find("_method_name")) == inMap.end()) {
- sendExceptionLH(replyTo, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
Manageable::STATUS_PARAMETER_INVALID, viaLocal);
return;
}
@@ -1332,7 +1361,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
inArgs = (mid->second).asMap();
}
} catch(exception& e) {
- sendExceptionLH(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
+ sendExceptionLH(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
return;
}
@@ -1341,7 +1370,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
if (iter == managementObjects.end() || iter->second->isDeleted()) {
stringstream estr;
estr << "No object found with ID=" << objId;
- sendExceptionLH(replyTo, cid, estr.str(), 1, viaLocal);
+ sendExceptionLH(rte, rtk, cid, estr.str(), 1, viaLocal);
return;
}
@@ -1351,7 +1380,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
i = disallowed.find(make_pair(iter->second->getClassName(), methodName));
if (i != disallowed.end()) {
- sendExceptionLH(replyTo, cid, i->second, Manageable::STATUS_FORBIDDEN, viaLocal);
+ sendExceptionLH(rte, rtk, cid, i->second, Manageable::STATUS_FORBIDDEN, viaLocal);
return;
}
@@ -1362,7 +1391,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
params[acl::PROP_SCHEMACLASS] = iter->second->getClassName();
if (!acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, &params)) {
- sendExceptionLH(replyTo, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
Manageable::STATUS_FORBIDDEN, viaLocal);
return;
}
@@ -1372,7 +1401,7 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
QPID_LOG(debug, "RECV MethodRequest (v2) class=" << iter->second->getPackageName()
<< ":" << iter->second->getClassName() << " method=" <<
- methodName << " replyTo=" << replyTo << " objId=" << objId << " inArgs=" << inArgs);
+ methodName << " replyTo=" << rte << "/" << rtk << " objId=" << objId << " inArgs=" << inArgs);
try {
sys::Mutex::ScopedUnlock u(userLock);
@@ -1387,18 +1416,18 @@ void ManagementAgent::handleMethodRequestLH (const string& body, const string& r
} else
error = callMap["_status_text"].asString();
} catch(exception& e) {
- sendExceptionLH(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
+ sendExceptionLH(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
return;
}
if (errorCode != 0) {
- sendExceptionLH(replyTo, cid, error, errorCode, viaLocal);
+ sendExceptionLH(rte, rtk, cid, error, errorCode, viaLocal);
return;
}
MapCodec::encode(outMap, content);
- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyTo);
- QPID_LOG(debug, "SEND MethodResponse (v2) to=" << replyTo << " seq=" << cid << " map=" << outMap);
+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
+ QPID_LOG(debug, "SEND MethodResponse (v2) to=" << rte << "/" << rtk << " seq=" << cid << " map=" << outMap);
}
@@ -1545,7 +1574,7 @@ void ManagementAgent::SchemaClass::appendSchema(Buffer& buf)
buf.putRawData(reinterpret_cast<uint8_t*>(&data[0]), data.size());
}
-void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& replyToKey, uint32_t sequence)
+void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& rte, const string& rtk, uint32_t sequence)
{
string packageName;
SchemaClassKey key;
@@ -1554,7 +1583,7 @@ void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& repl
key.decode(inBuffer);
QPID_LOG(debug, "RECV SchemaRequest class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) <<
- "), replyTo=" << replyToKey << " seq=" << sequence);
+ "), replyTo=" << rte << "/" << rtk << " seq=" << sequence);
PackageMap::iterator pIter = packages.find(packageName);
if (pIter != packages.end()) {
@@ -1570,17 +1599,17 @@ void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& repl
classInfo.appendSchema(outBuffer);
outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- sendBufferLH(outBuffer, outLen, dExchange, replyToKey);
- QPID_LOG(debug, "SEND SchemaResponse to=" << replyToKey << " seq=" << sequence);
+ sendBufferLH(outBuffer, outLen, rte, rtk);
+ QPID_LOG(debug, "SEND SchemaResponse to=" << rte << "/" << rtk << " seq=" << sequence);
}
else
- sendCommandCompleteLH(replyToKey, sequence, 1, "Schema not available");
+ sendCommandCompleteLH(rtk, sequence, 1, "Schema not available");
}
else
- sendCommandCompleteLH(replyToKey, sequence, 1, "Class key not found");
+ sendCommandCompleteLH(rtk, sequence, 1, "Class key not found");
}
else
- sendCommandCompleteLH(replyToKey, sequence, 1, "Package not found");
+ sendCommandCompleteLH(rtk, sequence, 1, "Package not found");
}
void ManagementAgent::handleSchemaResponseLH(Buffer& inBuffer, const string& /*replyToKey*/, uint32_t sequence)
@@ -1840,7 +1869,7 @@ void ManagementAgent::handleGetQueryLH(Buffer& inBuffer, const string& replyToKe
}
-void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo, const string& cid, bool viaLocal)
+void ManagementAgent::handleGetQueryLH(const string& body, const string& rte, const string& rtk, const string& cid, bool viaLocal)
{
moveNewObjectsLH();
@@ -1861,17 +1890,17 @@ void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo
*/
i = inMap.find("_what");
if (i == inMap.end()) {
- sendExceptionLH(replyTo, cid, "_what element missing in Query");
+ sendExceptionLH(rte, rtk, cid, "_what element missing in Query");
return;
}
if (i->second.getType() != qpid::types::VAR_STRING) {
- sendExceptionLH(replyTo, cid, "_what element is not a string");
+ sendExceptionLH(rte, rtk, cid, "_what element is not a string");
return;
}
if (i->second.asString() != "OBJECT") {
- sendExceptionLH(replyTo, cid, "Query for _what => '" + i->second.asString() + "' not supported");
+ sendExceptionLH(rte, rtk, cid, "Query for _what => '" + i->second.asString() + "' not supported");
return;
}
@@ -1930,8 +1959,8 @@ void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo
string content;
ListCodec::encode(list_, content);
- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
- QPID_LOG(debug, "SENT QueryResponse (query by object_id) to=" << replyTo);
+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
+ QPID_LOG(debug, "SENT QueryResponse (query by object_id) to=" << rte << "/" << rtk);
return;
}
} else {
@@ -1967,7 +1996,7 @@ void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo
"_data",
object->getMd5Sum());
_subList.push_back(map_);
- if (++objCount >= maxV2ReplyObjs) {
+ if (++objCount >= maxReplyObjs) {
objCount = 0;
_list.push_back(_subList);
_subList.clear();
@@ -1983,27 +2012,26 @@ void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo
string content;
while (_list.size() > 1) {
ListCodec::encode(_list.front().asList(), content);
- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
_list.pop_front();
- QPID_LOG(debug, "SENT QueryResponse (partial, query by schema_id) to=" << replyTo << " len=" << content.length());
+ QPID_LOG(debug, "SENT QueryResponse (partial, query by schema_id) to=" << rte << "/" << rtk << " len=" << content.length());
}
headers.erase("partial");
ListCodec::encode(_list.size() ? _list.front().asList() : Variant::List(), content);
- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
- QPID_LOG(debug, "SENT QueryResponse (query by schema_id) to=" << replyTo << " len=" << content.length());
+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
+ QPID_LOG(debug, "SENT QueryResponse (query by schema_id) to=" << rte << "/" << rtk << " len=" << content.length());
return;
}
// Unrecognized query - Send empty message to indicate CommandComplete
string content;
ListCodec::encode(Variant::List(), content);
- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
- QPID_LOG(debug, "SENT QueryResponse (empty) to=" << replyTo);
+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
+ QPID_LOG(debug, "SENT QueryResponse (empty) to=" << rte << "/" << rtk);
}
-void ManagementAgent::handleLocateRequestLH(const string&, const string& replyTo,
- const string& cid)
+void ManagementAgent::handleLocateRequestLH(const string&, const string& rte, const string& rtk, const string& cid)
{
QPID_LOG(debug, "RCVD AgentLocateRequest");
@@ -2021,10 +2049,10 @@ void ManagementAgent::handleLocateRequestLH(const string&, const string& replyTo
string content;
MapCodec::encode(map, content);
- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyTo);
+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
clientWasAdded = true;
- QPID_LOG(debug, "SENT AgentLocateResponse replyTo=" << replyTo);
+ QPID_LOG(debug, "SENT AgentLocateResponse replyTo=" << rte << "/" << rtk);
}
@@ -2151,13 +2179,14 @@ bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
msg.getFrames().getHeaders()->get<framing::MessageProperties>();
if (p && p->hasReplyTo()) {
const framing::ReplyTo& rt = p->getReplyTo();
- string replyToKey = rt.getRoutingKey();
+ string rte = rt.getExchange();
+ string rtk = rt.getRoutingKey();
string cid;
if (p && p->hasCorrelationId())
cid = p->getCorrelationId();
if (mapMsg) {
- sendExceptionLH(replyToKey, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
Manageable::STATUS_FORBIDDEN, false);
} else {
@@ -2169,7 +2198,7 @@ bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- sendBufferLH(outBuffer, outLen, dExchange, replyToKey);
+ sendBufferLH(outBuffer, outLen, rte, rtk);
}
QPID_LOG(debug, "SEND MethodResponse status=FORBIDDEN" << " seq=" << sequence);
@@ -2183,12 +2212,14 @@ bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
{
- string replyToKey;
+ string rte;
+ string rtk;
const framing::MessageProperties* p =
msg.getFrames().getHeaders()->get<framing::MessageProperties>();
if (p && p->hasReplyTo()) {
const framing::ReplyTo& rt = p->getReplyTo();
- replyToKey = rt.getRoutingKey();
+ rte = rt.getExchange();
+ rtk = rt.getRoutingKey();
}
else
return;
@@ -2220,11 +2251,11 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
}
if (opcode == "_method_request")
- return handleMethodRequestLH(body, replyToKey, cid, msg.getPublisher(), viaLocal);
+ return handleMethodRequestLH(body, rte, rtk, cid, msg.getPublisher(), viaLocal);
else if (opcode == "_query_request")
- return handleGetQueryLH(body, replyToKey, cid, viaLocal);
+ return handleGetQueryLH(body, rte, rtk, cid, viaLocal);
else if (opcode == "_agent_locate_request")
- return handleLocateRequestLH(body, replyToKey, cid);
+ return handleLocateRequestLH(body, rte, rtk, cid);
QPID_LOG(warning, "Support for QMF Opcode [" << opcode << "] TBD!!!");
return;
@@ -2237,16 +2268,16 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
if (!checkHeader(inBuffer, &opcode, &sequence))
return;
- if (opcode == 'B') handleBrokerRequestLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'P') handlePackageQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'p') handlePackageIndLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'Q') handleClassQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'q') handleClassIndLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'S') handleSchemaRequestLH (inBuffer, replyToKey, sequence);
- else if (opcode == 's') handleSchemaResponseLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'A') handleAttachRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
- else if (opcode == 'G') handleGetQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'M') handleMethodRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
+ if (opcode == 'B') handleBrokerRequestLH (inBuffer, rtk, sequence);
+ else if (opcode == 'P') handlePackageQueryLH (inBuffer, rtk, sequence);
+ else if (opcode == 'p') handlePackageIndLH (inBuffer, rtk, sequence);
+ else if (opcode == 'Q') handleClassQueryLH (inBuffer, rtk, sequence);
+ else if (opcode == 'q') handleClassIndLH (inBuffer, rtk, sequence);
+ else if (opcode == 'S') handleSchemaRequestLH (inBuffer, rte, rtk, sequence);
+ else if (opcode == 's') handleSchemaResponseLH (inBuffer, rtk, sequence);
+ else if (opcode == 'A') handleAttachRequestLH (inBuffer, rtk, sequence, msg.getPublisher());
+ else if (opcode == 'G') handleGetQueryLH (inBuffer, rtk, sequence);
+ else if (opcode == 'M') handleMethodRequestLH (inBuffer, rtk, sequence, msg.getPublisher());
}
}
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.h b/qpid/cpp/src/qpid/management/ManagementAgent.h
index 2202e2fc98..0db19594a7 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.h
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.h
@@ -35,6 +35,7 @@
#include "qpid/types/Variant.h"
#include <qpid/framing/AMQFrame.h>
#include <qpid/framing/FieldValue.h>
+#include <qpid/framing/ResizableBuffer.h>
#include <memory>
#include <string>
#include <map>
@@ -330,7 +331,7 @@ private:
// Maximum # of objects allowed in a single V2 response
// message.
- uint32_t maxV2ReplyObjs;
+ uint32_t maxReplyObjs;
// list of objects that have been deleted, but have yet to be published
// one final time.
@@ -343,6 +344,7 @@ private:
char inputBuffer[MA_BUFFER_SIZE];
char outputBuffer[MA_BUFFER_SIZE];
char eventBuffer[MA_BUFFER_SIZE];
+ framing::ResizableBuffer msgBuffer;
void writeData ();
void periodicProcessing (void);
@@ -352,7 +354,11 @@ private:
void sendBufferLH(framing::Buffer& buf,
uint32_t length,
qpid::broker::Exchange::shared_ptr exchange,
- std::string routingKey);
+ const std::string& routingKey);
+ void sendBufferLH(framing::Buffer& buf,
+ uint32_t length,
+ const std::string& exchange,
+ const std::string& routingKey);
void sendBufferLH(const std::string& data,
const std::string& cid,
const qpid::types::Variant::Map& headers,
@@ -360,6 +366,13 @@ private:
qpid::broker::Exchange::shared_ptr exchange,
const std::string& routingKey,
uint64_t ttl_msec = 0);
+ void sendBufferLH(const std::string& data,
+ const std::string& cid,
+ const qpid::types::Variant::Map& headers,
+ const std::string& content_type,
+ const std::string& exchange,
+ const std::string& routingKey,
+ uint64_t ttl_msec = 0);
void moveNewObjectsLH();
bool moveDeletedObjectsLH();
@@ -384,20 +397,20 @@ private:
void deleteOrphanedAgentsLH();
void sendCommandCompleteLH(const std::string& replyToKey, uint32_t sequence,
uint32_t code = 0, const std::string& text = "OK");
- void sendExceptionLH(const std::string& replyToKey, const std::string& cid, const std::string& text, uint32_t code=1, bool viaLocal=false);
+ void sendExceptionLH(const std::string& rte, const std::string& rtk, const std::string& cid, const std::string& text, uint32_t code=1, bool viaLocal=false);
void handleBrokerRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handlePackageQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handlePackageIndLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handleClassQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handleClassIndLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handleSchemaRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
+ void handleSchemaRequestLH (framing::Buffer& inBuffer, const std::string& replyToEx, const std::string& replyToKey, uint32_t sequence);
void handleSchemaResponseLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handleAttachRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
void handleGetQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
void handleMethodRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
- void handleGetQueryLH (const std::string& body, const std::string& replyToKey, const std::string& cid, bool viaLocal);
- void handleMethodRequestLH (const std::string& body, const std::string& replyToKey, const std::string& cid, const qpid::broker::ConnectionToken* connToken, bool viaLocal);
- void handleLocateRequestLH (const std::string& body, const std::string &replyToKey, const std::string& cid);
+ void handleGetQueryLH (const std::string& body, const std::string& replyToEx, const std::string& replyToKey, const std::string& cid, bool viaLocal);
+ void handleMethodRequestLH (const std::string& body, const std::string& replyToEx, const std::string& replyToKey, const std::string& cid, const qpid::broker::ConnectionToken* connToken, bool viaLocal);
+ void handleLocateRequestLH (const std::string& body, const std::string& replyToEx, const std::string &replyToKey, const std::string& cid);
size_t validateSchema(framing::Buffer&, uint8_t kind);
diff --git a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
index 9eb2eb7b5d..d53db20598 100644
--- a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp
@@ -84,7 +84,7 @@ class RdmaIOHandler : public OutputControl {
};
RdmaIOHandler::RdmaIOHandler(Rdma::Connection::intrusive_ptr c, qpid::sys::ConnectionCodec::Factory* f) :
- identifier(c->getPeerName()),
+ identifier(c->getFullName()),
factory(f),
codec(0),
readError(false),
diff --git a/qpid/cpp/src/qpid/sys/Socket.h b/qpid/cpp/src/qpid/sys/Socket.h
index 7b50c42a3c..7d50afc59f 100644
--- a/qpid/cpp/src/qpid/sys/Socket.h
+++ b/qpid/cpp/src/qpid/sys/Socket.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -60,26 +60,31 @@ public:
QPID_COMMON_EXTERN int listen(uint16_t port = 0, int backlog = 10) const;
QPID_COMMON_EXTERN int listen(const SocketAddress&, int backlog = 10) const;
- /** Returns the "socket name" ie the address bound to
+ /** Returns the "socket name" ie the address bound to
* the near end of the socket
*/
QPID_COMMON_EXTERN std::string getSockname() const;
- /** Returns the "peer name" ie the address bound to
+ /** Returns the "peer name" ie the address bound to
* the remote end of the socket
*/
std::string getPeername() const;
- /**
+ /**
* Returns an address (host and port) for the remote end of the
* socket
*/
QPID_COMMON_EXTERN std::string getPeerAddress() const;
- /**
+ /**
* Returns an address (host and port) for the local end of the
* socket
*/
- std::string getLocalAddress() const;
+ QPID_COMMON_EXTERN std::string getLocalAddress() const;
+
+ /**
+ * Returns the full address of the connection: local and remote host and port.
+ */
+ QPID_COMMON_EXTERN std::string getFullAddress() const { return getLocalAddress()+"-"+getPeerAddress(); }
QPID_COMMON_EXTERN uint16_t getLocalPort() const;
uint16_t getRemotePort() const;
@@ -95,7 +100,7 @@ public:
*/
QPID_COMMON_EXTERN Socket* accept() const;
- // TODO The following are raw operations, maybe they need better wrapping?
+ // TODO The following are raw operations, maybe they need better wrapping?
QPID_COMMON_EXTERN int read(void *buf, size_t count) const;
QPID_COMMON_EXTERN int write(const void *buf, size_t count) const;
diff --git a/qpid/cpp/src/qpid/sys/SslPlugin.cpp b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
index 297787f497..b0e791d60b 100644
--- a/qpid/cpp/src/qpid/sys/SslPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/SslPlugin.cpp
@@ -121,7 +121,7 @@ SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, int back
void SslProtocolFactory::established(Poller::shared_ptr poller, const qpid::sys::ssl::SslSocket& s,
ConnectionCodec::Factory* f, bool isClient) {
- qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getPeerAddress(), f, nodict);
+ qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getFullAddress(), f, nodict);
if (tcpNoDelay) {
s.setTcpNoDelay(tcpNoDelay);
diff --git a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
index d0c7fe4caa..a6528f9ad9 100644
--- a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
+++ b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
@@ -81,7 +81,7 @@ AsynchIOProtocolFactory::AsynchIOProtocolFactory(int16_t port, int backlog, bool
void AsynchIOProtocolFactory::established(Poller::shared_ptr poller, const Socket& s,
ConnectionCodec::Factory* f, bool isClient) {
- AsynchIOHandler* async = new AsynchIOHandler(s.getPeerAddress(), f);
+ AsynchIOHandler* async = new AsynchIOHandler(s.getFullAddress(), f);
if (tcpNoDelay) {
s.setTcpNoDelay();
diff --git a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
index 59d87822d4..28bddd2165 100644
--- a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
+++ b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h
@@ -274,6 +274,7 @@ namespace Rdma {
QueuePair::intrusive_ptr getQueuePair();
std::string getLocalName() const;
std::string getPeerName() const;
+ std::string getFullName() const { return getLocalName()+"-"+getPeerName(); }
};
}
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
index 8ebc5937d2..01e2658877 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
+++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -52,9 +52,9 @@ namespace ssl {
namespace {
std::string getName(int fd, bool local, bool includeService = false)
{
- ::sockaddr_storage name; // big enough for any socket address
+ ::sockaddr_storage name; // big enough for any socket address
::socklen_t namelen = sizeof(name);
-
+
int result = -1;
if (local) {
result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
@@ -67,8 +67,8 @@ std::string getName(int fd, bool local, bool includeService = false)
char servName[NI_MAXSERV];
char dispName[NI_MAXHOST];
if (includeService) {
- if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName),
- servName, sizeof(servName),
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName),
+ servName, sizeof(servName),
NI_NUMERICHOST | NI_NUMERICSERV) != 0)
throw QPID_POSIX_ERROR(rc);
return std::string(dispName) + ":" + std::string(servName);
@@ -82,9 +82,9 @@ std::string getName(int fd, bool local, bool includeService = false)
std::string getService(int fd, bool local)
{
- ::sockaddr_storage name; // big enough for any socket address
+ ::sockaddr_storage name; // big enough for any socket address
::socklen_t namelen = sizeof(name);
-
+
int result = -1;
if (local) {
result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
@@ -95,8 +95,8 @@ std::string getService(int fd, bool local)
QPID_POSIX_CHECK(result);
char servName[NI_MAXSERV];
- if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0,
- servName, sizeof(servName),
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0,
+ servName, sizeof(servName),
NI_NUMERICHOST | NI_NUMERICSERV) != 0)
throw QPID_POSIX_ERROR(rc);
return servName;
@@ -132,8 +132,8 @@ std::string getDomainFromSubject(std::string subject)
}
-SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0)
-{
+SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0)
+{
impl->fd = ::socket (PF_INET, SOCK_STREAM, 0);
if (impl->fd < 0) throw QPID_POSIX_ERROR(errno);
socket = SSL_ImportFD(0, PR_ImportTCPSocket(impl->fd));
@@ -145,12 +145,12 @@ SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0
* PR_Accept, we have to reset the handshake.
*/
SslSocket::SslSocket(IOHandlePrivate* ioph, PRFileDesc* model) : IOHandle(ioph), socket(0), prototype(0)
-{
+{
socket = SSL_ImportFD(model, PR_ImportTCPSocket(impl->fd));
NSS_CHECK(SSL_ResetHandshake(socket, true));
}
-void SslSocket::setNonblocking() const
+void SslSocket::setNonblocking() const
{
PRSocketOptionData option;
option.option = PR_SockOpt_Nonblocking;
@@ -164,7 +164,15 @@ void SslSocket::connect(const std::string& host, uint16_t port) const
namestream << host << ":" << port;
connectname = namestream.str();
- void* arg = SslOptions::global.certName.empty() ? 0 : const_cast<char*>(SslOptions::global.certName.c_str());
+ void* arg;
+ // Use the connection's cert-name if it has one; else use global cert-name
+ if (certname != "") {
+ arg = const_cast<char*>(certname.c_str());
+ } else if (SslOptions::global.certName.empty()) {
+ arg = 0;
+ } else {
+ arg = const_cast<char*>(SslOptions::global.certName.c_str());
+ }
NSS_CHECK(SSL_GetClientAuthDataHook(socket, NSS_GetClientAuthData, arg));
NSS_CHECK(SSL_SetURL(socket, host.data()));
@@ -220,7 +228,7 @@ int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, b
throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
if (::listen(socket, backlog) < 0)
throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
-
+
socklen_t namelen = sizeof(name);
if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
throw QPID_POSIX_ERROR(errno);
@@ -235,7 +243,7 @@ SslSocket* SslSocket::accept() const
return new SslSocket(new IOHandlePrivate(afd), prototype);
} else if (errno == EAGAIN) {
return 0;
- } else {
+ } else {
throw QPID_POSIX_ERROR(errno);
}
}
@@ -303,6 +311,11 @@ void SslSocket::setTcpNoDelay(bool nodelay) const
}
}
+void SslSocket::setCertName(const std::string& name)
+{
+ certname = name;
+}
+
/** get the bit length of the current cipher's key */
int SslSocket::getKeyLen() const
diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
index e2443e31c8..25712c98d5 100644
--- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
+++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -41,13 +41,18 @@ class SslSocket : public qpid::sys::IOHandle
public:
/** Create a socket wrapper for descriptor. */
SslSocket();
-
+
/** Set socket non blocking */
void setNonblocking() const;
/** Set tcp-nodelay */
void setTcpNoDelay(bool nodelay) const;
+ /** Set SSL cert-name. Allows the cert-name to be set per
+ * connection, overriding global cert-name settings from
+ * NSSInit().*/
+ void setCertName(const std::string& certName);
+
void connect(const std::string& host, uint16_t port) const;
void close() const;
@@ -59,38 +64,43 @@ public:
*@return The bound port.
*/
int listen(uint16_t port = 0, int backlog = 10, const std::string& certName = "localhost.localdomain", bool clientAuth = false) const;
-
- /**
+
+ /**
* Accept a connection from a socket that is already listening
* and has an incoming connection
*/
SslSocket* accept() const;
- // TODO The following are raw operations, maybe they need better wrapping?
+ // TODO The following are raw operations, maybe they need better wrapping?
int read(void *buf, size_t count) const;
int write(const void *buf, size_t count) const;
- /** Returns the "socket name" ie the address bound to
+ /** Returns the "socket name" ie the address bound to
* the near end of the socket
*/
std::string getSockname() const;
- /** Returns the "peer name" ie the address bound to
+ /** Returns the "peer name" ie the address bound to
* the remote end of the socket
*/
std::string getPeername() const;
- /**
+ /**
* Returns an address (host and port) for the remote end of the
* socket
*/
std::string getPeerAddress() const;
- /**
+ /**
* Returns an address (host and port) for the local end of the
* socket
*/
std::string getLocalAddress() const;
+ /**
+ * Returns the full address of the connection: local and remote host and port.
+ */
+ std::string getFullAddress() const { return getLocalAddress()+"-"+getPeerAddress(); }
+
uint16_t getLocalPort() const;
uint16_t getRemotePort() const;
@@ -106,6 +116,8 @@ public:
private:
mutable std::string connectname;
mutable PRFileDesc* socket;
+ std::string certname;
+
/**
* 'model' socket, with configuration to use when importing
* accepted sockets for use as ssl sockets. Set on listen(), used
diff --git a/qpid/python/qpid/brokertest.py b/qpid/cpp/src/tests/brokertest.py
index 98f58ebfdd..98f58ebfdd 100644
--- a/qpid/python/qpid/brokertest.py
+++ b/qpid/cpp/src/tests/brokertest.py
diff --git a/qpid/cpp/src/tests/cli_tests.py b/qpid/cpp/src/tests/cli_tests.py
index 4a7314a85c..deef03279d 100755
--- a/qpid/cpp/src/tests/cli_tests.py
+++ b/qpid/cpp/src/tests/cli_tests.py
@@ -22,7 +22,7 @@ import sys
import os
import imp
from qpid.testlib import TestBase010
-# from qpid.brokertest import import_script, checkenv
+# from brokertest import import_script, checkenv
from qpid.datatypes import Message
from qpid.queue import Empty
from time import sleep
diff --git a/qpid/cpp/src/tests/cluster.mk b/qpid/cpp/src/tests/cluster.mk
index f6cfd7a6ca..c9e6d79ee7 100644
--- a/qpid/cpp/src/tests/cluster.mk
+++ b/qpid/cpp/src/tests/cluster.mk
@@ -44,6 +44,7 @@ EXTRA_DIST += \
run_cluster_tests \
run_long_cluster_tests \
testlib.py \
+ brokertest.py \
cluster_tests.py \
cluster_test_logs.py \
long_cluster_tests.py \
@@ -93,7 +94,7 @@ cluster_test_SOURCES = \
cluster_test_LDADD=$(lib_client) $(lib_broker) ../cluster.la -lboost_unit_test_framework
-qpidtest_SCRIPTS += run_cluster_tests cluster_tests.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
+qpidtest_SCRIPTS += run_cluster_tests brokertest.py cluster_tests.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
qpidtest_SCRIPTS += $(CLUSTER_TEST_SCRIPTS_LIST)
endif
diff --git a/qpid/cpp/src/tests/cluster_test_logs.py b/qpid/cpp/src/tests/cluster_test_logs.py
index 0333822824..1fa9014d11 100755
--- a/qpid/cpp/src/tests/cluster_test_logs.py
+++ b/qpid/cpp/src/tests/cluster_test_logs.py
@@ -46,51 +46,48 @@ def filter_log(log):
to differ between brokers in a cluster. Filtered log contents between
the same checkpoints should match across the cluster."""
out = open("%s.filter"%(log), 'w')
- for l in open(log):
- # Lines to skip entirely
- skip = "|".join([
- 'local connection', # Only on local broker
- 'UPDATER|UPDATEE', # Ignore update process
- 'stall for update|unstall, ignore update|cancelled offer .* unstall',
- 'caught up',
- 'active for links|Passivating links|Activating links',
- 'info Connection.* connected to', # UpdateClient connection
- 'warning Broker closed connection: 200, OK',
- 'task late',
- 'task overran',
- 'warning CLOSING .* unsent data',
- 'Inter-broker link '
- ])
- if re.compile(skip).search(l): continue
-
- # Regex to match a UUID
- uuid='\w\w\w\w\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w\w\w\w\w\w\w\w\w'
+ # Lines to skip entirely, expected differences
+ skip = "|".join([
+ 'local connection', # Only on local broker
+ 'UPDATER|UPDATEE', # Ignore update process
+ 'stall for update|unstall, ignore update|cancelled offer .* unstall',
+ 'caught up',
+ 'active for links|Passivating links|Activating links',
+ 'info Connection.* connected to', # UpdateClient connection
+ 'warning Connection [\d+ [0-9.:]+] closed', # UpdateClient connection
+ 'warning Broker closed connection: 200, OK',
+ 'task late',
+ 'task overran',
+ 'warning CLOSING .* unsent data',
+ 'Inter-broker link ',
+ 'Running in a cluster, marking store'
+ ])
+ skip_re = re.compile(skip)
+ # Regex to match a UUID
+ uuid='\w\w\w\w\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w\w\w\w\w\w\w\w\w'
+ # Substitutions to remove expected differences
+ subs = [
+ (r'\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d ', ''), # Remove timestamp
+ (r'cluster\([0-9.: ]*', 'cluster('), # Remove cluster node id
+ (r' local\)| shadow\)', ')'), # Remove local/shadow indication
+ (r'CATCHUP', 'READY'), # Treat catchup as equivalent to ready.
+ (r'OFFER', 'READY'), # Treat offer as equivalent to ready.
+ # System UUID expected to be different
+ (r'(org.apache.qpid.broker:system[:(])%s(\)?)'%(uuid), r'\1UUID\2'),
- # Regular expression substitutions to remove expected differences
- for pattern,subst in [
- (r'\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d ', ''), # Remove timestamp
- (r'cluster\([0-9.: ]*', 'cluster('), # Remove cluster node id
- (r' local\)| shadow\)', ')'), # Remove local/shadow indication
- (r'CATCHUP', 'READY'), # Treat catchup as equivalent to ready.
- (r'OFFER', 'READY'), # Treat offer as equivalent to ready.
- # System UUID expected to be different
- (r'(org.apache.qpid.broker:system[:(])%s(\)?)'%(uuid), r'\1UUID\2'),
-
- # FIXME aconway 2010-12-20: substitutions to mask known problems
- # See https://issues.apache.org/jira/browse/QPID-2982
- (r' len=\d+', ' len=NN'), # buffer lengths
- (r' map={.*_object_name:([^,}]*)[,}].*', r' \1'), # V2 map - just keep name
- (r'\d+-\d+-\d+--\d+', 'X-X-X--X'), # V1 Object IDs
- ]: l = re.sub(pattern,subst,l)
+ # TODO aconway 2010-12-20: review if these should be expected:
+ (r' len=\d+', ' len=NN'), # buffer lengths
+ (r' map={.*_object_name:([^,}]*)[,}].*', r' \1'), # V2 map - just keep name
+ (r'\d+-\d+-\d+--\d+', 'X-X-X--X'), # V1 Object IDs
+ ]
+ for l in open(log):
+ if skip_re.search(l): continue
+ for pattern,subst in subs: l = re.sub(pattern,subst,l)
out.write(l)
out.close()
-def verify_logs(logs):
+def verify_logs():
"""Compare log files from cluster brokers, verify that they correspond correctly."""
- # FIXME aconway 2011-01-19: disable when called from unit tests
- # Causing sporadic failures, see https://issues.apache.org/jira/browse/QPID-3007
- if __name__ != "__main__": return
-
for l in glob.glob("*.log"): filter_log(l)
checkpoints = set()
for l in glob.glob("*.filter"): checkpoints = checkpoints.union(set(split_log(l)))
@@ -110,4 +107,4 @@ def verify_logs(logs):
# Can be run as a script.
if __name__ == "__main__":
- verify_logs(glob.glob("*.log"))
+ verify_logs()
diff --git a/qpid/cpp/src/tests/cluster_tests.py b/qpid/cpp/src/tests/cluster_tests.py
index 6e515cdbf1..cbad4010b4 100755
--- a/qpid/cpp/src/tests/cluster_tests.py
+++ b/qpid/cpp/src/tests/cluster_tests.py
@@ -7,9 +7,9 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,7 +20,7 @@
import os, signal, sys, time, imp, re, subprocess, glob, cluster_test_logs
from qpid import datatypes, messaging
-from qpid.brokertest import *
+from brokertest import *
from qpid.harness import Skipped
from qpid.messaging import Message, Empty
from threading import Thread, Lock
@@ -290,7 +290,7 @@ acl allow all all
if pattern.search(l): self.found = True; return
scanner = Scanner()
scanner.start()
- start = time.time()
+ start = time.time()
try:
# Wait up to 5 second timeout for scanner to find expected output
while not scanner.found and time.time() < start + 5:
@@ -302,7 +302,7 @@ acl allow all all
scanner.join()
assert scanner.found
# Verify logs are consistent
- cluster_test_logs.verify_logs(glob.glob("*.log"))
+ cluster_test_logs.verify_logs()
class LongTests(BrokerTest):
"""Tests that can run for a long time if -DDURATION=<minutes> is set"""
@@ -402,7 +402,7 @@ class LongTests(BrokerTest):
# Use store if present.
if BrokerTest.store_lib: args +=["--load-module", BrokerTest.store_lib]
cluster = self.cluster(3, args)
-
+
clients = [] # Per-broker list of clients that only connect to one broker.
mclients = [] # Management clients that connect to every broker in the cluster.
@@ -422,18 +422,20 @@ class LongTests(BrokerTest):
mclients.append(ClientLoop(broker, cmd))
endtime = time.time() + self.duration()
+ runtime = self.duration() / 4 # First run is longer, use quarter of duration.
alive = 0 # First live cluster member
for i in range(len(cluster)): start_clients(cluster[i])
start_mclients(cluster[alive])
while time.time() < endtime:
- time.sleep(5)
+ time.sleep(runtime)
+ runtime = 5 # Remaining runs 5 seconds, frequent broker kills
for b in cluster[alive:]: b.ready() # Check if a broker crashed.
- # Kill the first broker, expect the clients to fail.
+ # Kill the first broker, expect the clients to fail.
b = cluster[alive]
b.expect = EXPECT_EXIT_FAIL
b.kill()
- # Stop the brokers clients and all the mclients.
+ # Stop the brokers clients and all the mclients.
for c in clients[alive] + mclients:
try: c.stop()
except: pass # Ignore expected errors due to broker shutdown.
@@ -448,17 +450,26 @@ class LongTests(BrokerTest):
c.stop()
# Verify that logs are consistent
- cluster_test_logs.verify_logs(glob.glob("*.log"))
+ cluster_test_logs.verify_logs()
def test_management_qmf2(self):
self.test_management(args=["--mgmt-qmf2=yes"])
+ def test_connect_consistent(self): # FIXME aconway 2011-01-18:
+ args=["--mgmt-pub-interval=1","--log-enable=trace+:management"]
+ cluster = self.cluster(2, args=args)
+ end = time.time() + self.duration()
+ while (time.time() < end): # Get a management interval
+ for i in xrange(1000): cluster[0].connect().close()
+ cluster_test_logs.verify_logs()
+
+
class StoreTests(BrokerTest):
"""
Cluster tests that can only be run if there is a store available.
"""
def args(self):
- assert BrokerTest.store_lib
+ assert BrokerTest.store_lib
return ["--load-module", BrokerTest.store_lib]
def test_store_loaded(self):
@@ -523,7 +534,7 @@ class StoreTests(BrokerTest):
b = cluster.start("b", wait=False)
c = cluster.start("c", wait=True)
self.assertEqual(a.get_message("q").content, "clean")
-
+
def test_wrong_cluster_id(self):
# Start a cluster1 broker, then try to restart in cluster2
cluster1 = self.cluster(0, args=self.args())
@@ -582,16 +593,16 @@ class StoreTests(BrokerTest):
c = cluster.start("c", expect=EXPECT_EXIT_FAIL)
self.assertEqual(b.store_state(), "dirty")
self.assertEqual(c.store_state(), "dirty")
- retry(lambda: a.store_state() == "dirty")
+ retry(lambda: a.store_state() == "dirty")
a.send_message("q", Message("x", durable=True))
a.kill()
b.kill() # c is last man, will mark store clean
- retry(lambda: c.store_state() == "clean")
+ retry(lambda: c.store_state() == "clean")
a = cluster.start("a", expect=EXPECT_EXIT_FAIL) # c no longer last man
- retry(lambda: c.store_state() == "dirty")
+ retry(lambda: c.store_state() == "dirty")
c.kill() # a is now last man
- retry(lambda: a.store_state() == "clean")
+ retry(lambda: a.store_state() == "clean")
a.kill()
self.assertEqual(a.store_state(), "clean")
self.assertEqual(b.store_state(), "dirty")
diff --git a/qpid/cpp/src/tests/ssl_test b/qpid/cpp/src/tests/ssl_test
index 2e4add558e..04584f169d 100755
--- a/qpid/cpp/src/tests/ssl_test
+++ b/qpid/cpp/src/tests/ssl_test
@@ -8,9 +8,9 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -26,6 +26,7 @@ CONFIG=$(dirname $0)/config.null
CERT_DIR=`pwd`/test_cert_db
CERT_PW_FILE=`pwd`/cert.password
TEST_HOSTNAME=127.0.0.1
+TEST_CLIENT_CERT=rumplestiltskin
COUNT=10
trap cleanup EXIT
@@ -36,7 +37,8 @@ create_certs() {
#create certificate and key databases with single, simple, self-signed certificate in it
mkdir ${CERT_DIR}
certutil -N -d ${CERT_DIR} -f ${CERT_PW_FILE}
- certutil -S -d ${CERT_DIR} -n ${TEST_HOSTNAME} -s "CN=${TEST_HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+ certutil -S -d ${CERT_DIR} -n ${TEST_HOSTNAME} -s "CN=${TEST_HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+ certutil -S -d ${CERT_DIR} -n ${TEST_CLIENT_CERT} -s "CN=${TEST_CLIENT_CERT}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
}
delete_certs() {
@@ -46,11 +48,19 @@ delete_certs() {
}
COMMON_OPTS="--daemon --no-data-dir --no-module-dir --auth no --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME --require-encryption"
-start_broker() { ../qpidd --transport ssl --port 0 --ssl-port 0 $COMMON_OPTS; }
+start_broker() { # $1 = extra opts
+ ../qpidd --transport ssl --port 0 --ssl-port 0 $COMMON_OPTS $1;
+}
-cleanup() {
+stop_brokers() {
test -n "$PORT" && ../qpidd --no-module-dir -qp $PORT
test -n "$PORT2" && ../qpidd --no-module-dir -qp $PORT2
+ PORT=""
+ PORT2=""
+}
+
+cleanup() {
+ stop_brokers
delete_certs
}
@@ -76,11 +86,29 @@ export QPID_SSL_CERT_PASSWORD_FILE=${CERT_PW_FILE}
./qpid-perftest --count ${COUNT} --port ${PORT} -P ssl -b $TEST_HOSTNAME --summary
## Test connection with a URL
-URL=amqp:ssl:$TEST_HOSTNAME:$PORT
+URL=amqp:ssl:$TEST_HOSTNAME:$PORT
./qpid-send -b $URL --content-string=hello -a "foo;{create:always}"
MSG=`./qpid-receive -b $URL -a "foo;{create:always}" --messages 1`
test "$MSG" = "hello" || { echo "receive failed '$MSG' != 'hello'"; exit 1; }
+#### Client Authentication tests
+
+PORT2=`start_broker --ssl-require-client-authentication` || error "Could not start broker"
+echo "Running SSL client authentication test on port $PORT2"
+URL=amqp:ssl:$TEST_HOSTNAME:$PORT2
+
+## See if you can set the SSL cert-name for the connection
+./qpid-send -b $URL --connection-options "{ssl-cert-name: $TEST_CLIENT_CERT }" --content-string=hello -a "bar;{create:always}"
+MSG2=`./qpid-receive -b $URL --connection-options "{ssl-cert-name: $TEST_CLIENT_CERT }" -a "bar;{create:always}" --messages 1`
+test "$MSG2" = "hello" || { echo "receive failed '$MSG2' != 'hello'"; exit 1; }
+
+## Make sure that connect fails with an invalid SSL cert-name
+./qpid-send -b $URL --connection-options "{ssl-cert-name: pignose }" --content-string=hello -a "baz;{create:always}" 2>/dev/null 1>/dev/null
+MSG3=`./qpid-receive -b $URL --connection-options "{ssl-cert-name: pignose }" -a "baz;{create:always}" --messages 1 2>/dev/null`
+test "$MSG3" = "" || { echo "receive succeeded without valid ssl cert '$MSG3' != ''"; exit 1; }
+
+stop_brokers
+
test -z $CLUSTER_LIB && exit 0 # Exit if cluster not supported.
## Test failover in a cluster using SSL only
diff --git a/qpid/cpp/src/tests/store.py b/qpid/cpp/src/tests/store.py
index eb4cd4785e..77e8a78e5d 100644..100755
--- a/qpid/cpp/src/tests/store.py
+++ b/qpid/cpp/src/tests/store.py
@@ -19,7 +19,7 @@
#
import errno, os, time
-from qpid.brokertest import *
+from brokertest import *
from qpid import compat, session
from qpid.util import connect
from qpid.connection import Connection
diff --git a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
index 11882a0564..309492262d 100644
--- a/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
+++ b/qpid/doc/book/src/AMQP-Messaging-Broker-CPP-Book.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-
+
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
@@ -8,16 +8,16 @@
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-
+
-->
<book>
@@ -42,34 +42,33 @@
</preface>
<chapter>
- <title>
+ <title>
Running the AMQP Messaging Broker
</title>
-
+
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Running-CPP-Broker.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Cheat-Sheet-for-configuring-Queue-Options.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Cheat-Sheet-for-configuring-Exchange-Options.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Using-Broker-Federation.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="SSL.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Security.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="LVQ.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="queue-state-replication.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Starting-a-cluster.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ACL.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="AMQP-Compatibility.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="AMQP-Compatibility.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Qpid-Interoperability-Documentation.xml"/>
-
+
</chapter>
-
+
<chapter id="chapter-Managing-CPP-Broker">
- <title>
+ <title>
Managing the AMQP Messaging Broker
</title>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Managing-CPP-Broker.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Qpid-Management-Framework.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="QMF-Python-Console-Tutorial.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Managing-CPP-Broker.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Qpid-Management-Framework.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="QMF-Python-Console-Tutorial.xml"/>
</chapter>
</book>
diff --git a/qpid/doc/book/src/Programming-In-Apache-Qpid.xml b/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
index f4c82ac748..3950b375da 100644
--- a/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
+++ b/qpid/doc/book/src/Programming-In-Apache-Qpid.xml
@@ -1,9 +1,8 @@
<?xml version='1.0' encoding='utf-8' ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-]>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!--
-
+
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
@@ -11,16 +10,16 @@
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-
+
-->
<book id="client-api-tutorial">
@@ -29,7 +28,7 @@
<chapter>
<title>Introduction</title>
-
+
<para>Apache Qpid is a reliable, asynchronous messaging system that
supports the AMQP messaging protocol in several common programming
languages. Qpid is supported on most common platforms.
@@ -40,7 +39,7 @@
<para>
On the Java platform, Qpid uses the
established <ulink url="http://java.sun.com/products/jms/">Java JMS
- API</ulink>.
+ API</ulink>.
</para>
</listitem>
<listitem>
@@ -50,7 +49,7 @@
conceptually similar in each.
</para>
<para>
- On the .NET platform, Qpid also provides a WCF binding.
+ On the .NET platform, Qpid also provides a WCF binding.
</para>
</listitem>
<listitem>
@@ -82,14 +81,14 @@
message).
</para>
</listitem>
-
+
<listitem>
<para>
A <firstterm>connection</firstterm> represents a network
connection to a remote endpoint.
</para>
</listitem>
-
+
<listitem>
<para>
A <firstterm>session</firstterm> provides a sequentially
@@ -98,7 +97,7 @@
connection.
</para>
</listitem>
-
+
<listitem>
<para>
A <firstterm>sender</firstterm> sends messages to a target
@@ -106,7 +105,7 @@
obtained from a session for a given target address.
</para>
</listitem>
-
+
<listitem>
<para>
A <firstterm>receiver</firstterm> receives messages from a
@@ -115,7 +114,7 @@
address.
</para>
</listitem>
-
+
</itemizedlist>
<para>
@@ -147,7 +146,7 @@ int main(int argc, char** argv) {
std::string broker = argc > 1 ? argv[1] : "localhost:5672";
std::string address = argc > 2 ? argv[2] : "amq.topic";
std::string connectionOptions = argc > 3 ? argv[3] : "";
-
+
Connection connection(broker, connectionOptions);
try {
connection.open(); <co id="hello-cpp-open" linkends="callout-cpp-open"/>
@@ -161,13 +160,13 @@ int main(int argc, char** argv) {
Message message = receiver.fetch(Duration::SECOND * 1); <co id="hello-cpp-fetch" linkends="callout-cpp-fetch"/>
<![CDATA[std::cout << message.getContent() << std::endl;]]>
session.acknowledge(); <co id="hello-cpp-acknowledge" linkends="callout-cpp-acknowledge"/>
-
+
connection.close(); <co id="hello-cpp-close" linkends="callout-cpp-close"/>
return 0;
} catch(const std::exception&amp; error) {
<![CDATA[std::cerr << error.what() << std::endl;]]>
connection.close();
- return 1;
+ return 1;
}
}</programlisting>
@@ -274,7 +273,7 @@ finally:
<section>
<title>A Simple Messaging Program in .NET C#</title>
- <para>The following .NET C#
+ <para>The following .NET C#
<footnote>
<para>
The .NET binding for the Qpid C++ Messaging API
@@ -367,15 +366,15 @@ namespace Org.Apache.Qpid.Messaging {
<section id="section-addresses">
<title>Addresses</title>
-
+
<para>An <firstterm>address</firstterm> is the name of a message
- target or message source.
+ target or message source.
<footnote><para>In the programs we have just seen, we used
<literal>amq.topic</literal> as the default address if none is
passed in. This is the name of a standard exchange that always
exists on an AMQP 0-10 messaging broker.</para></footnote>
-
+
The methods that create senders and receivers require an
address. The details of sending to a particular target or
receiving from a particular source are then handled by the
@@ -408,7 +407,7 @@ namespace Org.Apache.Qpid.Messaging {
A topic immediately delivers a message to all eligible
receivers; if there are no eligible receivers, it discards the
message. In the AMQP 0-10 implementation of the API,
-
+
<footnote><para>The AMQP 0-10 implementation is the only one
that currently exists.</para></footnote>
@@ -435,7 +434,7 @@ namespace Org.Apache.Qpid.Messaging {
language. These programs can use any address string as a source
or a destination, and have many command line options to
configure behavior&mdash;use the <command>-h</command> option
- for documentation on these options.
+ for documentation on these options.
<footnote><para>Currently, the C++, Python, and .NET C#
implementations of <command>drain</command> and
@@ -518,7 +517,7 @@ $
<screen>
$ ./drain -t 30 hello-word
</screen>
-
+
<para><emphasis>Second Window:</emphasis></para>
@@ -548,14 +547,14 @@ Message(properties={spout-id:7da2d27d-93e6-4803-8a61-536d87b8d93f:0}, content=''
string</firstterm> can also contain a
<firstterm>subject</firstterm> and
<firstterm>options</firstterm>.</para>
-
+
<para>The syntax for an address string is:</para>
-
+
<programlisting><![CDATA[
address_string ::= <address> [ / <subject> ] [ ; <options> ]
options ::= { <key> : <value>, ... }
]]></programlisting>
-
+
<para>Addresses, subjects, and keys are strings. Values can
be numbers, strings (with optional single or double quotes),
maps, or lists. A complete BNF for address strings appears in
@@ -578,7 +577,7 @@ options ::= { <key> : <value>, ... }
message's subject is null. For convenience, address strings
also allow a subject. If a sender's address contains a
subject, it is used as the default subject for the messages
- it sends.
+ it sends.
If a receiver's address contains a subject, it is used to
select only messages that match the subject&mdash;the matching
@@ -639,7 +638,7 @@ Message(properties={qpid.subject:sports, spout-id:9441674e-a157-4780-a78e-f7ccea
<command>drain</command> receive the messages for that
subject.</para>
</example>
-
+
<para>The AMQP exchange type we are using here,
<literal>amq.topic</literal>, can also do more sophisticated
@@ -650,11 +649,11 @@ Message(properties={qpid.subject:sports, spout-id:9441674e-a157-4780-a78e-f7ccea
application, the sender might use subjects like
<literal>usa.news</literal>, <literal>usa.weather</literal>,
<literal>europe.news</literal>, or
- <literal>europe.weather</literal>.
+ <literal>europe.weather</literal>.
The receiver's subject can include wildcard characters&mdash;
<quote>#</quote> matches one or more words in the message's
- subject, <quote>*</quote> matches a single word.
+ subject, <quote>*</quote> matches a single word.
For instance, if the subject in the source address is
<literal>*.news</literal>, it matches messages with the
@@ -676,7 +675,7 @@ Message(properties={qpid.subject:sports, spout-id:9441674e-a157-4780-a78e-f7ccea
<literal>news</literal>.</para>
<para><emphasis>First Window:</emphasis></para>
-
+
<screen>
$ ./drain -t 30 news-service/*.news
</screen>
@@ -767,7 +766,7 @@ Message(properties={qpid.subject:usa.faux.news, spout-id:6029430a-cfcb-4700-8e9b
Policies for automatically creating or deleting the node to which an address refers.
</para>
<para>
- For instance, in the address string <literal>xoxox ; {create: always}</literal>,
+ For instance, in the address string <literal>xoxox ; {create: always}</literal>,
the queue <literal>xoxox</literal> is created, if it does
not exist, before the address is resolved.
</para>
@@ -801,7 +800,7 @@ Message(properties={qpid.subject:usa.faux.news, spout-id:6029430a-cfcb-4700-8e9b
address string options affect the behavior of senders and
receives.
</para>
-
+
<section>
<title>assert</title>
<para>
@@ -821,7 +820,7 @@ Message(properties={qpid.subject:usa.faux.news, spout-id:6029430a-cfcb-4700-8e9b
$ qpid-config add queue my-queue
$ qpid-config add exchange topic my-topic
</screen>
-
+
<para>
We can now use the address specified to drain to assert that it is
of a particular type:
@@ -839,7 +838,7 @@ Exchange my-queue does not exist
queue. The second attempt however failed; my-queue is not a
topic.
</para>
-
+
<para>
We can do the same thing for my-topic:
</para>
@@ -877,7 +876,7 @@ Queue my-topic does not exist
<para><emphasis>Second Window:</emphasis></para>
<screen>$ ./spout "xoxox ; {create: always}"</screen>
-
+
<para>Returning to the first window, we see that <command>drain</command> has received this message:</para>
<screen>Message(properties={spout-id:1a1a3842-1a8b-4f88-8940-b4096e615a7d:0}, content='')</screen>
@@ -906,7 +905,7 @@ $ ./spout my-queue --content one
$ ./spout my-queue --content two
$ ./spout my-queue --content three
</screen>
-
+
<para>Now we use drain to get those messages, using the browse option:</para>
<screen>
$ ./drain 'my-queue; {mode: browse}'
@@ -914,7 +913,7 @@ Message(properties={spout-id:fbb93f30-0e82-4b6d-8c1d-be60eb132530:0}, content='o
Message(properties={spout-id:ab9e7c31-19b0-4455-8976-34abe83edc5f:0}, content='two')
Message(properties={spout-id:ea75d64d-ea37-47f9-96a9-d38e01c97925:0}, content='three')
</screen>
-
+
<para>We can confirm the messages are still on the queue by repeating the drain:</para>
<screen>
$ ./drain 'my-queue; {mode: browse}'
@@ -960,9 +959,9 @@ $ qpid-config add exchange xml xml
<programlisting><![CDATA[
xml; {
- link: {
- x-bindings: [{exchange:xml, key:weather, arguments:{xquery:"./weather"} }]
- }
+ link: {
+ x-bindings: [{exchange:xml, key:weather, arguments:{xquery:"./weather"} }]
+ }
}
]]></programlisting>
@@ -978,8 +977,8 @@ xml; {
<programlisting>
<![CDATA[
-let $w := ./weather
-return $w/station = 'Raleigh-Durham International Airport (KRDU)'
+let $w := ./weather
+return $w/station = 'Raleigh-Durham International Airport (KRDU)'
and $w/temperature_f > 50
and $w/temperature_f - $w/dewpoint > 5
and $w/wind_speed_mph > 7
@@ -989,9 +988,9 @@ return $w/station = 'Raleigh-Durham International Airport (KRDU)'
<para>We can specify this query in an x-binding to listen to messages that meet the criteria specified by the query:</para>
<para><emphasis>First Window:</emphasis></para>
-
+
<screen>
-$ ./drain -f "xml; {link:{x-bindings:[{key:'weather',
+$ ./drain -f "xml; {link:{x-bindings:[{key:'weather',
arguments:{xquery:\"$(cat rdu.xquery )\"}}]}}"
</screen>
@@ -1015,9 +1014,9 @@ spout --content "$(cat rdu.xml)" xml/weather
</screen>
<para>Returning to the first window, we see that the message has been received:</para>
-
+
<screen><![CDATA[$ ./drain -f "xml; {link:{x-bindings:[{exchange:'xml', key:'weather', arguments:{xquery:\"$(cat rdu.xquery )\"}}]}}"
-Message(properties={qpid.subject:weather, spout-id:31c431de-593f-4bec-a3dd-29717bd945d3:0},
+Message(properties={qpid.subject:weather, spout-id:31c431de-593f-4bec-a3dd-29717bd945d3:0},
content='<weather>
<station>Raleigh-Durham International Airport (KRDU)</station>
<wind_speed_mph>16</wind_speed_mph>
@@ -1172,7 +1171,7 @@ spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
<row>
<entry>
durable
- </entry>
+ </entry>
<entry>
True, False
</entry>
@@ -1212,9 +1211,9 @@ spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
exchange: <exchange>,
queue: <queue>,
key: <key>,
- arguments: {
- <key_1>: <value_1>,
- ...,
+ arguments: {
+ <key_1>: <value_1>,
+ ...,
<key_n>: <value_n> }
},
...
@@ -1277,7 +1276,7 @@ spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
<row>
<entry>
durable
- </entry>
+ </entry>
<entry>
True, False
</entry>
@@ -1514,7 +1513,7 @@ options := map
</section>
-
+
<section>
<title>Receiving Messages from Multiple Sources</title>
@@ -1602,20 +1601,20 @@ Session session = connection.createTransactionalSession();
...
if (smellsOk())
session.commit();
-else
+else
session.rollback();
]]></programlisting>
<para>
.NET C#:
</para>
-
+
<programlisting>
Connection connection = new Connection(broker);
Session session = connection.CreateTransactionalSession();
...
if (smellsOk())
session.Commit();
-else
+else
session.Rollback();
</programlisting>
<!--
@@ -1670,7 +1669,7 @@ try:
!!! SNIP !!!
]]></programlisting>
-or
+<para>or</para>
<programlisting><![CDATA[
connection = Connection("localhost:5672")
@@ -1682,7 +1681,7 @@ try:
<para>
In .NET, these options can be set using <function>Connection.SetOption()</function> or by passing in a set of options to the constructor. The options can be passed in as a map or in string form:
</para>
-
+
<programlisting>
Connection connection= new Connection(&#34;localhost:5672&#34;, &#34;{reconnect: true}&#34;);
try {
@@ -1692,7 +1691,7 @@ try {
<para>
or
</para>
-
+
<programlisting>
Connection connection = new Connection(&#34;localhost:5672&#34;);
connection.SetOption(&#34;reconnect&#34;, true);
@@ -1881,21 +1880,21 @@ try {
<section id="section-Maps">
<title>Maps and Lists in Message Content</title>
-
+
<para>Many messaging applications need to exchange data across
languages and platforms, using the native datatypes of each
- programming language.</para>
+ programming language.</para>
- <para>The Qpid Messaging API supports <classname>map</classname> and <classname>list</classname> in message content.
+ <para>The Qpid Messaging API supports <classname>map</classname> and <classname>list</classname> in message content.
<footnote><para>Unlike JMS, there is not a specific message type for
map messages.</para></footnote>
- <footnote>
+ <footnote>
<para>
Note that the Qpid JMS client supports MapMessages whose values can be nested maps or lists. This is not standard JMS behaviour.
</para>
- </footnote>
+ </footnote>
Specific language support for <classname>map</classname> and <classname>list</classname> objects are shown in the following table.
</para>
<table id="tabl-Programming_in_Apache_Qpid-Qpid_Maps_in_Message_Content">
@@ -1959,8 +1958,8 @@ content = {'Id' : 987654321, 'name' : 'Widget', 'percent' : 0.99}
content['colours'] = ['red', 'green', 'white']
content['dimensions'] = {'length' : 10.2, 'width' : 5.1,'depth' : 2.0};
content['parts'] = [ [1,2,5], [8,2,5] ]
-content['specs'] = {'colors' : content['colours'],
- 'dimensions' : content['dimensions'],
+content['specs'] = {'colors' : content['colours'],
+ 'dimensions' : content['dimensions'],
'parts' : content['parts'] }
message = Message(content=content)
sender.send(message)
@@ -1970,7 +1969,7 @@ sender.send(message)
<para>The following table shows the datatypes that can be sent in a Python map message,
and the corresponding datatypes that will be received by clients in Java or C++.</para>
-
+
<table id="table-Python-Maps" >
<title>Python Datatypes in Maps</title>
@@ -2000,7 +1999,7 @@ sender.send(message)
- <section id="section-cpp-Maps">
+ <section id="section-cpp-Maps">
<title>Qpid Maps and Lists in C++</title>
@@ -2032,27 +2031,27 @@ Variant::Map dimensions;
dimensions["length"] = 10.2;
dimensions["width"] = 5.1;
dimensions["depth"] = 2.0;
-content["dimensions"]= dimensions;
+content["dimensions"]= dimensions;
Variant::List part1;
part1.push_back(Variant(1));
part1.push_back(Variant(2));
part1.push_back(Variant(5));
-
+
Variant::List part2;
part2.push_back(Variant(8));
part2.push_back(Variant(2));
part2.push_back(Variant(5));
-
+
Variant::List parts;
parts.push_back(part1);
parts.push_back(part2);
-content["parts"]= parts;
+content["parts"]= parts;
Variant::Map specs;
-specs["colours"] = colours;
-specs["dimensions"] = dimensions;
-specs["parts"] = parts;
+specs["colours"] = colours;
+specs["dimensions"] = dimensions;
+specs["parts"] = parts;
content["specs"] = specs;
encode(content, message);
@@ -2063,7 +2062,7 @@ sender.send(message, true);
<para>The following table shows the datatypes that can be sent
in a C++ map message, and the corresponding datatypes that
will be received by clients in Java and Python.</para>
-
+
<table id="table-cpp-Maps">
<title>C++ Datatypes in Maps</title>
<tgroup cols="3">
@@ -2104,6 +2103,7 @@ sender.send(message, true);
</para>
<example>
+ <?dbfo keep-together="auto" ?>
<title>Sending Qpid Maps and Lists in .NET C#</title>
<programlisting><![CDATA[
using System;
@@ -2176,47 +2176,47 @@ Send(message, true);
<para>
The following table shows the mapping between datatypes in .NET and C++.
</para>
-
- <table id="table-dotnet-Maps">
- <title>Datatype Mapping between C++ and .NET binding</title>
- <tgroup cols="2">
- <thead>
- <row>
- <entry>C++ Datatype</entry>
- <entry>&rarr; .NET binding</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>void</entry><entry>nullptr</entry></row>
- <row><entry>bool</entry><entry>bool</entry></row>
- <row><entry>uint8</entry><entry>byte</entry></row>
- <row><entry>uint16</entry><entry>UInt16</entry></row>
- <row><entry>uint32</entry><entry>UInt32</entry></row>
- <row><entry>uint64</entry><entry>UInt64</entry></row>
- <row><entry>uint8</entry><entry>char</entry></row>
- <row><entry>int16</entry><entry>Int16</entry></row>
- <row><entry>int32</entry><entry>Int32</entry></row>
- <row><entry>int64</entry><entry>Int64</entry></row>
- <row><entry>float</entry><entry>Single</entry></row>
- <row><entry>double</entry><entry>Double</entry></row>
- <row><entry>string</entry><entry>string <co id="mapping-dotnet-string" linkends="callout-dotnet-string"/></entry></row>
- <row><entry>qpid::types::Uuid</entry><entry>Guid</entry></row>
- <row><entry>Variant::Map</entry><entry><![CDATA[Dictionary<string, object>]]> <co id="mapping-dotnet-dict-index" linkends="callout-dotnet-string"/></entry></row>
- <row><entry>Variant::List</entry><entry><![CDATA[Collection<object>]]> <co id="mapping-dotnet-list-value" linkends="callout-dotnet-string"/></entry></row>
- </tbody>
- </tgroup>
- </table>
- <calloutlist>
- <callout id="callout-dotnet-string" arearefs="mapping-dotnet-string">
- <para>Strings are currently interpreted only with UTF-8 encoding.</para>
- </callout>
- </calloutlist>
+ <table id="table-dotnet-Maps">
+ <title>Datatype Mapping between C++ and .NET binding</title>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>C++ Datatype</entry>
+ <entry>&rarr; .NET binding</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row><entry>void</entry><entry>nullptr</entry></row>
+ <row><entry>bool</entry><entry>bool</entry></row>
+ <row><entry>uint8</entry><entry>byte</entry></row>
+ <row><entry>uint16</entry><entry>UInt16</entry></row>
+ <row><entry>uint32</entry><entry>UInt32</entry></row>
+ <row><entry>uint64</entry><entry>UInt64</entry></row>
+ <row><entry>uint8</entry><entry>char</entry></row>
+ <row><entry>int16</entry><entry>Int16</entry></row>
+ <row><entry>int32</entry><entry>Int32</entry></row>
+ <row><entry>int64</entry><entry>Int64</entry></row>
+ <row><entry>float</entry><entry>Single</entry></row>
+ <row><entry>double</entry><entry>Double</entry></row>
+ <row><entry>string</entry><entry>string
+ <footnote id="callout-dotnet-string">
+ <para>Strings are currently interpreted only with UTF-8 encoding.</para>
+ </footnote></entry></row>
+ <row><entry>qpid::types::Uuid</entry><entry>Guid</entry></row>
+ <row><entry>Variant::Map</entry><entry><![CDATA[Dictionary<string, object>]]>
+ <footnoteref linkend="callout-dotnet-string"/></entry></row>
+ <row><entry>Variant::List</entry><entry><![CDATA[Collection<object>]]>
+ <footnoteref linkend="callout-dotnet-string"/></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+
+ </section>
- </section>
-
-</section>
+</section>
<section>
<title>The Request / Response Pattern</title>
@@ -2347,8 +2347,8 @@ std::cout << request.getContent() << " -> " << response.getContent() << std::end
<example>
<title>Tracking cluster membership</title>
-
- <para>In C++:</para>
+
+ <para>In C++:</para>
<programlisting><![CDATA[
#include <qpid/messaging/FailoverUpdates.h>
@@ -2361,7 +2361,7 @@ try {
]]>
</programlisting>
- <para>In python:</para>
+ <para>In python:</para>
<programlisting><![CDATA[
import qpid.messaging.util
@@ -2376,7 +2376,7 @@ try:
<para>
In .NET C#:
</para>
-
+
<programlisting>
using Org.Apache.Qpid.Messaging;
...
@@ -2407,14 +2407,14 @@ try {
</para>
<para>Use QPID_LOG_ENABLE to set the level of logging you are interested in (trace, debug, info, notice, warning, error, or critical):
</para>
-
+
<screen>
export QPID_LOG_ENABLE=&#34;warning+&#34;
</screen>
<para>
The Qpidd broker and C++ clients use QPID_LOG_OUTPUT to determine where logging output should be sent. This is either a file name or the special values stderr, stdout, or syslog:
</para>
-
+
<screen>
export QPID_LOG_TO_FILE=&#34;/tmp/myclient.out&#34;
</screen>
@@ -2422,26 +2422,26 @@ export QPID_LOG_TO_FILE=&#34;/tmp/myclient.out&#34;
<para>
From a Windows command prompt, use the following command format to set the environment variables:
</para>
-
+
<screen>
set QPID_LOG_ENABLE=warning+
set QPID_LOG_TO_FILE=D:\tmp\myclient.out
</screen>
</section>
-
+
<section>
<title>Logging in Python</title>
<para>
The Python client library supports logging using the standard Python logging module. The easiest way to do logging is to use the <command>basicConfig()</command>, which reports all warnings and errors:
</para>
-
+
<programlisting>from logging import basicConfig
basicConfig()
</programlisting>
<para>
Qpidd also provides a convenience method that makes it easy to specify the level of logging desired. For instance, the following code enables logging at the <command>DEBUG</command> level:
</para>
-
+
<programlisting>from qpid.log import enable, DEBUG
enable("qpid.messaging.io", DEBUG)
</programlisting>
@@ -2604,9 +2604,9 @@ enable("qpid.messaging.io", DEBUG)
<entry>C++ API
<footnote>
<para>
- The .NET Binding for C++ Messaging provides all the
- message and delivery properties described in the C++ API.
- See <xref linkend="table-Dotnet-Binding-Message" /> .
+ The .NET Binding for C++ Messaging provides all the
+ message and delivery properties described in the C++ API.
+ See <xref linkend="table-Dotnet-Binding-Message" /> .
</para>
</footnote>
</entry>
@@ -2660,7 +2660,7 @@ enable("qpid.messaging.io", DEBUG)
same manner. In addition the routing key on incoming transfers
will be exposed directly via the custom property with key
<literal>x-amqp-0-10.routing-key</literal>.</para>
-
+
</section>
</chapter>
@@ -2669,7 +2669,7 @@ enable("qpid.messaging.io", DEBUG)
<title>Using the Qpid JMS client</title>
<section>
<title>A Simple Messaging Program in Java JMS</title>
-
+
<para>The following program shows how to send and receive a
message using the Qpid JMS client. JMS programs typically use
JNDI to obtain connection factory and destination objects which
@@ -2710,7 +2710,7 @@ public class Hello {
properties.load(this.getClass().getResourceAsStream("hello.properties")); <co id="hello-java-properties" linkends="callout-java-properties"/>
Context context = new InitialContext(properties); <co id="hello-java-context" linkends="callout-java-context"/>
- ConnectionFactory connectionFactory
+ ConnectionFactory connectionFactory
= (ConnectionFactory) context.lookup("qpidConnectionfactory"); <co id="hello-java-connection-factory" linkends="callout-java-connection-factory"/>
Connection connection = connectionFactory.createConnection(); <co id="hello-java-connection" linkends="callout-java-connection"/>
connection.start(); <co id="hello-java-start" linkends="callout-java-start"/>
@@ -2782,11 +2782,11 @@ public class Hello {
<example>
<title>JNDI Properties File for "Hello world!" example</title>
<programlisting>
-java.naming.factory.initial
+java.naming.factory.initial
= org.apache.qpid.jndi.PropertiesFileInitialContextFactory
# connectionfactory.[jndiname] = [ConnectionURL]
-connectionfactory.qpidConnectionfactory
+connectionfactory.qpidConnectionfactory
= amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' <co id="hello-properties-connectionfactory" linkends="callout-hello-properties-connectionfactory"/>
# destination.[jndiname] = [address_string]
destination.topicExchange = amq.topic <co id="hello-properties-destination" linkends="callout-hello-properties-destination"/>
@@ -2824,11 +2824,11 @@ destination.topicExchange = amq.topic <co id="hello-properties-destination" link
<example>
<title>JNDI Properties File</title>
<programlisting><![CDATA[
-java.naming.factory.initial
+java.naming.factory.initial
= org.apache.qpid.jndi.PropertiesFileInitialContextFactory
# connectionfactory.[jndiname] = [ConnectionURL]
-connectionfactory.qpidConnectionfactory
+connectionfactory.qpidConnectionfactory
= amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'
# destination.[jndiname] = [address_string]
destination.topicExchange = amq.topic
@@ -2837,7 +2837,7 @@ destination.topicExchange = amq.topic
<para>The following sections describe the JNDI properties that Qpid uses.</para>
-
+
<section>
<title>JNDI Properties for Apache Qpid</title>
<para>
@@ -2895,7 +2895,7 @@ destination.topicExchange = amq.topic
<para>
Can be used for defining all amq destinations,
queues, topics and header matching, using an
- address string.
+ address string.
<footnote><para>Binding URLs, which were used in
earlier versions of the Qpid Java JMS client, can
@@ -2908,19 +2908,19 @@ destination.topicExchange = amq.topic
</tgroup>
</table>
</section>
-
+
<section id="section-jms-connection-url">
<title>Connection URLs</title>
<para>
In JNDI properties, a Connection URL specifies properties for a connection. The format for a Connection URL is:
</para>
-
+
<programlisting>amqp://[&lt;user&gt;:&lt;pass&gt;@][&lt;clientid&gt;]&lt;virtualhost&gt;[?&lt;option&gt;=&#39;&lt;value&gt;&#39;[&amp;&lt;option&gt;=&#39;&lt;value&gt;&#39;]]
</programlisting>
<para>
For instance, the following Connection URL specifies a user name, a password, a client ID, a virtual host ("test"), a broker list with a single broker, and a TCP host with the host name <quote>localhost</quote> using port 5672:
</para>
-
+
<programlisting>amqp://username:password@clientid/test?brokerlist=&#39;tcp://localhost:5672&#39;
</programlisting>
<para>
@@ -3016,12 +3016,12 @@ destination.topicExchange = amq.topic
<para>
Broker lists are specified using a URL in this format:
</para>
-
+
<programlisting>brokerlist=&lt;transport&gt;://&lt;host&gt;[:&lt;port&gt;](?&lt;param>=&lt;value>)?(&amp;&lt;param>=&lt;value>)*</programlisting>
<para>
For instance, this is a typical broker list:
</para>
-
+
<programlisting>brokerlist=&#39;tcp://localhost:5672&#39;
</programlisting>
@@ -3100,7 +3100,7 @@ amqp://guest:guest@test/test?sync_ack='true'
sasl_encryption
</entry>
<entry>
- Boolean
+ Boolean
</entry>
<entry>
If <literal>sasl_encryption='true'</literal>, the JMS client attempts to negotiate a security layer with the broker using GSSAPI to encrypt the connection. Note that for this to happen, GSSAPI must be selected as the sasl_mech.
@@ -3226,7 +3226,7 @@ amqp://guest:guest@test/test?sync_ack='true'
</tgroup>
</table>
</section>
- </section>
+ </section>
<section>
<title>Java JMS Message Properties</title>
@@ -3287,7 +3287,7 @@ amqp://guest:guest@test/test?sync_ack='true'
</tbody>
</tgroup>
</table>
-
+
</section>
<section id="section-JMS-MapMessage">
@@ -3326,7 +3326,7 @@ m.setDoubleProperty("price", 0.99);
List<String> colors = new ArrayList<String>();
colors.add("red");
colors.add("green");
-colors.add("white");
+colors.add("white");
m.setObject("colours", colors);
Map<String,Double> dimensions = new HashMap<String,Double>();
@@ -3351,7 +3351,7 @@ producer.send(m);
</example>
<para>The following table shows the datatypes that can be sent in a <classname>MapMessage</classname>, and the corresponding datatypes that will be received by clients in Python or C++.</para>
-
+
<table id="table-Java-Maps">
<title>Java Datatypes in Maps</title>
<tgroup cols="3">
@@ -3378,7 +3378,7 @@ producer.send(m);
</table>
</section>
-
+
<section id="section-JMS-Logging">
<title>JMS Client Logging</title>
<para>The JMS Client logging is handled using the Simple Logging Facade for Java (<ulink url="http://www.slf4j.org/">SLF4J</ulink>). As the name implies, slf4j is a facade that delegates to other logging systems like log4j or JDK 1.4 logging. For more information on how to configure slf4j for specific logging systems, please consult the slf4j documentation.</para>
@@ -3399,7 +3399,7 @@ log4j.appender.console.Threshold=all
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
]]></programlisting>
- </example>
+ </example>
</section>
@@ -3407,13 +3407,13 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<title>Configuring the JMS Client</title>
<para>The Qpid JMS Client allows several configuration options to customize it's behaviour at different levels of granualarity.</para>
-
+
<itemizedlist>
<listitem>
<para>
JVM level using JVM arguments : Configuration that affects all connections, sessions, consumers and producers created within that JVM.
</para>
- <para>Ex. <varname>-Dmax_prefetch=1000</varname> property specifies the message credits to use.</para>
+ <para>Ex. <varname>-Dmax_prefetch=1000</varname> property specifies the message credits to use.</para>
</listitem>
<listitem>
@@ -3422,7 +3422,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
</para>
<para>Ex. <varname>amqp://guest:guest@test/test?max_prefetch='1000'
&amp;brokerlist='tcp://localhost:5672'
-</varname> property specifies the message credits to use. This overrides any value specified via the JVM argument <varname>max_prefetch</varname>.</para>
+</varname> property specifies the message credits to use. This overrides any value specified via the JVM argument <varname>max_prefetch</varname>.</para>
<para>Please refer to the <xref linkend="section-jms-connection-url"/> section for a complete list of all properties and how to use them.</para>
</listitem>
@@ -3430,11 +3430,11 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<para>
Destination level using Addressing options : Affects the producer(s) and consumer(s) created using the respective destination.
</para>
- <para>Ex. <varname>my-queue; {create: always, link:{capacity: 10}}</varname>, where <varname>capacity</varname> option specifies the message credits to use. This overrides any connection level configuration.</para>
+ <para>Ex. <varname>my-queue; {create: always, link:{capacity: 10}}</varname>, where <varname>capacity</varname> option specifies the message credits to use. This overrides any connection level configuration.</para>
<para>Please refer to the <xref linkend="section-addresses"/> section for a complete understanding of addressing and it's various options.</para>
</listitem>
</itemizedlist>
-
+
<para>Some of these config options are available at all three levels (Ex. <varname>max_prefetch</varname>), while others are available only at JVM or connection level.</para>
<section>
@@ -3442,7 +3442,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Connection Behaviour</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3479,7 +3479,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Session Behaviour</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3515,7 +3515,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Consumer Behaviour</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3538,8 +3538,8 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<entry>1000 (ms)</entry>
<entry><para>Timer interval to flush message acks in buffer when using AUTO_ACK and DUPS_OK.</para> <para>When using the above ack modes, message acks are batched and sent if one of the following conditions are met (which ever happens first).
<itemizedlist>
- <listitem>When the ack timer fires.</listitem>
- <listitem>if un_acked_msg_count > max_prefetch/2.</listitem>
+ <listitem><para>When the ack timer fires.</para></listitem>
+ <listitem><para>if un_acked_msg_count > max_prefetch/2.</para></listitem>
</itemizedlist>
</para>
<para>The ack timer can be disabled by setting it to 0.</para>
@@ -3558,7 +3558,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Producer Behaviour</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3580,7 +3580,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Threading</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3609,7 +3609,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For I/O</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3638,7 +3638,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table >
<title>Config Options For Security</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3673,8 +3673,8 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
</table>
<table>
- <title>Config Options For Security - Standard JVM properties needed when using GSSAPI as the SASL mechanism.<footnote>Please refer to the Java security documentation for a complete understanding of the above properties.</footnote></title>
- <tgroup cols="3">
+ <title>Config Options For Security - Standard JVM properties needed when using GSSAPI as the SASL mechanism.<footnote><para>Please refer to the Java security documentation for a complete understanding of the above properties.</para></footnote></title>
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3710,7 +3710,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
<table>
<title>Config Options For Security - Using SSL for securing connections or using EXTERNAL as the SASL mechanism.</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3745,8 +3745,8 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
</table>
<table>
- <title>Config Options For Security - Standard JVM properties needed when Using SSL for securing connections or using EXTERNAL as the SASL mechanism.<footnote>Qpid allows you to have per connection key and trust stores if required. If specified per connection, the JVM arguments are ignored.</footnote></title>
- <tgroup cols="3">
+ <title>Config Options For Security - Standard JVM properties needed when Using SSL for securing connections or using EXTERNAL as the SASL mechanism.<footnote><para>Qpid allows you to have per connection key and trust stores if required. If specified per connection, the JVM arguments are ignored.</para></footnote></title>
+ <tgroup cols="4">
<thead>
<row>
<entry>Property Name</entry>
@@ -3808,7 +3808,7 @@ log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
"hello_service_node" has been created and configured on the AMQP
broker.</para>
- <example>
+ <example><?dbfo keep-together="auto" ?>
<title>Traditional service model "Hello world!" example</title>
<programlisting><![CDATA[
namespace Apache.Qpid.Documentation.HelloService
@@ -3901,7 +3901,7 @@ namespace Apache.Qpid.Documentation.HelloService
contains the raw content and is identical and fully interoperable with
the Qpid C++ "Hello world!" example.</para>
- <example>
+ <example><?dbfo keep-together="auto" ?>
<title>Binary "Hello world!" example using the channel model</title>
<programlisting><![CDATA[
namespace Apache.Qpid.Samples.Channel.HelloWorld
@@ -3915,7 +3915,7 @@ namespace Apache.Qpid.Samples.Channel.HelloWorld
using Apache.Qpid.Channel;
public class HelloWorld
- {
+ {
static void Main(string[] args)
{
String broker = "localhost";
@@ -4245,11 +4245,12 @@ using (TransactionScope ts = new TransactionScope())
<chapter>
<title>The .NET Binding for the C++ Messaging Client</title>
<para>
- The .NET Binding for the C++ Qpid Messaging Client is a library that gives
+ The .NET Binding for the C++ Qpid Messaging Client is a library that gives
any .NET program access to Qpid C++ Messaging objects and methods.
</para>
<section>
<title>.NET Binding for the C++ Messaging Client Component Architecture</title>
+
<programlisting><![CDATA[
+----------------------------+
| Dotnet examples |
@@ -4281,8 +4282,10 @@ unmanaged | org.apache.qpid.messaging.dll |
| qpid*.dll qmf*.dll |
+--------+--------------+----------+
]]></programlisting>
-This diagram illustrates the code and library components of the binding
-and the hierarchical relationships between them.
+
+
+<para>This diagram illustrates the code and library components of the binding
+and the hierarchical relationships between them.</para>
<table id="table-Dotnet-Binding-Component-Architecture" >
<title>.NET Binding for the C++ Messaging Client Component Architecture</title>
@@ -4290,7 +4293,7 @@ and the hierarchical relationships between them.
<thead>
<row>
<entry>Component Name</entry>
- <entry>Component Function</entry>
+ <entry>Component Function</entry>
</row>
</thead>
<tbody>
@@ -4306,9 +4309,9 @@ and the hierarchical relationships between them.
<row>
<entry>.NET Messaging Binding Library</entry>
<entry>The .NET Messaging Binding library provides interoprability between
- managed .NET programs and the unmanaged, native Qpid Messaging C++ core
- run time system. .NET programs create a Reference to this library thereby
- exposing all of the native C++ Messaging functionality to programs
+ managed .NET programs and the unmanaged, native Qpid Messaging C++ core
+ run time system. .NET programs create a Reference to this library thereby
+ exposing all of the native C++ Messaging functionality to programs
written in any .NET language.</entry>
</row>
<row>
@@ -4328,8 +4331,8 @@ and the hierarchical relationships between them.
<section>
<title>.NET Binding for the C++ Messaging Client Examples</title>
- This chapter describes the various sample programs that are available to
- illustrate common Qpid Messaging usage.
+ <para>This chapter describes the various sample programs that
+ are available to illustrate common Qpid Messaging usage.</para>
<table id="table-Dotnet-Binding-Example-Client-Server">
<title>Example : Client - Server</title>
@@ -4511,8 +4514,11 @@ and the hierarchical relationships between them.
<section>
<title>.NET Binding Class Mapping to Underlying C++ Messaging API</title>
- This chapter describes the specific mappings between classes in the .NET
- Binding and the underlying C++ Messaging API.
+
+ <para>This chapter describes the specific mappings between
+ classes in the .NET Binding and the underlying C++ Messaging
+ API.</para>
+
<section>
<title>.NET Binding for the C++ Messaging API Class: Address</title>
<table id="table-Dotnet-Binding-Address">
@@ -6308,10 +6314,10 @@ namespace Org.Apache.Qpid.Messaging.SessionReceiver
<para>
To use this class a client program includes references to both
Org.Apache.Qpid.Messaging and Org.Apache.Qpid.Messaging.SessionReceiver.
- The calling program creates a function that implements the
+ The calling program creates a function that implements the
ISessionReceiver interface. This function will be called whenever
message is received by the session. The callback process is started
- by creating a CallbackServer and will continue to run until the
+ by creating a CallbackServer and will continue to run until the
client program calls the CallbackServer.Close function.
</para>
<para>
diff --git a/qpid/doc/book/src/Security.xml b/qpid/doc/book/src/Security.xml
new file mode 100644
index 0000000000..77d10abf8c
--- /dev/null
+++ b/qpid/doc/book/src/Security.xml
@@ -0,0 +1,1197 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<section id="chap-Messaging_User_Guide-Security">
+ <title>Security</title>
+ <para>
+ This chapter describes how authentication, rule-based authorization, encryption, and digital signing can be accomplished using Qpid. Authentication is the process of verifying the identity of a user; in Qpid, this is done using the SASL framework. Rule-based authorization is a mechanism for specifying the actions that each user is allowed to perform; in Qpid, this is done using an Access Control List (ACL) that is part of the Qpid broker. Encryption is used to ensure that data is not transferred in a plain-text format that could be intercepted and read. Digital signatures provide proof that a given message was sent by a known sender. Encryption and signing are done using SSL (they can also be done using SASL, but SSL provides stronger encryption).
+ </para>
+ <section id="sect-Messaging_User_Guide-Security-User_Authentication">
+ <title>User Authentication</title>
+ <para>
+ AMQP uses Simple Authentication and Security Layer (SASL) to authenticate client connections to the broker. SASL is a framework that supports a variety of authentication methods. For secure applications, we suggest <command>CRAM-MD5</command>, <command>DIGEST-MD5</command>, or <command>GSSAPI</command>. The <command>ANONYMOUS</command> method is not secure. The <command>PLAIN</command> method is secure only when used together with SSL.
+ </para>
+ <para>
+ Both the Qpid broker and Qpid clients use the <ulink url="http://cyrusimap.web.cmu.edu/">Cyrus SASL library</ulink>, a full-featured authentication framework, which offers many configuration options. This section shows how to configure users for authentication with SASL, which is sufficient when using <command>SASL PLAIN</command>. If you are not using SSL, you should configure SASL to use <command>CRAM-MD5</command>, <command>DIGEST-MD5</command>, or <command>GSSAPI</command> (which provides Kerberos authentication). For information on configuring these and other options in SASL, see the Cyrus SASL documentation<!-- at <filename>/usr/share/doc/cyrus-sasl-lib-2.1.22/index.html</filename> for &RHEL5; or <filename>/usr/share/doc/cyrus-sasl-2.1.19/index.html</filename> for &RHEL4;-->.
+ </para>
+ <important>
+ <title>Important</title>
+ <para>
+ The <command>SASL PLAIN</command> method sends passwords in cleartext, and is vulnerable to man-in-the-middle attacks unless SSL (Secure Socket Layer) is also used (see <xref linkend="sect-Messaging_User_Guide-Security-Encryption_using_SSL" />).
+ </para>
+ <para>
+ If you are not using SSL, we recommend that you disable <command>PLAIN</command> authentication in the broker.
+ </para>
+
+ </important>
+ <para>
+ The Qpid broker uses the <command>auth yes|no</command> option to determine whether to use SASL authentication. Turn on authentication by setting <command>auth</command> to <command>yes</command> in <filename>/etc/qpidd.conf</filename>:
+ </para>
+
+<programlisting>
+# /etc/qpidd.conf
+#
+# Set auth to &#39;yes&#39; or &#39;no&#39;
+
+auth=yes
+</programlisting>
+ <section id="sect-Messaging_User_Guide-User_Authentication-Configuring_SASL">
+ <title>Configuring SASL</title>
+ <para>
+ On Linux systems, the SASL configuration file is generally found in <filename>/etc/sasl2/qpidd.conf</filename> <!-- for &RHEL5; and-->or <filename>/usr/lib/sasl2/qpidd.conf</filename><!-- for &RHEL4;-->.
+ </para>
+ <para>
+ The SASL database contains user names and passwords for SASL. In SASL, a user may be associated with a <firstterm>realm</firstterm>. The Qpid broker authenticates users in the <command>QPID</command> realm by default, but it can be set to a different realm using the <command>realm</command> option:
+ </para>
+
+<programlisting>
+# /etc/qpidd.conf
+#
+# Set the SASL realm using &#39;realm=&#39;
+
+auth=yes
+realm=QPID
+</programlisting>
+ <para>
+ The SASL database is installed at <filename>/var/lib/qpidd/qpidd.sasldb</filename>; initially, it has one user named <command>guest</command> in the <command>QPID</command> realm, and the password for this user is <command>guest</command>.
+ </para>
+ <note>
+ <title>Note</title>
+ <para>
+ The user database is readable only by the <systemitem class="username">qpidd</systemitem> user. When run as a daemon, Qpid always runs as the <systemitem class="username">qpidd</systemitem> user. If you start the broker from a user other than the <systemitem class="username">qpidd</systemitem> user, you will need to either reconfigure SASL or turn authentication off.
+ </para>
+
+ </note>
+ <important>
+ <title>Important</title>
+ <para>
+ The SASL database stores user names and passwords in plain text. If it is compromised so are all of the passwords that it stores. This is the reason that the <systemitem class="username">qpidd</systemitem> user is the only user that can read the database. If you modify permissions, be careful not to expose the SASL database.
+ </para>
+
+ </important>
+ <para>
+ Add new users to the database by using the <command>saslpasswd2</command> command, which specifies a realm and a user ID. A user ID takes the form <command><replaceable>user-id</replaceable>@<replaceable>domain</replaceable>.</command>.
+ </para>
+
+<screen># saslpasswd2 -f /var/lib/qpidd/qpidd.sasldb -u <replaceable>realm</replaceable> <replaceable>new_user_name</replaceable></screen>
+ <para>
+ To list the users in the SASL database, use <command>sasldblistusers2</command>:
+ </para>
+
+<screen># sasldblistusers2 -f /var/lib/qpidd/qpidd.sasldb
+</screen>
+ <para>
+ If you are using <command>PLAIN</command> authentication, users who are in the database can now connect with their user name and password. This is secure only if you are using SSL. If you are using a more secure form of authentication, please consult your SASL documentation for information on configuring the options you need.
+ </para>
+
+ </section>
+
+ <section id="sect-Messaging_User_Guide-User_Authentication-Kerberos">
+ <title>Kerberos</title>
+ <para>
+ Both the Qpid broker and Qpid users are &#39;principals&#39; of the Kerberos server, which means that they are both clients of the Kerberos authentication services.
+ </para>
+ <para>
+ To use Kerberos, both the Qpid broker and each Qpid user must be authenticated on the Kerberos server:
+ </para>
+ <procedure>
+ <step>
+ <para>
+ Install the Kerberos workstation software and Cyrus SASL GSSAPI on each machine that runs a qpidd broker or a qpidd messaging client:
+ </para>
+
+<screen>$ sudo yum install cyrus-sasl-gssapi krb5-workstation</screen>
+
+ </step>
+ <step>
+ <para>
+ Make sure that the Qpid broker is registered in the Kerberos database.
+ </para>
+ <para>
+ Traditionally, a Kerberos principal is divided into three parts: the primary, the instance, and the realm. A typical Kerberos V5 has the format <literal>primary/instance@REALM</literal>. For a Qpid broker, the primary is <literal>qpidd</literal>, the instance is the fully qualified domain name, which you can obtain using <command>hostname --fqdn</command>, and the REALM is the Kerberos domain realm. By default, this realm is <literal>QPID</literal>, but a different realm can be specified in qpid.conf, e.g.:
+<screen>realm=EXAMPLE.COM</screen>
+
+ </para>
+ <para>
+ For instance, if the fully qualified domain name is <literal>dublduck.example.com</literal> and the Kerberos domain realm is <literal>EXAMPLE.COM</literal>, then the principal name is <literal>qpidd/dublduck.example.com@EXAMPLE.COM</literal>.
+ </para>
+ <para>
+ The following script creates a principal for qpidd:
+ </para>
+
+<programlisting>
+FDQN=`hostname --fqdn`
+REALM=&#34;EXAMPLE.COM&#34;
+kadmin -r $REALM -q &#34;addprinc -randkey -clearpolicy qpidd/$FQDN&#34;
+</programlisting>
+ <para>
+ Now create a Kerberos keytab file for the Qpid broker. The Qpid broker must have read access to the keytab file. The following script creates a keytab file and allows the broker read access:
+ </para>
+
+<programlisting>
+QPIDD_GROUP=&#34;qpidd&#34;
+kadmin -r $REALM -q &#34;ktadd -k /etc/qpidd.keytab qpidd/$FQDN@$REALM&#34;
+chmod g+r /etc/qpidd.keytab
+chgrp $QPIDD_GROUP /etc/qpidd.keytab
+</programlisting>
+ <para>
+ The default location for the keytab file is <filename>/etc/krb5.keytab</filename>. If a different keytab file is used, the KRB5_KTNAME environment variable must contain the name of the file, e.g.:
+ </para>
+
+<programlisting>
+export KRB5_KTNAME=/etc/qpidd.keytab
+</programlisting>
+ <para>
+ If this is correctly configured, you can now enable kerberos support on the Qpid broker by setting the <varname>auth</varname> and <varname>realm</varname> options in <filename>/etc/qpidd.conf</filename>:
+ </para>
+
+<programlisting>
+# /etc/qpidd.conf
+auth=yes
+realm=EXAMPLE.COM
+</programlisting>
+ <para>
+ Restart the broker to activate these settings.
+ </para>
+
+ </step>
+ <step>
+ <para>
+ Make sure that each Qpid user is registered in the Kerberos database, and that Kerberos is correctly configured on the client machine. The Qpid user is the account from which a Qpid messaging client is run. If it is correctly configured, the following command should succeed:
+ </para>
+
+<screen>$ kinit user@REALM.COM</screen>
+
+ </step>
+
+ </procedure>
+
+ <para>
+ Java JMS clients require a few additional steps.
+ </para>
+ <procedure>
+ <step>
+ <para>
+ The Java JVM must be run with the following arguments:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>-Djavax.security.auth.useSubjectCredsOnly=false</term>
+ <listitem>
+ <para>
+ Forces the SASL GASSPI client to obtain the kerberos credentials explicitly instead of obtaining from the &#34;subject&#34; that owns the current thread.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term>-Djava.security.auth.login.config=myjas.conf</term>
+ <listitem>
+ <para>
+ Specifies the jass configuration file. Here is a sample JASS configuration file:
+ </para>
+
+<programlisting>
+com.sun.security.jgss.initiate {
+ com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
+};
+</programlisting>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term>-Dsun.security.krb5.debug=true</term>
+ <listitem>
+ <para>
+ Enables detailed debug info for troubleshooting
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
+ </step>
+ <step>
+ <para>
+ The client&#39;s Connection URL must specify the following Kerberos-specific broker properties:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <varname>sasl_mechs</varname> must be set to <literal>GSSAPI</literal>.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ <varname>sasl_protocol</varname> must be set to the principal for the qpidd broker, e.g. <literal>qpidd</literal>/
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ <varname>sasl_server</varname> must be set to the host for the SASL server, e.g. <literal>sasl.com</literal>.
+ </para>
+
+ </listitem>
+
+ </itemizedlist>
+ <para>
+ Here is a sample connection URL for a Kerberos connection:
+ </para>
+
+<screen>amqp://guest@clientid/testpath?brokerlist=&#39;tcp://localhost:5672?sasl_mechs=&#39;GSSAPI&#39;&amp;sasl_protocol=&#39;qpidd&#39;&amp;sasl_server=&#39;&#60;server-host-name&#62;&#39;&#39;</screen>
+
+ </step>
+
+ </procedure>
+<!--
+ <para>
+ Please refer to the following documentation for more detail on using Kerberos:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>RHEL5</term>
+ <listitem>
+ <para>
+ <ulink url="http://www.redhat.com/docs/manuals/enterprise/RHEL-5-manual/Deployment_Guide-en-US/ch-kerberos.html"> Red Hat Enterprise Linux 5: Deployment Guide </ulink>
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term>RHEL4</term>
+ <listitem>
+ <para>
+ <ulink url="http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/ref-guide/ch-kerberos.html"> Red Hat Enterprise Linux 4: Reference Guide </ulink>
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term>Java</term>
+ <listitem>
+ <para>
+ <ulink url="http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/index.html"> Introduction to JAAS and Java GSS-API Tutorials </ulink>
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+ -->
+
+ </section>
+
+
+ </section>
+
+ <!-- ################################################### --> <section id="sect-Messaging_User_Guide-Security-Authorization">
+ <title>Authorization</title>
+ <para>
+ In Qpid, Authorization specifies which actions can be performed by each authenticated user using an Access Control List (ACL). Use the <command>--acl-file</command> command to load the access control list. The filename should have a <filename>.acl</filename> extension:
+ </para>
+
+<screen>
+$ qpidd --acl-file <replaceable>./aclfilename.acl</replaceable></screen>
+ <para>
+ Each line in an ACL file grants or denies specific rights to a user. If the last line in an ACL file is <literal>acl deny all all</literal>, the ACL uses <firstterm>deny mode</firstterm>, and only those rights that are explicitly allowed are granted:
+ </para>
+
+<programlisting>
+acl allow rajith@QPID all all
+acl deny all all
+</programlisting>
+ <para>
+ On this server, <literal>rajith@QPID</literal> can perform any action, but nobody else can. Deny mode is the default, so the previous example is equivalent to the following ACL file:
+ </para>
+
+<programlisting>
+acl allow rajith@QPID all all
+</programlisting>
+ <para>
+ In deny mode, denying rights to an action is redundant and has no effect.
+ </para>
+
+<programlisting>
+acl allow rajith@QPID all all
+acl deny jonathan@QPID all all # This rule is redundant, and has no effect
+acl deny all all
+</programlisting>
+ <para>
+ If the last line in an ACL file is <literal>acl allow all all</literal>, ACL uses <firstterm>allow mode</firstterm>, and all rights are granted except those that are explicitly denied. The following ACL file allows everyone else to perform any action, but denies <literal>jonathan@QPID</literal> all permissions.
+ </para>
+
+<programlisting>
+acl deny jonathan@QPID all all
+acl allow all all
+</programlisting>
+ <para>
+ In allow mode, allowing rights to an action is redundant and has no effect.
+ </para>
+
+<programlisting>
+acl allow rajith@QPID all all # This rule is redundant, and has no effect
+acl deny jonathan@QPID all all
+acl allow all all
+</programlisting>
+ <important>
+ <title>Important</title>
+ <para>
+ ACL processing ends when one of the following lines is encountered:
+ </para>
+
+<programlisting>
+acl allow all all
+</programlisting>
+
+<programlisting>
+acl deny all all
+</programlisting>
+ <para>
+ Any lines that occur after one of these statements will be ignored:
+ </para>
+
+<programlisting>
+acl allow all all
+acl deny jonathan@QPID all all # This line is ignored !!!
+</programlisting>
+
+ </important>
+ <para>
+ ACL syntax allows fine-grained access rights for specific actions:
+ </para>
+
+<programlisting>
+acl allow carlt@QPID create exchange name=carl.*
+acl allow fred@QPID create all
+acl allow all consume queue
+acl allow all bind exchange
+acl deny all all
+</programlisting>
+ <para>
+ An ACL file can define user groups, and assign permissions to them:
+ </para>
+
+<programlisting>
+group admin ted@QPID martin@QPID
+acl allow admin create all
+acl deny all all
+</programlisting>
+ <!-- ######## --> <section id="sect-Messaging_User_Guide-Authorization-ACL_Syntax">
+ <title>ACL Syntax</title>
+ <para>
+ ACL rules must be on a single line and follow this syntax:
+<programlisting>acl permission {&#60;group-name&#62;|&#60;user-name&#62;|&#34;all&#34;} {action|&#34;all&#34;} [object|&#34;all&#34;] [property=&#60;property-value&#62;]
+</programlisting>
+ ACL rules can also include a single object name (or the keyword <parameter>all</parameter>) and one or more property name value pairs in the form <command>property=value</command>
+ </para>
+ <para>
+ The following tables show the possible values for <command>permission</command>, <command>action</command>, <command>object</command>, and <command>property</command> in an ACL rules file.
+ </para>
+ <table id="tabl-Messaging_User_Guide-ACL_Syntax-ACL_Rules_permission">
+ <title>ACL Rules: permission</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <command>allow</command>
+ </entry>
+ <entry>
+ <para>
+ Allow the action <!-- ### rule => the action -->
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>allow-log</command>
+ </entry>
+ <entry>
+ <para>
+ Allow the action and log the action in the event log
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>deny</command>
+ </entry>
+ <entry>
+ <para>
+ Deny the action
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>deny-log</command>
+ </entry>
+ <entry>
+ <para>
+ Deny the action and log the action in the event log
+ </para>
+
+ </entry>
+
+ </row>
+
+ </tbody>
+
+ </tgroup>
+
+ </table>
+ <!-- Actions --> <table id="tabl-Messaging_User_Guide-ACL_Syntax-ACL_Rulesaction">
+ <title>ACL Rules:action</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <command>consume</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when subscriptions are created
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>publish</command>
+ </entry>
+ <entry>
+ <para>
+ Applied on a per message basis on publish message transfers, this rule consumes the most resources
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>create</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when an object is created, such as bindings, queues, exchanges, links
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>access</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when an object is read or accessed
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>bind</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when objects are bound together
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>unbind</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when objects are unbound
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>delete</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when objects are deleted
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>purge</command>
+ </entry>
+ <entry>
+ <para>
+ Similar to delete but the action is performed on more than one object
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>update</command>
+ </entry>
+ <entry>
+ <para>
+ Applied when an object is updated
+ </para>
+
+ </entry>
+
+ </row>
+
+ </tbody>
+
+ </tgroup>
+
+ </table>
+ <!-- object types --> <table id="tabl-Messaging_User_Guide-ACL_Syntax-ACL_Rulesobject">
+ <title>ACL Rules:object</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <command>queue</command>
+ </entry>
+ <entry>
+ <para>
+ A queue
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>exchange</command>
+ </entry>
+ <entry>
+ <para>
+ An exchange
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>broker</command>
+ </entry>
+ <entry>
+ <para>
+ The broker
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>link</command>
+ </entry>
+ <entry>
+ <para>
+ A federation or inter-broker link
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>method</command>
+ </entry>
+ <entry>
+ <para>
+ Management or agent or broker method
+ </para>
+
+ </entry>
+
+ </row>
+
+ </tbody>
+
+ </tgroup>
+
+ </table>
+ <!--
+ <para>
+ Wild cards can be used on properties that are a string. The following properties are supported: --> <table id="tabl-Messaging_User_Guide-ACL_Syntax-ACL_Rulesproperty">
+ <title>ACL Rules:property</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <command>name</command>
+ </entry>
+ <entry>
+ <para>
+ String. Object name, such as a queue name or exchange name.
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>durable</command>
+ </entry>
+ <entry>
+ <para>
+ Boolean. Indicates the object is durable
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>routingkey</command>
+ </entry>
+ <entry>
+ <para>
+ Sring. Specifies routing key
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>passive</command>
+ </entry>
+ <entry>
+ <para>
+ Boolean. Indicates the presence of a <parameter>passive</parameter> flag
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>autodelete</command>
+ </entry>
+ <entry>
+ <para>
+ Boolean. Indicates whether or not the object gets deleted when the connection is closed
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>exclusive</command>
+ </entry>
+ <entry>
+ <para>
+ Boolean. Indicates the presence of an <parameter>exclusive</parameter> flag
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>type</command>
+ </entry>
+ <entry>
+ <para>
+ String. Type of object, such as topic, fanout, or xml
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>alternate</command>
+ </entry>
+ <entry>
+ <para>
+ String. Name of the alternate exchange
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>queuename</command>
+ </entry>
+ <entry>
+ <para>
+ String. Name of the queue (used only when the object is something other than <parameter>queue</parameter>
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>schemapackage</command>
+ </entry>
+ <entry>
+ <para>
+ String. QMF schema package name
+ </para>
+
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>schemaclass</command>
+ </entry>
+ <entry>
+ <para>
+ String. QMF schema class name
+ </para>
+
+ </entry>
+
+ </row>
+
+ </tbody>
+
+ </tgroup>
+
+ </table>
+
+ </section>
+
+ <section id="sect-Messaging_User_Guide-Authorization-ACL_Syntactic_Conventions">
+ <title>ACL Syntactic Conventions</title>
+ <para>
+ In ACL files, the following syntactic conventions apply:
+ <itemizedlist>
+ <listitem>
+ <para>
+ A line starting with the <command>#</command> character is considered a comment and is ignored.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Empty lines and lines that contain only whitespace are ignored
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ All tokens are case sensitive. <parameter>name1</parameter> is not the same as <parameter>Name1</parameter> and <parameter>create</parameter> is not the same as <parameter>CREATE</parameter>
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Group lists can be extended to the following line by terminating the line with the <command>\</command> character
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Additional whitespace - that is, where there is more than one whitespace character - between and after tokens is ignored. Group and ACL definitions must start with either <command>group</command> or <command>acl</command> and with no preceding whitespace.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ All ACL rules are limited to a single line
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Rules are interpreted from the top of the file down until the name match is obtained; at which point processing stops.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The keyword <parameter>all</parameter> matches all individuals, groups and actions
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The last line of the file - whether present or not - will be assumed to be <command>acl deny all all</command>. If present in the file, all lines below it are ignored.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Names and group names may contain only <parameter>a-z</parameter>, <parameter>A-Z</parameter>, <parameter>0-9</parameter>, <parameter>-</parameter> and <parameter>_</parameter>
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Rules must be preceded by any group definitions they can use. Any name not defined as a group will be assumed to be that of an individual.
+ </para>
+
+ </listitem>
+
+ </itemizedlist>
+
+ </para>
+
+ </section>
+
+ <section id="sect-Messaging_User_Guide-Authorization-Specifying_ACL_Permissions">
+ <title>Specifying ACL Permissions</title>
+ <para>
+ Now that we have seen the ACL syntax, we will provide representative examples and guidelines for ACL files.
+ </para>
+ <para>
+ Most ACL files begin by defining groups:
+ </para>
+
+<programlisting>
+group admin ted@QPID martin@QPID
+group user-consume martin@QPID ted@QPID
+group group2 kim@QPID user-consume rob@QPID
+group publisher group2 \
+tom@QPID andrew@QPID debbie@QPID
+</programlisting>
+ <para>
+ Rules in an ACL file grant or deny specific permissions to users or groups:
+ </para>
+
+<programlisting>
+acl allow carlt@QPID create exchange name=carl.*
+acl allow rob@QPID create queue
+acl allow guest@QPID bind exchange name=amq.topic routingkey=stocks.rht.#
+acl allow user-consume create queue name=tmp.*
+
+acl allow publisher publish all durable=false
+acl allow publisher create queue name=RequestQueue
+acl allow consumer consume queue durable=true
+acl allow fred@QPID create all
+acl allow bob@QPID all queue
+acl allow admin all
+acl allow all consume queue
+acl allow all bind exchange
+acl deny all all
+</programlisting>
+ <para>
+ In the previous example, the last line, <literal>acl deny all all</literal>, denies all authorizations that have not been specifically granted. This is the default, but it is useful to include it explicitly on the last line for the sake of clarity. If you want to grant all rights by default, you can specify <literal>acl allow all all</literal> in the last line.
+ </para>
+ <para>
+ Do not allow <parameter>guest</parameter> to access and log QMF management methods that could cause security breaches:
+ </para>
+
+<programlisting>
+group allUsers guest@QPID
+....
+acl deny-log allUsers create link
+acl deny-log allUsers access method name=connect
+acl deny-log allUsers access method name=echo
+acl allow all all
+</programlisting>
+
+ </section>
+
+
+ </section>
+
+ <!-- ########################### --> <section id="sect-Messaging_User_Guide-Security-Encryption_using_SSL">
+ <title>Encryption using SSL</title>
+ <para>
+ Encryption and certificate management for <command>qpidd</command> is provided by Mozilla&#39;s Network Security Services Library (NSS).
+ </para>
+ <orderedlist id="orde-Messaging_User_Guide-Encryption_using_SSL-Enabling_SSL_for_the_RHM_broker">
+ <title>Enabling SSL for the Qpid broker</title>
+ <listitem>
+ <para>
+ You will need a certificate that has been signed by a Certification Authority (CA). This certificate will also need to be trusted by your client. If you require client authentication in addition to server authentication, the client&#39;s certificate will also need to be signed by a CA and trusted by the broker.
+ </para>
+ <para>
+ In the broker, SSL is provided through the <command>ssl.so</command> module. This module is installed and loaded by default in Qpid. To enable the module, you need to specify the location of the database containing the certificate and key to use. This is done using the <command>ssl-cert-db</command> option.
+ </para>
+ <para>
+ The certificate database is created and managed by the Mozilla Network Security Services (NSS) <command>certutil</command> tool. Information on this utility can be found on the <ulink url="http://www.mozilla.org/projects/security/pki/nss/tools/certutil.html">Mozilla website</ulink>, including tutorials on setting up and testing SSL connections. The certificate database will generally be password protected. The safest way to specify the password is to place it in a protected file, use the password file when creating the database, and specify the password file with the <command>ssl-cert-password-file</command> option when starting the broker.
+ </para>
+ <para>
+ The following script shows how to create a certificate database using certutil:
+ </para>
+ <!-- TODO: improve description -->
+<programlisting>
+mkdir ${CERT_DIR}
+certutil -N -d ${CERT_DIR} -f ${CERT_PW_FILE}
+certutil -S -d ${CERT_DIR} -n ${NICKNAME} -s &#34;CN=${NICKNAME}&#34; -t &#34;CT,,&#34; -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+</programlisting>
+ <para>
+ When starting the broker, set <command>ssl-cert-password-file</command> to the value of <command>${CERT_PW_FILE}</command>, set <command>ssl-cert-db</command> to the value of <command>${CERT_DIR}</command>, and set <command>ssl-cert-name</command> to the value of <command>${NICKNAME}</command>.
+ </para>
+
+ </listitem>
+ <!-- SSL options --> <listitem>
+ <para>
+ The following SSL options can be used when starting the broker:
+ <variablelist>
+ <varlistentry>
+ <term><command>--ssl-use-export-policy</command></term>
+ <listitem>
+ <para>
+ Use NSS export policy
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-cert-password-file <replaceable>PATH</replaceable></command></term>
+ <listitem>
+ <para>
+ Required. Plain-text file containing password to use for accessing certificate database.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-cert-db <replaceable>PATH</replaceable></command></term>
+ <listitem>
+ <para>
+ Required. Path to directory containing certificate database.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-cert-name <replaceable>NAME</replaceable></command></term>
+ <listitem>
+ <para>
+ Name of the certificate to use. Default is <literal>localhost.localdomain</literal>.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-port <replaceable>NUMBER</replaceable></command></term>
+ <listitem>
+ <para>
+ Port on which to listen for SSL connections. If no port is specified, port 5671 is used.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-require-client-authentication</command></term>
+ <listitem>
+ <para>
+ Require SSL client authentication (i.e. verification of a client certificate) during the SSL handshake. This occurs before SASL authentication, and is independent of SASL.
+ </para>
+ <para>
+ This option enables the <literal>EXTERNAL</literal> SASL mechanism for SSL connections. If the client chooses the <literal>EXTERNAL</literal> mechanism, the client&#39;s identity is taken from the validated SSL certificate, using the <literal>CN</literal>literal&#62;, and appending any <literal>DC</literal>literal&#62;s to create the domain. For instance, if the certificate contains the properties <literal>CN=bob</literal>, <literal>DC=acme</literal>, <literal>DC=com</literal>, the client&#39;s identity is <literal>bob@acme.com</literal>.
+ </para>
+ <para>
+ If the client chooses a different SASL mechanism, the identity take from the client certificate will be replaced by that negotiated during the SASL handshake.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><command>--ssl-sasl-no-dict</command></term>
+ <listitem>
+ <para>
+ Do not accept SASL mechanisms that can be compromised by dictionary attacks. This prevents a weaker mechanism being selected instead of <literal>EXTERNAL</literal>, which is not vulnerable to dictionary attacks.
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+ Also relevant is the <command>--require-encryption</command> broker option. This will cause <command>qpidd</command> to only accept encrypted connections.
+ </para>
+
+ </listitem>
+
+ </orderedlist>
+ <!-- --> <variablelist id="vari-Messaging_User_Guide-Encryption_using_SSL-Enabling_SSL_in_Clients">
+ <title>Enabling SSL in Clients</title>
+ <varlistentry>
+ <term>C++ clients:</term>
+ <listitem>
+ <para>
+ <orderedlist>
+ <listitem>
+ <para>
+ In C++ clients, SSL is implemented in the <command>sslconnector.so</command> module. This module is installed and loaded by default in Qpid.
+ </para>
+ <para>
+ The following options can be specified for C++ clients using environment variables:
+ </para>
+ <table frame="all" id="tabl-Messaging_User_Guide-Enabling_SSL_in_Clients-SSL_Client_Environment_Variables_for_C_clients">
+ <title>SSL Client Environment Variables for C++ clients</title>
+ <tgroup align="left" cols="2" colsep="1" rowsep="1">
+ <colspec colname="c1"></colspec>
+ <colspec colname="c2"></colspec>
+ <thead>
+ <row>
+ <entry align="center" nameend="c2" namest="c1">
+ SSL Client Options for C++ clients
+ </entry>
+
+ </row>
+
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <command>QPID_SSL_USE_EXPORT_POLICY</command>
+ </entry>
+ <entry>
+ Use NSS export policy
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>QPID_SSL_CERT_PASSWORD_FILE <replaceable>PATH</replaceable></command>
+ </entry>
+ <entry>
+ File containing password to use for accessing certificate database
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>QPID_SSL_CERT_DB <replaceable>PATH</replaceable></command>
+ </entry>
+ <entry>
+ Path to directory containing certificate database
+ </entry>
+
+ </row>
+ <row>
+ <entry>
+ <command>QPID_SSL_CERT_NAME <replaceable>NAME</replaceable></command>
+ </entry>
+ <entry>
+ Name of the certificate to use. When SSL client authentication is enabled, a certificate name should normally be provided.
+ </entry>
+
+ </row>
+
+ </tbody>
+
+ </tgroup>
+
+ </table>
+ <!-- ######## -->
+ </listitem>
+ <listitem>
+ <para>
+ When using SSL connections, clients must specify the location of the certificate database, a directory that contains the client&#39;s certificate and the public key of the Certificate Authority. This can be done by setting the environment variable <command>QPID_SSL_CERT_DB</command> to the full pathname of the directory. If a connection uses SSL client authentication, the client&#39;s password is also needed&mdash;the password should be placed in a protected file, and the <command>QPID_SSL_CERT_PASSWORD_FILE</command> variable should be set to the location of the file containing this password.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ To open an SSL enabled connection in the Qpid Messaging API, set the <parameter>protocol</parameter> connection option to <parameter>ssl</parameter>.
+ </para>
+
+ </listitem>
+
+ </orderedlist>
+
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term>Java clients:</term>
+ <listitem>
+ <para>
+ <orderedlist>
+ <listitem>
+ <para>
+ For both server and client authentication, import the trusted CA to your trust store and keystore and generate keys for them. Create a certificate request using the generated keys and then create a certificate using the request. You can then import the signed certificate into your keystore. Pass the following arguments to the Java JVM when starting your client:
+<programlisting>
+-Djavax.net.ssl.keyStore=/home/bob/ssl_test/keystore.jks
+-Djavax.net.ssl.keyStorePassword=password
+-Djavax.net.ssl.trustStore=/home/bob/ssl_test/certstore.jks
+-Djavax.net.ssl.trustStorePassword=password
+</programlisting>
+
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ For server side authentication only, import the trusted CA to your trust store and pass the following arguments to the Java JVM when starting your client:
+<programlisting>
+-Djavax.net.ssl.trustStore=/home/bob/ssl_test/certstore.jks
+-Djavax.net.ssl.trustStorePassword=password
+</programlisting>
+
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Java clients must use the SSL option in the connection URL to enable SSL encryption, e.g.
+ </para>
+
+<programlisting>amqp://username:password@clientid/test?brokerlist=&#39;tcp://localhost:5672?ssl=&#39;true&#39;&#39;
+</programlisting>
+
+ </listitem>
+ <listitem>
+ <para>
+ If you need to debug problems in an SSL connection, enable Java&#39;s SSL debugging by passing the argument <literal>-Djavax.net.debug=ssl</literal> to the Java JVM when starting your client.
+ </para>
+
+ </listitem>
+
+ </orderedlist>
+
+ </para>
+
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
+ </section>
+
+
+</section>
+
diff --git a/qpid/doc/book/src/Starting-a-cluster.xml b/qpid/doc/book/src/Starting-a-cluster.xml
index d2852b4f69..036e571649 100644
--- a/qpid/doc/book/src/Starting-a-cluster.xml
+++ b/qpid/doc/book/src/Starting-a-cluster.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-
+
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
@@ -8,16 +8,16 @@
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-
+
-->
<section id="chap-Messaging_User_Guide-High_Availability_Messaging_Clusters">
@@ -32,7 +32,7 @@
An OpenAIS daemon runs on every machine in the cluster, and these daemons communicate using multicast on a particular address. Every qpidd process in a cluster joins a named group that is automatically synchronized using OpenAIS Closed Process Groups (CPG) — the qpidd processes multicast events to the named group, and CPG ensures that each qpidd process receives all the events in the same sequence. All members get an identical sequence of events, so they can all update their state consistently.
</para>
<para>
- Two messaging brokers are in the same cluster if
+ Two messaging brokers are in the same cluster if
<orderedlist>
<listitem>
<para>
@@ -62,13 +62,13 @@
<para>
Clustering is implemented using the <filename>cluster.so</filename> module, which is loaded by default when you start a broker. To run brokers in a cluster, make sure they all use the same OpenAIS mcastaddr, mcastport, and bindnetaddr. All brokers in a cluster must also have the same cluster name — specify the cluster name in <filename>qpidd.conf</filename>:
</para>
-
+
<screen>cluster-name=&#34;local_test_cluster&#34;
</screen>
<para>
On RHEL6, you must create the file <filename>/etc/corosync/uidgid.d/qpidd</filename> to tell Corosync the name of the user running the broker.By default, the user is qpidd:
</para>
-
+
<programlisting>
uidgid {
uid: qpidd
@@ -78,13 +78,13 @@ uidgid {
<para>
On RHEL5, the primary group for the process running qpidd must be the ais group. If you are running qpidd as a service, it is run as the <command>qpidd</command> user, which is already in the ais group. If you are running the broker from the command line, you must ensure that the primary group for the user running qpidd is ais. You can set the primary group using <command>newgrp</command>:
</para>
-
+
<screen>$ newgrp ais
</screen>
<para>
You can then run the broker from the command line, specifying the cluster name as an option.
</para>
-
+
<screen>[jonathan@localhost]$ qpidd --cluster-name=&#34;local_test_cluster&#34;
</screen>
<para>
@@ -117,9 +117,9 @@ uidgid {
<para>
The qpid log contains entries that record significant clustering events, e.g. when a broker becomes a member of a cluster, the membership of a cluster is changed, or an old journal is moved out of the way. For instance, the following message states that a broker has been added to a cluster as the first node:
</para>
-
+
<screen>
-2009-07-09 18:13:41 info 127.0.0.1:1410(READY) member update: 127.0.0.1:1410(member)
+2009-07-09 18:13:41 info 127.0.0.1:1410(READY) member update: 127.0.0.1:1410(member)
2009-07-09 18:13:41 notice 127.0.0.1:1410(READY) first in cluster
</screen>
<note>
@@ -134,8 +134,8 @@ uidgid {
<table frame="all" id="tabl-Messaging_User_Guide-Starting_a_Broker_in_a_Cluster-Options_for_High_Availability_Messaging_Cluster">
<title>Options for High Availability Messaging Cluster</title>
<tgroup align="left" cols="2" colsep="1" rowsep="1">
- <colspec colname="c1"></colspec>
- <colspec colname="c2"></colspec>
+ <colspec colname="c1" colwidth="1*"></colspec>
+ <colspec colname="c2" colwidth="4*"></colspec>
<thead>
<row>
<entry align="center" nameend="c2" namest="c1">
@@ -169,7 +169,7 @@ uidgid {
<command>--cluster-url <replaceable>URL</replaceable></command>
</entry>
<entry>
- An AMQP URL containing the local address that the broker advertizes to clients for fail-over connections. This is different for each host. By default, all local addresses for the broker are advertized. You only need to set this if
+ An AMQP URL containing the local address that the broker advertizes to clients for fail-over connections. This is different for each host. By default, all local addresses for the broker are advertized. You only need to set this if
<orderedlist>
<listitem>
<para>
@@ -185,7 +185,16 @@ uidgid {
</listitem>
</orderedlist>
- Each broker in the cluster is specified using the form: <command> url = [&#34;amqp:&#34;][ user [&#34;/&#34; password] &#34;@&#34; ] protocol_addr *(&#34;,&#34; protocol_addr) protocol_addr = tcp_addr / rmda_addr / ssl_addr / ... tcp_addr = [&#34;tcp:&#34;] host [&#34;:&#34; port] rdma_addr = &#34;rdma:&#34; host [&#34;:&#34; port] ssl_addr = &#34;ssl:&#34; host [&#34;:&#34; port]</command> In most cases, only one address is advertized, but more than one address can be specified in if the machine running the broker has more than one network interface card, and you want to allow clients to connect using multiple network interfaces. Use a comma delimiter (&#34;,&#34;) to separate brokers in the URL. Examples:
+ <para>Each broker in the cluster is specified using the following form:</para>
+
+<programlisting>url = [&#34;amqp:&#34;][ user [&#34;/&#34; password] &#34;@&#34; ] protocol_addr
+ (&#34;,&#34; protocol_addr)*
+protocol_addr = tcp_addr / rmda_addr / ssl_addr / ...
+tcp_addr = [&#34;tcp:&#34;] host [&#34;:&#34; port]
+rdma_addr = &#34;rdma:&#34; host [&#34;:&#34; port]
+ssl_addr = &#34;ssl:&#34; host [&#34;:&#34; port]</programlisting>
+
+ <para>In most cases, only one address is advertized, but more than one address can be specified in if the machine running the broker has more than one network interface card, and you want to allow clients to connect using multiple network interfaces. Use a comma delimiter (&#34;,&#34;) to separate brokers in the URL. Examples:</para>
<itemizedlist>
<listitem>
<para>
@@ -214,7 +223,7 @@ uidgid {
CMAN protects against the &#34;split-brain&#34; condition, in which a network failure splits the cluster into two sub-clusters that cannot communicate with each other. When &#34;split-brain&#34; occurs, each of the sub-clusters can access shared resources without knowledge of the other sub-cluster, resulting in corrupted cluster integrity.
</para>
<para>
- To avoid &#34;split-brain&#34;, CMAN uses the notion of a &#34;quorum&#34;. If more than half the cluster nodes are active, the cluster has quorum and can act. If half (or fewer) nodes are active, the cluster does not have quorum, and all cluster activity is stopped. There are other ways to define the quorum for particular use cases (e.g. a cluster of only 2 members), see the <ulink url="http://sources.redhat.com/cluster/wiki">CMAN Wiki</ulink>
+ To avoid &#34;split-brain&#34;, CMAN uses the notion of a &#34;quorum&#34;. If more than half the cluster nodes are active, the cluster has quorum and can act. If half (or fewer) nodes are active, the cluster does not have quorum, and all cluster activity is stopped. There are other ways to define the quorum for particular use cases (e.g. a cluster of only 2 members), see the <ulink url="http://sources.redhat.com/cluster/wiki">CMAN Wiki</ulink>
for more detail.
</para>
<para>
@@ -260,7 +269,7 @@ for more detail.
<para>
If a broker is unable to establish a connection to another broker in the cluster, the log will contain SASL errors, e.g:
</para>
-
+
<screen>2009-aug-04 10:17:37 info SASL: Authentication failed: SASL(-13): user not found: Password verification failed
</screen>
<para>
@@ -274,16 +283,16 @@ for more detail.
</para>
</section>
-
+
<section id="sect-Messaging_User_Guide-High_Availability_Messaging_Clusters-qpid_cluster">
<title>qpid-cluster</title>
<para>
<command>qpid-cluster</command> is a command-line utility that allows you to view information on a cluster and its brokers, disconnect a client connection, shut down a broker in a cluster, or shut down the entire cluster. You can see the options using the <command>--help</command> option:
</para>
-
+
<screen>$ ./qpid-cluster --help
</screen>
-
+
<screen>Usage: qpid-cluster [OPTIONS] [broker-addr]
broker-addr is in the form: [username/password@] hostname | ip-address [:&#60;port&#62;]
@@ -302,14 +311,14 @@ Options:
<para>
Let&#39;s connect to a cluster and display basic information about the cluser and its brokers. When you connect to the cluster using <command>qpid-tool</command>, you can use the host and port for any broker in the cluster. For instance, if a broker in the cluster is running on <filename>localhost</filename> on port 6664, you can start <command>qpid-tool</command> like this:
</para>
-
+
<screen>
$ qpid-cluster localhost:6664
</screen>
<para>
Here is the output:
</para>
-
+
<screen>
Cluster Name: local_test_cluster
Cluster Status: ACTIVE
@@ -321,12 +330,12 @@ Cluster Status: ACTIVE
<para>
The ID for each broker in cluster is given on the left. For instance, the ID for the first broker in the cluster is <command>127.0.0.1:13143</command>. The URL in the output is the broker&#39;s advertized address. Let&#39;s use the ID to shut the broker down using the <command>--stop</command> command:
</para>
-
+
<screen>$ ./qpid-cluster localhost:6664 --stop 127.0.0.1:13143
</screen>
</section>
-
+
<section id="sect-Messaging_User_Guide-High_Availability_Messaging_Clusters-Failover_in_Clients">
<title>Failover in Clients</title>
<para>
@@ -349,7 +358,7 @@ Cluster Status: ACTIVE
<para>
You can configure a connection to use failover using the <command>failover</command> property:
</para>
-
+
<screen>
connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?brokerlist=&#39;tcp://localhost:5672&#39;&amp;failover=&#39;failover_exchange&#39;
</screen>
@@ -393,13 +402,13 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
<para>
In a Connection URL, heartbeat is set using the <command>idle_timeout</command> property, which is an integer corresponding to the heartbeat period in seconds. For instance, the following line from a JNDI properties file sets the heartbeat time out to 3 seconds:
</para>
-
+
<screen>
connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?brokerlist=&#39;tcp://localhost:5672&#39;,idle_timeout=3
</screen>
</section>
-
+
<section id="sect-Messaging_User_Guide-Failover_in_Clients-Failover_and_the_Qpid_Messaging_API">
<title>Failover and the Qpid Messaging API</title>
<para>
@@ -413,10 +422,10 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
</section>
-
+
</section>
-
+
<section id="sect-Messaging_User_Guide-High_Availability_Messaging_Clusters-Error_handling_in_Clusters">
<title>Error handling in Clusters</title>
<para>
@@ -439,7 +448,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
<!-- "Bad case" for cluster matrix - things we will fix, or things users may encounter long term? -->
</section>
-
+
<section id="sect-Messaging_User_Guide-High_Availability_Messaging_Clusters-Persistence_in_High_Availability_Message_Clusters">
<title>Persistence in High Availability Message Clusters</title>
<para>
@@ -461,7 +470,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
</section>
-
+
<section id="sect-Messaging_User_Guide-Persistence_in_High_Availability_Message_Clusters-Starting_a_persistent_cluster">
<title>Starting a persistent cluster</title>
<para>
@@ -493,7 +502,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
</section>
-
+
<section id="sect-Messaging_User_Guide-Persistence_in_High_Availability_Message_Clusters-Stopping_a_persistent_cluster">
<title>Stopping a persistent cluster</title>
<para>
@@ -501,7 +510,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
</section>
-
+
<section id="sect-Messaging_User_Guide-Persistence_in_High_Availability_Message_Clusters-Starting_a_persistent_cluster_with_no_clean_store">
<title>Starting a persistent cluster with no clean store</title>
<para>
@@ -512,7 +521,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
<para>
Move the latest store backup into place in the brokers data-directory. The backups end in a 4 digit number, the latest backup is the highest number.
</para>
-
+
<screen>
cd &#60;data-dir&#62;
mv rhm rhm.bak
@@ -522,7 +531,7 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</step>
<step>
<para>
- Mark the store as clean:
+ Mark the store as clean:
<screen>qpid-cluster-store -c &#60;data-dir&#62;</screen>
</para>
@@ -530,13 +539,13 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</step>
</procedure>
-
+
<para>
Now you can start the cluster, all members will be initialized from the store you marked as clean.
</para>
</section>
-
+
<section id="sect-Messaging_User_Guide-Persistence_in_High_Availability_Message_Clusters-Isolated_failures_in_a_persistent_cluster">
<title>Isolated failures in a persistent cluster</title>
<para>
@@ -544,9 +553,9 @@ connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?broke
</para>
</section>
-
+
</section>
-
+
</section>
diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml
index d9677c9cf6..14b9456067 100644
--- a/qpid/java/broker/etc/config.xml
+++ b/qpid/java/broker/etc/config.xml
@@ -62,8 +62,6 @@
</management>
<advanced>
<filterchain enableExecutorPool="true"/>
- <enablePooledAllocator>false</enablePooledAllocator>
- <enableDirectBuffers>false</enableDirectBuffers>
<framesize>65535</framesize>
<compressBufferOnQueue>false</compressBufferOnQueue>
<enableJMSXUserID>false</enableJMSXUserID>
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 3e31115dcb..4f86c82578 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -281,7 +281,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
routeCurrentMessage();
- _transaction.addPostCommitAction(new ServerTransaction.Action()
+ _transaction.addPostTransactionAction(new ServerTransaction.Action()
{
public void postCommit()
@@ -313,7 +313,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
if(!checkMessageUserId(_currentMessage.getContentHeader()))
{
- _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage));
+ _transaction.addPostTransactionAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage));
}
else
{
@@ -321,7 +321,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
if (_currentMessage.isMandatory() || _currentMessage.isImmediate())
{
- _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage));
+ _transaction.addPostTransactionAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage));
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index a0f5f9fa4c..7197ec8cdc 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -108,6 +108,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount");
envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth");
envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize");
+ envVarMap.put("QPID_MAXIMUMCHANNELCOUNT", "maximumChannelCount");
envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap");
envVarMap.put("QPID_QUEUECAPACITY", "capacity");
envVarMap.put("QPID_FLOWRESUMECAPACITY", "flowResumeCapacity");
@@ -212,7 +213,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
* both, as a fix for QPID-2360 and QPID-2361.
*/
@SuppressWarnings("unchecked")
- private void setupVirtualHosts(Configuration conf) throws ConfigurationException
+ protected void setupVirtualHosts(Configuration conf) throws ConfigurationException
{
List<String> vhostFiles = conf.getList("virtualhosts");
Configuration vhostConfig = conf.subset("virtualhosts");
@@ -704,16 +705,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
return getBooleanValue("advanced.filterchain[@enableExecutorPool]");
}
- public boolean getEnablePooledAllocator()
- {
- return getBooleanValue("advanced.enablePooledAllocator");
- }
-
- public boolean getEnableDirectBuffers()
- {
- return getBooleanValue("advanced.enableDirectBuffers");
- }
-
public boolean getEnableSSL()
{
return getBooleanValue("connector.ssl.enabled");
@@ -828,4 +819,9 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
}
};
}
+
+ public int getMaxChannelCount()
+ {
+ return getIntValue("maximumChannelCount", 256);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
index cda8cff25a..d4b79134a2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
@@ -92,7 +92,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener
stateManager.changeState(AMQState.CONNECTION_NOT_TUNED);
ConnectionTuneBody tuneBody =
- methodRegistry.createConnectionTuneBody(0xFFFF,
+ methodRegistry.createConnectionTuneBody(ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount(),
ConnectionStartOkMethodHandler.getConfiguredFrameSize(),
ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay());
session.writeFrame(tuneBody.generateFrame(0));
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
index 6512ff1a14..4442f969c4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
@@ -113,7 +113,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
stateManager.changeState(AMQState.CONNECTION_NOT_TUNED);
- ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF,
+ ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount(),
getConfiguredFrameSize(),
ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay());
session.writeFrame(tuneBody.generateFrame(0));
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
index 9f392ffc44..1da2760639 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
@@ -23,7 +23,6 @@ package org.apache.qpid.server.handler;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.ConnectionTuneOkBody;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
@@ -51,5 +50,9 @@ public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener<C
stateManager.changeState(AMQState.CONNECTION_NOT_OPENED);
session.initHeartbeats(body.getHeartbeat());
session.setMaxFrameSize(body.getFrameMax());
+
+ long maxChannelNumber = body.getChannelMax();
+ //0 means no implied limit, except that forced by protocol limitations (0xFFFF)
+ session.setMaximumNumberOfChannels( maxChannelNumber == 0 ? 0xFFFFL : maxChannelNumber);
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index 5368dfe532..a1ffe272fd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -136,7 +136,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
protected volatile boolean _closed;
// maximum number of channels this session should have
- private long _maxNoOfChannels = 1000;
+ private long _maxNoOfChannels = ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
/* AMQP Version for this session */
private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
index 1fe4ec792e..30d506a89b 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
@@ -58,8 +58,8 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine
_appRegistry = appRegistry;
// FIXME Two log messages to maintain compatinbility with earlier protocol versions
- CurrentActor.get().message(ConnectionMessages.OPEN(null, null, false, false));
- CurrentActor.get().message(ConnectionMessages.OPEN(null, "0-10", false, true));
+ _connection.getLogActor().message(ConnectionMessages.OPEN(null, null, false, false));
+ _connection.getLogActor().message(ConnectionMessages.OPEN(null, "0-10", false, true));
}
public void setNetworkDriver(NetworkDriver driver)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index ec6fb1f8de..b003152db6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -54,7 +54,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
import javax.management.JMException;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
@@ -742,12 +741,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private void deliverMessage(final Subscription sub, final QueueEntry entry)
throws AMQException
{
+ setLastSeenEntry(sub, entry);
+
_deliveredMessages.incrementAndGet();
incrementUnackedMsgCount();
sub.send(entry);
-
- setLastSeenEntry(sub,entry);
}
private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) throws AMQException
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
index b1172a880e..ff2a8c959b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
@@ -41,7 +41,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
public void close()
{
//Set the Actor for Broker Shutdown
- CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger));
+ CurrentActor.set(new BrokerActor(_rootMessageLogger));
try
{
super.close();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
index 0e19b17a50..b36ac84cdd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -36,6 +36,7 @@ import org.apache.qpid.server.flow.WindowCreditManager;
import org.apache.qpid.server.flow.FlowCreditManager_0_10;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.GenericActor;
import org.apache.qpid.server.logging.messages.SubscriptionMessages;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
@@ -179,12 +180,13 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
_trace = (String) arguments.get("qpid.trace.id");
_id = getConfigStore().createId();
getConfigStore().addConfiguredObject(this);
- String filterLogString = null;
- LogActor _logActor = CurrentActor.get();
- if (_logActor.getRootMessageLogger().isMessageEnabled(_logActor, this, SubscriptionMessages.CREATE_LOG_HIERARCHY))
+ String filterLogString = null;
+
+ _logActor = GenericActor.getInstance(this);
+ if (CurrentActor.get().getRootMessageLogger().isMessageEnabled(_logActor, this, SubscriptionMessages.CREATE_LOG_HIERARCHY))
{
filterLogString = getFilterLogString();
- _logActor.message(SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive,
+ CurrentActor.get().message(this, SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive,
filterLogString.length() > 0));
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
index a1a7bd119b..d2addfde0c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -23,10 +23,12 @@ package org.apache.qpid.server.transport;
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.*;
import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.configuration.ConnectionConfig;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
@@ -38,15 +40,18 @@ import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.ExecutionErrorCode;
import org.apache.qpid.transport.ExecutionException;
import org.apache.qpid.transport.Method;
+import org.apache.qpid.transport.ProtocolEvent;
public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject
{
private ConnectionConfig _config;
private Runnable _onOpenTask;
+ private AtomicBoolean _logClosed = new AtomicBoolean(false);
+ private LogActor _actor = GenericActor.getInstance(this);
public ServerConnection()
{
- CurrentActor.set(GenericActor.getInstance(this));
+
}
@Override
@@ -66,11 +71,19 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
{
_onOpenTask.run();
}
- CurrentActor.get().message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true));
+ _actor.message(ConnectionMessages.OPEN(getClientId(), "0-10", true, true));
}
if (state == State.CLOSED)
{
+ logClosed();
+ }
+ }
+
+ protected void logClosed()
+ {
+ if(_logClosed.compareAndSet(false, true))
+ {
CurrentActor.get().message(this, ConnectionMessages.CLOSE());
}
}
@@ -133,13 +146,44 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
((ServerSession)session).close();
}
- public String toLogString() {
+ @Override
+ public void received(ProtocolEvent event)
+ {
+ if (event.isConnectionControl())
+ {
+ CurrentActor.set(_actor);
+ }
+ else
+ {
+ ServerSession channel = (ServerSession) getSession(event.getChannel());
+ LogActor channelActor = null;
+
+ if (channel != null)
+ {
+ channelActor = channel.getLogActor();
+ }
+
+ CurrentActor.set(channelActor == null ? _actor : channelActor);
+ }
+
+ try
+ {
+ super.received(event);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+
+ public String toLogString()
+ {
boolean hasVirtualHost = (null != this.getVirtualHost());
boolean hasPrincipal = (null != getAuthorizationID());
if (hasPrincipal && hasVirtualHost)
{
- return " [" +
+ return "[" +
MessageFormat.format(CONNECTION_FORMAT,
getConnectionId(),
getClientId(),
@@ -149,7 +193,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
}
else if (hasPrincipal)
{
- return " [" +
+ return "[" +
MessageFormat.format(USER_FORMAT,
getConnectionId(),
getClientId(),
@@ -159,7 +203,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
}
else
{
- return " [" +
+ return "[" +
MessageFormat.format(SOCKET_FORMAT,
getConnectionId(),
getConfig().getAddress())
@@ -167,4 +211,8 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
}
}
+ public LogActor getLogActor()
+ {
+ return _actor;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index 4a304b3e66..2b9e92f685 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -26,6 +26,7 @@ import org.apache.qpid.server.logging.actors.GenericActor;
import org.apache.qpid.common.ClientProperties;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -84,7 +85,22 @@ public class ServerConnectionDelegate extends ServerDelegate
}
- @Override public void connectionOpen(Connection conn, ConnectionOpen open)
+ @Override
+ public void connectionClose(Connection conn, ConnectionClose close)
+ {
+ try
+ {
+ ((ServerConnection) conn).logClosed();
+ }
+ finally
+ {
+ super.connectionClose(conn, close);
+ }
+
+ }
+
+ @Override
+ public void connectionOpen(Connection conn, ConnectionOpen open)
{
ServerConnection sconn = (ServerConnection) conn;
@@ -114,7 +130,6 @@ public class ServerConnectionDelegate extends ServerDelegate
else
{
sconn.invoke(new ConnectionOpenOk(Collections.emptyList()));
- CurrentActor.set(GenericActor.getInstance(sconn));
sconn.setState(Connection.State.OPEN);
}
}
@@ -131,4 +146,10 @@ public class ServerConnectionDelegate extends ServerDelegate
//TODO: implement broker support for actually sending heartbeats
return 0;
}
+
+ @Override
+ protected int getChannelMax()
+ {
+ return ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index c53f65f302..540ad3fffd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -32,6 +32,7 @@ import org.apache.qpid.server.configuration.ConfiguredObject;
import org.apache.qpid.server.configuration.ConnectionConfig;
import org.apache.qpid.server.configuration.SessionConfig;
import org.apache.qpid.server.configuration.SessionConfigType;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
@@ -57,7 +58,6 @@ import org.apache.qpid.transport.Range;
import org.apache.qpid.transport.RangeSet;
import org.apache.qpid.transport.Session;
import org.apache.qpid.transport.SessionDelegate;
-import org.apache.qpid.transport.Session.State;
import java.lang.ref.WeakReference;
import java.security.Principal;
@@ -81,6 +81,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
private final UUID _id;
private ConnectionConfig _connectionConfig;
private long _createTime = System.currentTimeMillis();
+ private LogActor _actor = GenericActor.getInstance(this);
public static interface MessageDispositionChangeListener
{
@@ -130,7 +131,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
if (state == State.OPEN)
{
- GenericActor.getInstance(this).message(ChannelMessages.CREATE());
+ _actor.message(ChannelMessages.CREATE());
}
}
@@ -595,6 +596,11 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
return getConnection().getClientId();
}
+ public LogActor getLogActor()
+ {
+ return _actor;
+ }
+
public LogSubject getLogSubject()
{
return (LogSubject) this;
@@ -603,7 +609,7 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
@Override
public String toLogString()
{
- return " [" +
+ return "[" +
MessageFormat.format(CHANNEL_FORMAT,
getConnection().getConnectionId(),
getClientID(),
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index 7715f70f0d..42a3975e24 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -253,8 +253,6 @@ public class ServerSessionDelegate extends SessionDelegate
filterManager,
method.getArguments());
- CurrentActor.set(GenericActor.getInstance(sub));
-
((ServerSession)session).register(destination, sub);
try
{
@@ -1225,7 +1223,6 @@ public class ServerSessionDelegate extends SessionDelegate
@Override
public void closed(Session session)
{
- super.closed(session);
for(Subscription_0_10 sub : getSubscriptions(session))
{
((ServerSession)session).unregister(sub);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
index f674741057..db781ead96 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
@@ -20,19 +20,28 @@
*/
package org.apache.qpid.server.txn;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.BaseQueue;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQStoreException;
import org.apache.qpid.server.message.EnqueableMessage;
import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.store.TransactionLog;
-import org.apache.qpid.AMQException;
-
-import java.util.List;
-import java.util.Collection;
+/**
+ * An implementation of ServerTransaction where each enqueue/dequeue
+ * operation takes place within it own transaction.
+ *
+ * Since there is no long-lived transaction, the commit and rollback methods of
+ * this implementation are empty.
+ */
public class AutoCommitTransaction implements ServerTransaction
{
+ protected static final Logger _logger = Logger.getLogger(AutoCommitTransaction.class);
private final TransactionLog _transactionLog;
@@ -41,52 +50,69 @@ public class AutoCommitTransaction implements ServerTransaction
_transactionLog = transactionLog;
}
-
- public void addPostCommitAction(Action postCommitAction)
+ /**
+ * Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered
+ * by the caller are executed immediately.
+ */
+ public void addPostTransactionAction(Action immediateAction)
{
- postCommitAction.postCommit();
+ immediateAction.postCommit();
}
- public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction)
+ public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
{
-
+ TransactionLog.Transaction txn = null;
try
{
if(message.isPersistent() && queue.isDurable())
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString());
+ }
- TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ txn = _transactionLog.newTransaction();
txn.dequeueMessage(queue, message.getMessageNumber());
- // store.remove enqueue
- // store.commit
txn.commitTran();
+ txn = null;
}
- postCommitAction.postCommit();
+ postTransactionAction.postCommit();
+ postTransactionAction = null;
}
catch (AMQException e)
{
- //TODO
- postCommitAction.onRollback();
- throw new RuntimeException(e);
+ _logger.error("Error during message dequeue", e);
+ throw new RuntimeException("Error during message dequeue", e);
+ }
+ finally
+ {
+ rollbackIfNecessary(postTransactionAction, txn);
}
+
}
- public void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction)
+ public void dequeue(Collection<QueueEntry> queueEntries, Action postTransactionAction)
{
+ TransactionLog.Transaction txn = null;
try
{
- TransactionLog.Transaction txn = null;
- for(QueueEntry entry : ackedMessages)
+ for(QueueEntry entry : queueEntries)
{
ServerMessage message = entry.getMessage();
- AMQQueue queue = entry.getQueue();
+ BaseQueue queue = entry.getQueue();
if(message.isPersistent() && queue.isDurable())
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString());
+ }
+
if(txn == null)
{
txn = _transactionLog.newTransaction();
}
+
txn.dequeueMessage(queue, message.getMessageNumber());
}
@@ -94,78 +120,134 @@ public class AutoCommitTransaction implements ServerTransaction
if(txn != null)
{
txn.commitTran();
+ txn = null;
}
- postCommitAction.postCommit();
+ postTransactionAction.postCommit();
+ postTransactionAction = null;
}
catch (AMQException e)
{
- //TODO
- postCommitAction.onRollback();
- throw new RuntimeException(e);
+ _logger.error("Error during message dequeues", e);
+ throw new RuntimeException("Error during message dequeues", e);
+ }
+ finally
+ {
+ rollbackIfNecessary(postTransactionAction, txn);
}
+
}
- public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction)
+ public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
{
+ TransactionLog.Transaction txn = null;
try
{
if(message.isPersistent() && queue.isDurable())
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString());
+ }
- TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ txn = _transactionLog.newTransaction();
txn.enqueueMessage(queue, message.getMessageNumber());
txn.commitTran();
+ txn = null;
}
- postCommitAction.postCommit();
+ postTransactionAction.postCommit();
+ postTransactionAction = null;
}
catch (AMQException e)
{
- //TODO
- e.printStackTrace();
- postCommitAction.onRollback();
- throw new RuntimeException(e);
+ _logger.error("Error during message enqueue", e);
+ throw new RuntimeException("Error during message enqueue", e);
}
+ finally
+ {
+ rollbackIfNecessary(postTransactionAction, txn);
+ }
+
}
- public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction)
+ public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction)
{
+ TransactionLog.Transaction txn = null;
try
{
if(message.isPersistent())
{
- TransactionLog.Transaction txn = _transactionLog.newTransaction();
Long id = message.getMessageNumber();
- for(BaseQueue q : queues)
+ for(BaseQueue queue : queues)
{
- if(q.isDurable())
+ if (queue.isDurable())
{
- txn.enqueueMessage(q, id);
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString());
+ }
+ if (txn == null)
+ {
+ txn = _transactionLog.newTransaction();
+ }
+
+ txn.enqueueMessage(queue, id);
}
}
- txn.commitTran();
+
+ if (txn != null)
+ {
+ txn.commitTran();
+ txn = null;
+ }
}
- postCommitAction.postCommit();
+ postTransactionAction.postCommit();
+ postTransactionAction = null;
}
catch (AMQException e)
{
- //TODO
- postCommitAction.onRollback();
- throw new RuntimeException(e);
+ _logger.error("Error during message enqueues", e);
+ throw new RuntimeException("Error during message enqueues", e);
+ }
+ finally
+ {
+ rollbackIfNecessary(postTransactionAction, txn);
}
}
+
public void commit()
{
-
}
public void rollback()
{
+ }
+ private void rollbackIfNecessary(Action postTransactionAction, TransactionLog.Transaction txn)
+ {
+ if (txn != null)
+ {
+ try
+ {
+ txn.abortTran();
+ }
+ catch (AMQStoreException e)
+ {
+ _logger.error("Abort transaction failed", e);
+ // Deliberate decision not to re-throw this exception. Rationale: we can only reach here if a previous
+ // TransactionLog method has ended in Exception. If we were to re-throw here, we would prevent
+ // our caller from receiving the original exception (which is likely to be more revealing of the underlying error).
+ }
+ }
+ if (postTransactionAction != null)
+ {
+ postTransactionAction.onRollback();
+ }
}
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
index 7c9276dbdc..a04c743be1 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
@@ -21,21 +21,29 @@ package org.apache.qpid.server.txn;
*/
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.BaseQueue;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.EnqueableMessage;
import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.store.TransactionLog;
-import org.apache.qpid.AMQException;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collection;
+/**
+ * A concrete implementation of ServerTransaction where enqueue/dequeue
+ * operations share a single long-lived transaction.
+ *
+ * The caller is responsible for invoking commit() (or rollback()) as necessary.
+ */
public class LocalTransaction implements ServerTransaction
{
- private final List<Action> _postCommitActions = new ArrayList<Action>();
+ protected static final Logger _logger = Logger.getLogger(LocalTransaction.class);
+
+ private final List<Action> _postTransactionActions = new ArrayList<Action>();
private volatile TransactionLog.Transaction _transaction;
private TransactionLog _transactionLog;
@@ -45,17 +53,23 @@ public class LocalTransaction implements ServerTransaction
_transactionLog = transactionLog;
}
- public void addPostCommitAction(Action postCommitAction)
+ public void addPostTransactionAction(Action postTransactionAction)
{
- _postCommitActions.add(postCommitAction);
+ _postTransactionActions.add(postTransactionAction);
}
- public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction)
+ public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
{
+ _postTransactionActions.add(postTransactionAction);
+
if(message.isPersistent() && queue.isDurable())
{
try
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString());
+ }
beginTranIfNecessary();
_transaction.dequeueMessage(queue, message.getMessageNumber());
@@ -63,23 +77,31 @@ public class LocalTransaction implements ServerTransaction
}
catch(AMQException e)
{
+ _logger.error("Error during message dequeues", e);
tidyUpOnError(e);
}
}
- _postCommitActions.add(postCommitAction);
}
- public void dequeue(Collection<QueueEntry> queueEntries, Action postCommitAction)
+ public void dequeue(Collection<QueueEntry> queueEntries, Action postTransactionAction)
{
+ _postTransactionActions.add(postTransactionAction);
+
try
{
for(QueueEntry entry : queueEntries)
{
ServerMessage message = entry.getMessage();
- AMQQueue queue = entry.getQueue();
+ BaseQueue queue = entry.getQueue();
+
if(message.isPersistent() && queue.isDurable())
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString());
+ }
+
beginTranIfNecessary();
_transaction.dequeueMessage(queue, message.getMessageNumber());
}
@@ -88,9 +110,9 @@ public class LocalTransaction implements ServerTransaction
}
catch(AMQException e)
{
+ _logger.error("Error during message dequeues", e);
tidyUpOnError(e);
}
- _postCommitActions.add(postCommitAction);
}
@@ -98,7 +120,7 @@ public class LocalTransaction implements ServerTransaction
{
try
{
- for(Action action : _postCommitActions)
+ for(Action action : _postTransactionActions)
{
action.onRollback();
}
@@ -107,14 +129,20 @@ public class LocalTransaction implements ServerTransaction
{
try
{
- _transaction.abortTran();
+ if (_transaction != null)
+ {
+ _transaction.abortTran();
+ }
}
- catch (Exception e1)
+ catch (Exception abortException)
{
- // TODO could try to chain the information to the original error
+ _logger.error("Abort transaction failed while trying to handle previous error", abortException);
+ }
+ finally
+ {
+ _transaction = null;
+ _postTransactionActions.clear();
}
- _transaction = null;
- _postCommitActions.clear();
}
throw new RuntimeException(e);
@@ -122,6 +150,7 @@ public class LocalTransaction implements ServerTransaction
private void beginTranIfNecessary()
{
+
if(_transaction == null)
{
try
@@ -135,52 +164,50 @@ public class LocalTransaction implements ServerTransaction
}
}
- public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction)
+ public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
{
+ _postTransactionActions.add(postTransactionAction);
+
if(message.isPersistent() && queue.isDurable())
{
- beginTranIfNecessary();
try
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString());
+ }
+
+ beginTranIfNecessary();
_transaction.enqueueMessage(queue, message.getMessageNumber());
}
catch (Exception e)
{
+ _logger.error("Error during message enqueue", e);
+
tidyUpOnError(e);
}
}
- _postCommitActions.add(postCommitAction);
-
-
}
- public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction)
+ public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction)
{
-
+ _postTransactionActions.add(postTransactionAction);
if(message.isPersistent())
{
- if(_transaction == null)
- {
- for(BaseQueue queue : queues)
- {
- if(queue.isDurable())
- {
- beginTranIfNecessary();
- break;
- }
- }
-
-
- }
-
-
try
{
for(BaseQueue queue : queues)
{
if(queue.isDurable())
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString() );
+ }
+
+
+ beginTranIfNecessary();
_transaction.enqueueMessage(queue, message.getMessageNumber());
}
}
@@ -188,12 +215,11 @@ public class LocalTransaction implements ServerTransaction
}
catch (Exception e)
{
+ _logger.error("Error during message enqueue", e);
+
tidyUpOnError(e);
}
}
- _postCommitActions.add(postCommitAction);
-
-
}
public void commit()
@@ -202,55 +228,52 @@ public class LocalTransaction implements ServerTransaction
{
if(_transaction != null)
{
-
_transaction.commitTran();
}
- for(Action action : _postCommitActions)
+ for(Action action : _postTransactionActions)
{
action.postCommit();
}
}
catch (Exception e)
{
- for(Action action : _postCommitActions)
+ _logger.error("Failed to commit transaction", e);
+
+ for(Action action : _postTransactionActions)
{
action.onRollback();
}
- //TODO
- throw new RuntimeException(e);
+ throw new RuntimeException("Failed to commit transaction", e);
}
finally
{
_transaction = null;
- _postCommitActions.clear();
+ _postTransactionActions.clear();
}
}
public void rollback()
{
-
try
{
if(_transaction != null)
{
-
_transaction.abortTran();
}
}
catch (AMQException e)
{
- //TODO
- e.printStackTrace();
- throw new RuntimeException(e);
+ _logger.error("Failed to rollback transaction", e);
+ throw new RuntimeException("Failed to rollback transaction", e);
}
finally
{
try
{
- for(Action action : _postCommitActions)
+ for(Action action : _postTransactionActions)
{
action.onRollback();
}
@@ -258,7 +281,7 @@ public class LocalTransaction implements ServerTransaction
finally
{
_transaction = null;
- _postCommitActions.clear();
+ _postTransactionActions.clear();
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
index f3ef6569f3..b61b8a5c64 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
@@ -27,14 +27,24 @@ import org.apache.qpid.server.queue.QueueEntry;
import java.util.Collection;
import java.util.List;
+
+/**
+ * The ServerTransaction interface allows a set enqueue/dequeue operations to be
+ * performed against the transaction belonging the underlying TransactionLog object.
+ *
+ * Typically all ServerTransaction implementations decide if a message should be enlisted
+ * into a store transaction by examining the durable property of the queue, and the persistence
+ * property of the message.
+ *
+ * A caller may register a list of post transaction Actions to be
+ * performed on commit() (or rollback()).
+ *
+ */
public interface ServerTransaction
{
-
- void addPostCommitAction(Action postCommitAction);
-
-
-
-
+ /**
+ * Represents an action to be performed on transaction commit or rollback
+ */
public static interface Action
{
public void postCommit();
@@ -42,16 +52,52 @@ public interface ServerTransaction
public void onRollback();
}
- void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction);
-
- void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction);
-
- void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction);
-
- void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction);
-
-
+ /**
+ * Register an Action for execution after transaction commit or rollback. Actions
+ * will be executed in the order in which they are registered.
+ */
+ void addPostTransactionAction(Action postTransactionAction);
+
+ /**
+ * Dequeue a message from a queue registering a post transaction action.
+ *
+ * A store operation will result only for a persistent message on a durable queue.
+ */
+ void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction);
+
+ /**
+ * Dequeue a message(s) from queue(s) registering a post transaction action.
+ *
+ * Store operations will result only for a persistent messages on durable queues.
+ */
+ void dequeue(Collection<QueueEntry> messages, Action postTransactionAction);
+
+ /**
+ * Enqueue a message to a queue registering a post transaction action.
+ *
+ * A store operation will result only for a persistent message on a durable queue.
+ */
+ void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction);
+
+ /**
+ * Enqueue a message(s) to queue(s) registering a post transaction action.
+ *
+ * Store operations will result only for a persistent messages on durable queues.
+ */
+ void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction);
+
+ /**
+ * Commit the transaction represented by this object.
+ *
+ * If the caller has registered one or more Actions, the postCommit() method on each will
+ * be executed immediately after the underlying transaction has committed.
+ */
void commit();
+ /** Rollback the transaction represented by this object.
+ *
+ * If the caller has registered one or more Actions, the onRollback() method on each will
+ * be executed immediately after the underlying transaction has rolled-back.
+ */
void rollback();
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
index ddebe28d03..718874cf69 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -630,34 +630,6 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase
assertEquals(true, serverConfig.getEnableExecutorPool());
}
- public void testGetEnablePooledAllocator() throws ConfigurationException
- {
- // Check default
- ServerConfiguration serverConfig = new ServerConfiguration(_config);
- serverConfig.initialise();
- assertEquals(false, serverConfig.getEnablePooledAllocator());
-
- // Check value we set
- _config.setProperty("advanced.enablePooledAllocator", true);
- serverConfig = new ServerConfiguration(_config);
- serverConfig.initialise();
- assertEquals(true, serverConfig.getEnablePooledAllocator());
- }
-
- public void testGetEnableDirectBuffers() throws ConfigurationException
- {
- // Check default
- ServerConfiguration serverConfig = new ServerConfiguration(_config);
- serverConfig.initialise();
- assertEquals(false, serverConfig.getEnableDirectBuffers());
-
- // Check value we set
- _config.setProperty("advanced.enableDirectBuffers", true);
- serverConfig = new ServerConfiguration(_config);
- serverConfig.initialise();
- assertEquals(true, serverConfig.getEnableDirectBuffers());
- }
-
public void testGetEnableSSL() throws ConfigurationException
{
// Check default
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
index 8b894c9629..5bdbe2c68e 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
@@ -24,6 +24,7 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.message.AMQMessageHeader;
import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
public class MockQueueEntry implements QueueEntry
{
@@ -100,7 +101,7 @@ public class MockQueueEntry implements QueueEntry
return false;
}
- public AMQMessage getMessage()
+ public ServerMessage getMessage()
{
return _message;
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java
new file mode 100644
index 0000000000..b67723dd25
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryTest.java
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+/**
+ *
+ * Tests QueueEntry
+ *
+ */
+public class QueueEntryTest extends QpidTestCase
+{
+ private QueueEntryImpl _queueEntry1 = null;
+ private QueueEntryImpl _queueEntry2 = null;
+ private QueueEntryImpl _queueEntry3 = null;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ int i = 0;
+
+ SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(null);
+ _queueEntry1 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
+ _queueEntry2 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
+ _queueEntry3 = (QueueEntryImpl) queueEntryList.add(new MockAMQMessage(i++));
+ }
+
+ public void testCompareTo()
+ {
+ assertTrue(_queueEntry1.compareTo(_queueEntry2) < 0);
+ assertTrue(_queueEntry2.compareTo(_queueEntry1) > 0);
+ assertTrue(_queueEntry1.compareTo(_queueEntry1) == 0);
+ }
+
+ /**
+ * Tests that the getNext() can be used to traverse the list.
+ */
+ public void testTraverseWithNoDeletedEntries()
+ {
+ QueueEntryImpl current = _queueEntry1;
+
+ current = current.getNext();
+ assertSame("Unexpected current entry",_queueEntry2, current);
+
+ current = current.getNext();
+ assertSame("Unexpected current entry",_queueEntry3, current);
+
+ current = current.getNext();
+ assertNull(current);
+
+ }
+
+ /**
+ * Tests that the getNext() can be used to traverse the list but deleted
+ * entries are skipped and de-linked from the chain of entries.
+ */
+ public void testTraverseWithDeletedEntries()
+ {
+ // Delete 2nd queue entry
+ _queueEntry2.delete();
+ assertTrue(_queueEntry2.isDeleted());
+
+
+ QueueEntryImpl current = _queueEntry1;
+
+ current = current.getNext();
+ assertSame("Unexpected current entry",_queueEntry3, current);
+
+ current = current.getNext();
+ assertNull(current);
+
+ // Assert the side effects of getNext()
+ assertSame("Next node of entry 1 should now be entry 3",
+ _queueEntry3, _queueEntry1.nextNode());
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
index 9b65b7750c..67d093d00a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -1,4 +1,3 @@
-package org.apache.qpid.server.queue;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,6 +19,7 @@ package org.apache.qpid.server.queue;
*
*/
+package org.apache.qpid.server.queue;
import org.apache.commons.configuration.PropertiesConfiguration;
@@ -36,6 +36,7 @@ import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.exchange.DirectExchange;
import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.queue.BaseQueue.PostEnqueueAction;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.StoredMessage;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
@@ -170,7 +171,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
}
- public void testSubscription() throws AMQException
+ public void testRegisterSubscriptionThenEnqueueMessage() throws AMQException
{
// Check adding a subscription adds it to the queue
_queue.registerSubscription(_subscription, false);
@@ -185,6 +186,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
AMQMessage messageA = createMessage(new Long(24));
_queue.enqueue(messageA);
assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+ assertNull(((QueueContext)_subscription.getQueueContext())._releasedEntry);
// Check removing the subscription removes it's information from the queue
_queue.unregisterSubscription(_subscription);
@@ -199,13 +201,269 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase
}
- public void testQueueNoSubscriber() throws AMQException, InterruptedException
+ public void testEnqueueMessageThenRegisterSubscription() throws AMQException, InterruptedException
{
AMQMessage messageA = createMessage(new Long(24));
_queue.enqueue(messageA);
_queue.registerSubscription(_subscription, false);
Thread.sleep(150);
assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+ assertNull("There should be no releasedEntry after an enqueue", ((QueueContext)_subscription.getQueueContext())._releasedEntry);
+ }
+
+ /**
+ * Tests enqueuing two messages.
+ */
+ public void testEnqueueTwoMessagesThenRegisterSubscription() throws Exception
+ {
+ AMQMessage messageA = createMessage(new Long(24));
+ AMQMessage messageB = createMessage(new Long(25));
+ _queue.enqueue(messageA);
+ _queue.enqueue(messageB);
+ _queue.registerSubscription(_subscription, false);
+ Thread.sleep(150);
+ assertEquals(messageB, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+ assertNull("There should be no releasedEntry after enqueues", ((QueueContext)_subscription.getQueueContext())._releasedEntry);
+ }
+
+ /**
+ * Tests that a re-queued message is resent to the subscriber. Verifies also that the
+ * QueueContext._releasedEntry is reset to null after the entry has been reset.
+ */
+ public void testRequeuedMessageIsResentToSubscriber() throws Exception
+ {
+ _queue.registerSubscription(_subscription, false);
+
+ final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+ PostEnqueueAction postEnqueueAction = new PostEnqueueAction()
+ {
+ public void onEnqueue(QueueEntry entry)
+ {
+ queueEntries.add(entry);
+ }
+ };
+
+ AMQMessage messageA = createMessage(new Long(24));
+ AMQMessage messageB = createMessage(new Long(25));
+ AMQMessage messageC = createMessage(new Long(26));
+
+ /* Enqueue three messages */
+
+ _queue.enqueue(messageA, postEnqueueAction);
+ _queue.enqueue(messageB, postEnqueueAction);
+ _queue.enqueue(messageC, postEnqueueAction);
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription", 3, _subscription.getMessages().size());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered());
+
+ /* Now requeue the first message only */
+
+ queueEntries.get(0).release();
+ _queue.requeue(queueEntries.get(0));
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription", 4, _subscription.getMessages().size());
+ assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered());
+ assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered());
+ assertFalse("Redelivery flag should remain be unset",queueEntries.get(2).isRedelivered());
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)_subscription.getQueueContext())._releasedEntry);
+ }
+
+ /**
+ * Tests that a re-queued message that becomes expired is not resent to the subscriber.
+ * This tests ensures that SimpleAMQQueueEntry.getNextAvailableEntry avoids expired entries.
+ * Verifies also that the QueueContext._releasedEntry is reset to null after the entry has been reset.
+ */
+ public void testRequeuedMessageThatBecomesExpiredIsNotRedelivered() throws Exception
+ {
+ _queue.registerSubscription(_subscription, false);
+
+ final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+ PostEnqueueAction postEnqueueAction = new PostEnqueueAction()
+ {
+ public void onEnqueue(QueueEntry entry)
+ {
+ queueEntries.add(entry);
+ }
+ };
+
+ /* Enqueue one message with expiration set for a short time in the future */
+
+ AMQMessage messageA = createMessage(new Long(24));
+ int messageExpirationOffset = 200;
+ messageA.setExpiration(System.currentTimeMillis() + messageExpirationOffset);
+
+ _queue.enqueue(messageA, postEnqueueAction);
+
+ int subFlushWaitTime = 150;
+ Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription", 1, _subscription.getMessages().size());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered());
+
+ /* Wait a little more to be sure that message will have expired, then requeue it */
+ Thread.sleep(messageExpirationOffset - subFlushWaitTime + 10);
+ queueEntries.get(0).release();
+ _queue.requeue(queueEntries.get(0));
+
+ Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner Thread
+
+ assertTrue("Expecting the queue entry to be now expired", queueEntries.get(0).expired());
+ assertEquals("Total number of messages sent should not have changed", 1, _subscription.getMessages().size());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered());
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)_subscription.getQueueContext())._releasedEntry);
+
+ }
+
+ /**
+ * Tests that if a client requeues messages 'out of order' (the order
+ * used by QueueEntryImpl.compareTo) that messages are still resent
+ * successfully. Specifically this test ensures the {@see SimpleAMQQueue#requeue()}
+ * can correctly move the _releasedEntry to an earlier position in the QueueEntry list.
+ */
+ public void testMessagesRequeuedOutOfComparableOrderAreDelivered() throws Exception
+ {
+ _queue.registerSubscription(_subscription, false);
+
+ final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+ PostEnqueueAction postEnqueueAction = new PostEnqueueAction()
+ {
+ public void onEnqueue(QueueEntry entry)
+ {
+ queueEntries.add(entry);
+ }
+ };
+
+ AMQMessage messageA = createMessage(new Long(24));
+ AMQMessage messageB = createMessage(new Long(25));
+ AMQMessage messageC = createMessage(new Long(26));
+
+ /* Enqueue three messages */
+
+ _queue.enqueue(messageA, postEnqueueAction);
+ _queue.enqueue(messageB, postEnqueueAction);
+ _queue.enqueue(messageC, postEnqueueAction);
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription", 3, _subscription.getMessages().size());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered());
+ assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered());
+
+ /* Now requeue the third and first message only */
+
+ queueEntries.get(2).release();
+ queueEntries.get(0).release();
+ _queue.requeue(queueEntries.get(2));
+ _queue.requeue(queueEntries.get(0));
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription", 5, _subscription.getMessages().size());
+ assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered());
+ assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered());
+ assertTrue("Redelivery flag should now be set",queueEntries.get(2).isRedelivered());
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)_subscription.getQueueContext())._releasedEntry);
+ }
+
+
+ /**
+ * Tests a requeue for a queue with multiple subscriptions. Verifies that a
+ * requeue resends a message to a <i>single</i> subscriber.
+ */
+ public void testRequeueForQueueWithMultipleSubscriptions() throws Exception
+ {
+ MockSubscription subscription1 = new MockSubscription();
+ MockSubscription subscription2 = new MockSubscription();
+
+ _queue.registerSubscription(subscription1, false);
+ _queue.registerSubscription(subscription2, false);
+
+ final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+ PostEnqueueAction postEnqueueAction = new PostEnqueueAction()
+ {
+ public void onEnqueue(QueueEntry entry)
+ {
+ queueEntries.add(entry);
+ }
+ };
+
+ AMQMessage messageA = createMessage(new Long(24));
+ AMQMessage messageB = createMessage(new Long(25));
+
+ /* Enqueue two messages */
+
+ _queue.enqueue(messageA, postEnqueueAction);
+ _queue.enqueue(messageB, postEnqueueAction);
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription1 after enqueue", 1, subscription1.getMessages().size());
+ assertEquals("Unexpected total number of messages sent to subscription2 after enqueue", 1, subscription2.getMessages().size());
+
+ /* Now requeue a message (for any subscription) */
+
+ queueEntries.get(0).release();
+ _queue.requeue((QueueEntryImpl)queueEntries.get(0));
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to all subscriptions after requeue", 3, subscription1.getMessages().size() + subscription2.getMessages().size());
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)subscription1.getQueueContext())._releasedEntry);
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)subscription2.getQueueContext())._releasedEntry);
+ }
+
+ /**
+ * Tests a requeue for a queue with multiple subscriptions. Verifies that a
+ * subscriber specific requeue resends the message to <i>that</i> subscriber.
+ */
+ public void testSubscriptionSpecificRequeueForQueueWithMultipleSubscriptions() throws Exception
+ {
+ MockSubscription subscription1 = new MockSubscription();
+ MockSubscription subscription2 = new MockSubscription();
+
+ _queue.registerSubscription(subscription1, false);
+ _queue.registerSubscription(subscription2, false);
+
+ final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+ PostEnqueueAction postEnqueueAction = new PostEnqueueAction()
+ {
+ public void onEnqueue(QueueEntry entry)
+ {
+ queueEntries.add(entry);
+ }
+ };
+
+ AMQMessage messageA = createMessage(new Long(24));
+ AMQMessage messageB = createMessage(new Long(25));
+
+ /* Enqueue two messages */
+
+ _queue.enqueue(messageA, postEnqueueAction);
+ _queue.enqueue(messageB, postEnqueueAction);
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription1 after enqueue", 1, subscription1.getMessages().size());
+ assertEquals("Unexpected total number of messages sent to subscription2 after enqueue", 1, subscription2.getMessages().size());
+
+ /* Now requeue a message (for first subscription) */
+
+ queueEntries.get(0).release();
+ _queue.requeue((QueueEntryImpl)queueEntries.get(0), subscription1);
+
+ Thread.sleep(150); // Work done by SubFlushRunner Thread
+
+ assertEquals("Unexpected total number of messages sent to subscription1 after requeue", 2, subscription1.getMessages().size());
+ assertEquals("Unexpected total number of messages sent to subscription2 after requeue", 1, subscription2.getMessages().size());
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)subscription1.getQueueContext())._releasedEntry);
+ assertNull("releasedEntry should be cleared after requeue processed", ((QueueContext)subscription2.getQueueContext())._releasedEntry);
}
public void testExclusiveConsumer() throws AMQException
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
index 2fbf5bb2cf..320a75045a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
@@ -51,6 +51,21 @@ public class SimpleQueueEntryListTest extends TestCase
}
}
+ /**
+ * Tests the behavior of the next(QueuyEntry) method.
+ */
+ public void testNext() throws Exception
+ {
+ SimpleQueueEntryList sqel = new SimpleQueueEntryList(null);
+ int i = 0;
+
+ QueueEntry queueEntry1 = sqel.add(new MockAMQMessage(i++));
+ QueueEntry queueEntry2 = sqel.add(new MockAMQMessage(i++));
+
+ assertSame(queueEntry2, sqel.next(queueEntry1));
+ assertNull(sqel.next(queueEntry2));
+ }
+
public void testScavenge() throws Exception
{
SimpleQueueEntryList sqel = new SimpleQueueEntryList(null);
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
index e8d0b99e6e..3593297a05 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
@@ -20,17 +20,12 @@
*/
package org.apache.qpid.server.store;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.apache.qpid.AMQStoreException;
import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.message.MessageMetaData;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.HashMap;
-import java.util.List;
-import java.nio.ByteBuffer;
/**
* Adds some extra methods to the memory message store for testing purposes.
@@ -52,8 +47,11 @@ public class TestableMemoryMessageStore extends MemoryMessageStore
}
-
-
+ @Override
+ public void close() throws Exception
+ {
+ // Not required to do anything
+ }
@Override
public StoredMessage addMessage(StorableMessageMetaData metaData)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
index e6367c4468..1ec134e90e 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
@@ -21,20 +21,19 @@ package org.apache.qpid.server.subscription;
*
*/
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.queue.QueueEntry.SubscriptionAcquiredState;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
public class MockSubscription implements Subscription
{
@@ -137,12 +136,11 @@ public class MockSubscription implements Subscription
public void set(String key, Object value)
{
- //To change body of implemented methods use File | Settings | File Templates.
}
public Object get(String key)
{
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ return null;
}
public boolean isAutoClose()
@@ -194,12 +192,15 @@ public class MockSubscription implements Subscription
public void restoreCredit(QueueEntry queueEntry)
{
- //To change body of implemented methods use File | Settings | File Templates.
}
- public void send(QueueEntry msg) throws AMQException
+ public void send(QueueEntry entry) throws AMQException
{
- messages.add(msg);
+ if (messages.contains(entry))
+ {
+ entry.setRedelivered();
+ }
+ messages.add(entry);
}
public void setQueueContext(AMQQueue.Context queueContext)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java
new file mode 100644
index 0000000000..9afed49922
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java
@@ -0,0 +1,442 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.queue.MockQueueEntry;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+/**
+ * A unit test ensuring that AutoCommitTransaction creates a separate transaction for
+ * each dequeue/enqueue operation that involves enlistable messages. Verifies
+ * that the transaction is properly committed (or rolled-back in the case of exception),
+ * and that post transaction actions are correctly fired.
+ *
+ */
+public class AutoCommitTransactionTest extends QpidTestCase
+{
+ private ServerTransaction _transaction = null; // Class under test
+
+ private TransactionLog _transactionLog;
+ private AMQQueue _queue;
+ private List<AMQQueue> _queues;
+ private Collection<QueueEntry> _queueEntries;
+ private ServerMessage _message;
+ private MockAction _action;
+ private MockStoreTransaction _storeTransaction;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _storeTransaction = createTestStoreTransaction(false);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _action = new MockAction();
+
+ _transaction = new AutoCommitTransaction(_transactionLog);
+ }
+
+ /**
+ * Tests the enqueue of a non persistent message to a single non durable queue.
+ * Asserts that a store transaction has not been started and commit action fired.
+ */
+ public void testEnqueueToNonDurableQueueOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queue = createTestAMQQueue(false);
+
+ _transaction.enqueue(_queue, _message, _action);
+
+ assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+
+ }
+
+ /**
+ * Tests the enqueue of a persistent message to a durable queue.
+ * Asserts that a store transaction has been committed and commit action fired.
+ */
+ public void testEnqueueToDurableQueueOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.enqueue(_queue, _message, _action);
+
+ assertEquals("Enqueue of persistent message to durable queue must cause message to be enqueued", 1, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted and rollback action is fired.
+ */
+ public void testStoreEnqueueCausesException() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new AutoCommitTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.enqueue(_queue, _message, _action);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertTrue("Rollback action must be fired", _action.isRollbackActionFired());
+ assertFalse("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the enqueue of a non persistent message to a many non durable queues.
+ * Asserts that a store transaction has not been started and post commit action fired.
+ */
+ public void testEnqueueToManyNonDurableQueuesOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queues = createTestBaseQueues(new boolean[] {false, false, false});
+
+ _transaction.enqueue(_queues, _message, _action);
+
+ assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+
+ }
+
+
+ /**
+ * Tests the enqueue of a persistent message to a many non durable queues.
+ * Asserts that a store transaction has not been started and post commit action
+ * fired.
+ */
+ public void testEnqueueToManyNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {false, false, false});
+
+ _transaction.enqueue(_queues, _message, _action);
+
+ assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+
+ }
+
+ /**
+ * Tests the enqueue of a persistent message to many queues, some durable others not.
+ * Asserts that a store transaction has been committed and post commit action fired.
+ */
+ public void testEnqueueToDurableAndNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {false, true, false, true});
+
+ _transaction.enqueue(_queues, _message, _action);
+
+ assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted and rollback action fired.
+ */
+ public void testStoreEnqueuesCausesExceptions() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {true, true});
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new AutoCommitTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.enqueue(_queues, _message, _action);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertTrue("Rollback action must be fired", _action.isRollbackActionFired());
+ assertFalse("Post commit action must not be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the dequeue of a non persistent message from a single non durable queue.
+ * Asserts that a store transaction has not been started and post commit action
+ * fired.
+ */
+ public void testDequeueFromNonDurableQueueOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queue = createTestAMQQueue(false);
+
+ _transaction.dequeue(_queue, _message, _action);
+
+ assertEquals("Dequeue of non-persistent message must not cause message to be dequeued", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+
+ }
+
+ /**
+ * Tests the dequeue of a persistent message from a single non durable queue.
+ * Asserts that a store transaction has not been started and post commit
+ * action fired.
+ */
+ public void testDequeueFromDurableQueueOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.dequeue(_queue, _message, _action);
+
+ assertEquals("Dequeue of persistent message to durable queue must cause message to be dequeued",1, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted and post rollback action
+ * fired.
+ */
+ public void testStoreDequeueCausesException() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new AutoCommitTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.dequeue(_queue, _message, _action);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+
+ assertTrue("Rollback action must be fired", _action.isRollbackActionFired());
+ assertFalse("Post commit action must not be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the dequeue of a non persistent message from many non durable queues.
+ * Asserts that a store transaction has not been started and post commit action
+ * fired.
+ */
+ public void testDequeueFromManyNonDurableQueuesOfNonPersistentMessage() throws Exception
+ {
+ _queueEntries = createTestQueueEntries(new boolean[] {false, false, false}, new boolean[] {false, false, false});
+
+ _transaction.dequeue(_queueEntries, _action);
+
+ assertEquals("Dequeue of non-persistent messages must not cause message to be dequeued", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertEquals("Rollback action must not be fired", false, _action.isRollbackActionFired());
+ assertEquals("Post commit action must be fired", true, _action.isPostCommitActionFired());
+
+ }
+
+
+ /**
+ * Tests the dequeue of a persistent message from a many non durable queues.
+ * Asserts that a store transaction has not been started and post commit action
+ * fired.
+ */
+ public void testDequeueFromManyNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _queueEntries = createTestQueueEntries(new boolean[] {false, false, false}, new boolean[] {true, true, true});
+
+ _transaction.dequeue(_queueEntries, _action);
+
+ assertEquals("Dequeue of persistent message from non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the dequeue of a persistent message from many queues, some durable others not.
+ * Asserts that a store transaction has not been started and post commit action fired.
+ */
+ public void testDequeueFromDurableAndNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ // A transaction will exist owing to the 1st and 3rd.
+ _queueEntries = createTestQueueEntries(new boolean[] {true, false, true, true}, new boolean[] {true, true, true, false});
+
+ _transaction.dequeue(_queueEntries, _action);
+
+ assertEquals("Dequeue of persistent messages from durable/non-durable queues must cause messages to be dequeued", 2, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired", _action.isRollbackActionFired());
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted and post rollback action fired.
+ */
+ public void testStoreDequeuesCauseExceptions() throws Exception
+ {
+ // Transactions will exist owing to the 1st and 3rd queue entries in the collection
+ _queueEntries = createTestQueueEntries(new boolean[] {true}, new boolean[] {true});
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new AutoCommitTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.dequeue(_queueEntries, _action);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+
+ assertTrue("Rollback action must be fired", _action.isRollbackActionFired());
+ assertFalse("Post commit action must not be fired", _action.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the add of a post-commit action. Since AutoCommitTranctions
+ * have no long lived transactions, the post commit action is fired immediately.
+ */
+ public void testPostCommitActionFiredImmediately() throws Exception
+ {
+
+ _transaction.addPostTransactionAction(_action);
+
+ assertTrue("Post commit action must be fired", _action.isPostCommitActionFired());
+ assertFalse("Rollback action must be fired", _action.isRollbackActionFired());
+ }
+
+ private Collection<QueueEntry> createTestQueueEntries(boolean[] queueDurableFlags, boolean[] messagePersistentFlags)
+ {
+ Collection<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+
+ assertTrue("Boolean arrays must be the same length", queueDurableFlags.length == messagePersistentFlags.length);
+
+ for(int i = 0; i < queueDurableFlags.length; i++)
+ {
+ final AMQQueue queue = createTestAMQQueue(queueDurableFlags[i]);
+ final ServerMessage message = createTestMessage(messagePersistentFlags[i]);
+
+ queueEntries.add(new MockQueueEntry()
+ {
+
+ @Override
+ public ServerMessage getMessage()
+ {
+ return message;
+ }
+
+ @Override
+ public AMQQueue getQueue()
+ {
+ return queue;
+ }
+
+ });
+ }
+
+ return queueEntries;
+ }
+
+ private MockStoreTransaction createTestStoreTransaction(boolean throwException)
+ {
+ return new MockStoreTransaction(throwException);
+ }
+
+ private List<AMQQueue> createTestBaseQueues(boolean[] durableFlags)
+ {
+ List<AMQQueue> queues = new ArrayList<AMQQueue>();
+ for (boolean b: durableFlags)
+ {
+ queues.add(createTestAMQQueue(b));
+ }
+
+ return queues;
+ }
+
+ private AMQQueue createTestAMQQueue(final boolean durable)
+ {
+ return new MockAMQQueue("mockQueue")
+ {
+ @Override
+ public boolean isDurable()
+ {
+ return durable;
+ }
+
+ };
+ }
+
+ private ServerMessage createTestMessage(final boolean persistent)
+ {
+ return new MockServerMessage(persistent);
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java
new file mode 100644
index 0000000000..e81fd8e3f1
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java
@@ -0,0 +1,557 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.queue.MockQueueEntry;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+/**
+ * A unit test ensuring that LocalTransactionTest creates a long-lived store transaction
+ * that spans many dequeue/enqueue operations of enlistable messages. Verifies
+ * that the long-lived transaction is properly committed and rolled back, and that
+ * post transaction actions are correctly fired.
+ *
+ */
+public class LocalTransactionTest extends QpidTestCase
+{
+ private ServerTransaction _transaction = null; // Class under test
+
+ private AMQQueue _queue;
+ private List<AMQQueue> _queues;
+ private Collection<QueueEntry> _queueEntries;
+ private ServerMessage _message;
+ private MockAction _action1;
+ private MockAction _action2;
+ private MockStoreTransaction _storeTransaction;
+ private TransactionLog _transactionLog;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _storeTransaction = createTestStoreTransaction(false);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _action1 = new MockAction();
+ _action2 = new MockAction();
+
+ _transaction = new LocalTransaction(_transactionLog);
+
+ }
+
+
+ /**
+ * Tests the enqueue of a non persistent message to a single non durable queue.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testEnqueueToNonDurableQueueOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queue = createTestAMQQueue(false);
+
+ _transaction.enqueue(_queue, _message, _action1);
+
+ assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the enqueue of a persistent message to a durable queue.
+ * Asserts that a store transaction has been started.
+ */
+ public void testEnqueueToDurableQueueOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.enqueue(_queue, _message, _action1);
+
+ assertEquals("Enqueue of persistent message to durable queue must cause message to be enqueued", 1, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted.
+ */
+ public void testStoreEnqueueCausesException() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new LocalTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.enqueue(_queue, _message, _action1);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertTrue("Rollback action must be fired", _action1.isRollbackActionFired());
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+
+ assertFalse("Post commit action must not be fired", _action1.isPostCommitActionFired());
+
+ }
+
+ /**
+ * Tests the enqueue of a non persistent message to a many non durable queues.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testEnqueueToManyNonDurableQueuesOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queues = createTestBaseQueues(new boolean[] {false, false, false});
+
+ _transaction.enqueue(_queues, _message, _action1);
+
+ assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the enqueue of a persistent message to a many non durable queues.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testEnqueueToManyNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {false, false, false});
+
+ _transaction.enqueue(_queues, _message, _action1);
+
+ assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+
+ }
+
+ /**
+ * Tests the enqueue of a persistent message to many queues, some durable others not.
+ * Asserts that a store transaction has been started.
+ */
+ public void testEnqueueToDurableAndNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {false, true, false, true});
+
+ _transaction.enqueue(_queues, _message, _action1);
+
+ assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted.
+ */
+ public void testStoreEnqueuesCausesExceptions() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queues = createTestBaseQueues(new boolean[] {true, true});
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new LocalTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.enqueue(_queues, _message, _action1);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertTrue("Rollback action must be fired", _action1.isRollbackActionFired());
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertFalse("Post commit action must not be fired", _action1.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the dequeue of a non persistent message from a single non durable queue.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testDequeueFromNonDurableQueueOfNonPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(false);
+ _queue = createTestAMQQueue(false);
+
+ _transaction.dequeue(_queue, _message, _action1);
+
+ assertEquals("Dequeue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+
+ }
+
+ /**
+ * Tests the dequeue of a persistent message from a single non durable queue.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testDequeueFromDurableQueueOfPersistentMessage() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.dequeue(_queue, _message, _action1);
+
+ assertEquals("Dequeue of non-persistent message must cause message to be dequeued", 1, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted.
+ */
+ public void testStoreDequeueCausesException() throws Exception
+ {
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new LocalTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.dequeue(_queue, _message, _action1);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertTrue("Rollback action must be fired", _action1.isRollbackActionFired());
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertFalse("Post commit action must not be fired", _action1.isPostCommitActionFired());
+
+ }
+
+ /**
+ * Tests the dequeue of a non persistent message from many non durable queues.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testDequeueFromManyNonDurableQueuesOfNonPersistentMessage() throws Exception
+ {
+ _queueEntries = createTestQueueEntries(new boolean[] {false, false, false}, new boolean[] {false, false, false});
+
+ _transaction.dequeue(_queueEntries, _action1);
+
+ assertEquals("Dequeue of non-persistent messages must not cause message to be dequeued", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+
+ }
+
+ /**
+ * Tests the dequeue of a persistent message from a many non durable queues.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testDequeueFromManyNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ _queueEntries = createTestQueueEntries(new boolean[] {false, false, false}, new boolean[] {true, true, true});
+
+ _transaction.dequeue(_queueEntries, _action1);
+
+ assertEquals("Dequeue of persistent message from non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the dequeue of a persistent message from many queues, some durable others not.
+ * Asserts that a store transaction has not been started.
+ */
+ public void testDequeueFromDurableAndNonDurableQueuesOfPersistentMessage() throws Exception
+ {
+ // A transaction will exist owing to the 1st and 3rd.
+ _queueEntries = createTestQueueEntries(new boolean[] {true, false, true, true}, new boolean[] {true, true, true, false});
+
+ _transaction.dequeue(_queueEntries, _action1);
+
+ assertEquals("Dequeue of persistent messages from durable/non-durable queues must cause messages to be dequeued", 2, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertNotFired(_action1);
+ }
+
+ /**
+ * Tests the case where the store operation throws an exception.
+ * Asserts that the transaction is aborted.
+ */
+ public void testStoreDequeuesCauseExceptions() throws Exception
+ {
+ // Transactions will exist owing to the 1st and 3rd queue entries in the collection
+ _queueEntries = createTestQueueEntries(new boolean[] {true}, new boolean[] {true});
+
+ _storeTransaction = createTestStoreTransaction(true);
+ _transactionLog = MockStoreTransaction.createTestTransactionLog(_storeTransaction);
+ _transaction = new LocalTransaction(_transactionLog);
+
+ try
+ {
+ _transaction.dequeue(_queueEntries, _action1);
+ fail("Exception not thrown");
+ }
+ catch (RuntimeException re)
+ {
+ // PASS
+ }
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertTrue("Rollback action must be fired", _action1.isRollbackActionFired());
+ assertFalse("Post commit action must not be fired", _action1.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the add of a post-commit action. Unlike AutoCommitTranctions, the post transaction actions
+ * is added to a list to be fired on commit or rollback.
+ */
+ public void testAddingPostCommitActionNotFiredImmediately() throws Exception
+ {
+
+ _transaction.addPostTransactionAction(_action1);
+
+ assertNotFired(_action1);
+ }
+
+
+ /**
+ * Tests committing a transaction without work accepted without error and without causing store
+ * enqueues or dequeues.
+ */
+ public void testCommitNoWork() throws Exception
+ {
+
+ _transaction.commit();
+
+ assertEquals("Unexpected number of store dequeues", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected number of store enqueues", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ }
+
+ /**
+ * Tests rolling back a transaction without work accepted without error and without causing store
+ * enqueues or dequeues.
+ */
+ public void testRollbackNoWork() throws Exception
+ {
+
+ _transaction.rollback();
+
+ assertEquals("Unexpected number of store dequeues", 0, _storeTransaction.getNumberOfDequeuedMessages());
+ assertEquals("Unexpected number of store enqueues", 0, _storeTransaction.getNumberOfEnqueuedMessages());
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ }
+
+ /**
+ * Tests the dequeuing of a message with a commit. Test ensures that the underlying store transaction is
+ * correctly controlled and the post commit action is fired.
+ */
+ public void testCommitWork() throws Exception
+ {
+
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Post commit action must not be fired yet", _action1.isPostCommitActionFired());
+
+ _transaction.dequeue(_queue, _message, _action1);
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertFalse("Post commit action must not be fired yet", _action1.isPostCommitActionFired());
+
+ _transaction.commit();
+
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+ assertTrue("Post commit action must be fired", _action1.isPostCommitActionFired());
+ }
+
+ /**
+ * Tests the dequeuing of a message with a rollback. Test ensures that the underlying store transaction is
+ * correctly controlled and the post rollback action is fired.
+ */
+ public void testRollbackWork() throws Exception
+ {
+
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+
+ assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired yet", _action1.isRollbackActionFired());
+
+ _transaction.dequeue(_queue, _message, _action1);
+
+ assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
+ assertFalse("Rollback action must not be fired yet", _action1.isRollbackActionFired());
+
+ _transaction.rollback();
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+ assertTrue("Rollback action must be fired", _action1.isRollbackActionFired());
+
+ }
+
+ /**
+ * Variation of testCommitWork with an additional post transaction action.
+ *
+ */
+ public void testCommitWorkWithAdditionalPostAction() throws Exception
+ {
+
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.addPostTransactionAction(_action1);
+ _transaction.dequeue(_queue, _message, _action2);
+ _transaction.commit();
+
+ assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
+
+ assertTrue("Post commit action1 must be fired", _action1.isPostCommitActionFired());
+ assertTrue("Post commit action2 must be fired", _action2.isPostCommitActionFired());
+
+ assertFalse("Rollback action1 must not be fired", _action1.isRollbackActionFired());
+ assertFalse("Rollback action2 must not be fired", _action1.isRollbackActionFired());
+ }
+
+ /**
+ * Variation of testRollbackWork with an additional post transaction action.
+ *
+ */
+ public void testRollbackWorkWithAdditionalPostAction() throws Exception
+ {
+
+ _message = createTestMessage(true);
+ _queue = createTestAMQQueue(true);
+
+ _transaction.addPostTransactionAction(_action1);
+ _transaction.dequeue(_queue, _message, _action2);
+ _transaction.rollback();
+
+ assertEquals("Unexpected transaction state", TransactionState.ABORTED, _storeTransaction.getState());
+
+ assertFalse("Post commit action1 must not be fired", _action1.isPostCommitActionFired());
+ assertFalse("Post commit action2 must not be fired", _action2.isPostCommitActionFired());
+
+ assertTrue("Rollback action1 must be fired", _action1.isRollbackActionFired());
+ assertTrue("Rollback action2 must be fired", _action1.isRollbackActionFired());
+ }
+
+ private Collection<QueueEntry> createTestQueueEntries(boolean[] queueDurableFlags, boolean[] messagePersistentFlags)
+ {
+ Collection<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
+
+ assertTrue("Boolean arrays must be the same length", queueDurableFlags.length == messagePersistentFlags.length);
+
+ for(int i = 0; i < queueDurableFlags.length; i++)
+ {
+ final AMQQueue queue = createTestAMQQueue(queueDurableFlags[i]);
+ final ServerMessage message = createTestMessage(messagePersistentFlags[i]);
+
+ queueEntries.add(new MockQueueEntry()
+ {
+
+ @Override
+ public ServerMessage getMessage()
+ {
+ return message;
+ }
+
+ @Override
+ public AMQQueue getQueue()
+ {
+ return queue;
+ }
+
+ });
+ }
+
+ return queueEntries;
+ }
+
+ private MockStoreTransaction createTestStoreTransaction(boolean throwException)
+ {
+ return new MockStoreTransaction(throwException);
+ }
+
+ private List<AMQQueue> createTestBaseQueues(boolean[] durableFlags)
+ {
+ List<AMQQueue> queues = new ArrayList<AMQQueue>();
+ for (boolean b: durableFlags)
+ {
+ queues.add(createTestAMQQueue(b));
+ }
+
+ return queues;
+ }
+
+ private AMQQueue createTestAMQQueue(final boolean durable)
+ {
+ return new MockAMQQueue("mockQueue")
+ {
+ @Override
+ public boolean isDurable()
+ {
+ return durable;
+ }
+
+ };
+ }
+
+ private ServerMessage createTestMessage(final boolean persistent)
+ {
+ return new MockServerMessage(persistent);
+ }
+
+ private void assertNotFired(MockAction action)
+ {
+ assertFalse("Rollback action must not be fired", action.isRollbackActionFired());
+ assertFalse("Post commit action must not be fired", action.isPostCommitActionFired());
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockAction.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockAction.java
new file mode 100644
index 0000000000..975e3e91b9
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockAction.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import org.apache.qpid.server.txn.ServerTransaction.Action;
+
+/**
+ * Mock implementation of a ServerTranaction Action
+ * allowing its state to be observed.
+ *
+ */
+class MockAction implements Action
+{
+ private boolean _rollbackFired = false;
+ private boolean _postCommitFired = false;
+
+ @Override
+ public void postCommit()
+ {
+ _postCommitFired = true;
+ }
+
+ @Override
+ public void onRollback()
+ {
+ _rollbackFired = true;
+ }
+
+ public boolean isRollbackActionFired()
+ {
+ return _rollbackFired;
+ }
+
+ public boolean isPostCommitActionFired()
+ {
+ return _postCommitFired;
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java
new file mode 100644
index 0000000000..64c62fd029
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import java.nio.ByteBuffer;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.qpid.server.configuration.SessionConfig;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+
+/**
+ * Mock Server Message allowing its persistent flag to be controlled from test.
+ */
+class MockServerMessage implements ServerMessage
+{
+ /**
+ *
+ */
+ private final boolean persistent;
+
+ /**
+ * @param persistent
+ */
+ MockServerMessage(boolean persistent)
+ {
+ this.persistent = persistent;
+ }
+
+ @Override
+ public boolean isPersistent()
+ {
+ return persistent;
+ }
+
+ @Override
+ public MessageReference newReference()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isImmediate()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public long getSize()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public SessionConfig getSessionConfig()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getRoutingKey()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public AMQMessageHeader getMessageHeader()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public long getExpiration()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public int getContent(ByteBuffer buf, int offset)
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public long getArrivalTime()
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Long getMessageNumber()
+ {
+ return 0L;
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java
new file mode 100644
index 0000000000..5700bba9f8
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.qpid.AMQStoreException;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.TransactionLogRecoveryHandler;
+import org.apache.qpid.server.store.TransactionLogResource;
+import org.apache.qpid.server.store.TransactionLog.StoreFuture;
+import org.apache.qpid.server.store.TransactionLog.Transaction;
+
+/**
+ * Mock implementation of a (Store) Transaction allow its state to be observed.
+ * Also provide a factory method to produce TestTransactionLog objects suitable
+ * for unit test use.
+ *
+ */
+class MockStoreTransaction implements Transaction
+{
+ enum TransactionState {NOT_STARTED, STARTED, COMMITTED, ABORTED};
+
+ private TransactionState _state = TransactionState.NOT_STARTED;
+
+ private int _numberOfEnqueuedMessages = 0;
+ private int _numberOfDequeuedMessages = 0;
+ private boolean _throwExceptionOnQueueOp;
+
+ public MockStoreTransaction(boolean throwExceptionOnQueueOp)
+ {
+ _throwExceptionOnQueueOp = throwExceptionOnQueueOp;
+ }
+
+ public void setState(TransactionState state)
+ {
+ _state = state;
+ }
+
+ public TransactionState getState()
+ {
+ return _state;
+ }
+
+ @Override
+ public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+ {
+ if (_throwExceptionOnQueueOp)
+ {
+
+ throw new AMQStoreException("Mocked exception");
+ }
+
+ _numberOfEnqueuedMessages++;
+ }
+
+ public int getNumberOfDequeuedMessages()
+ {
+ return _numberOfDequeuedMessages;
+ }
+
+ public int getNumberOfEnqueuedMessages()
+ {
+ return _numberOfEnqueuedMessages;
+ }
+
+
+ @Override
+ public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+ {
+ if (_throwExceptionOnQueueOp)
+ {
+ throw new AMQStoreException("Mocked exception");
+ }
+
+ _numberOfDequeuedMessages++;
+ }
+
+ @Override
+ public void commitTran() throws AMQStoreException
+ {
+ _state = TransactionState.COMMITTED;
+ }
+
+ @Override
+ public StoreFuture commitTranAsync() throws AMQStoreException
+ {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void abortTran() throws AMQStoreException
+ {
+ _state = TransactionState.ABORTED;
+ }
+
+ public static TransactionLog createTestTransactionLog(final MockStoreTransaction storeTransaction)
+ {
+ return new TransactionLog()
+ {
+
+ @Override
+ public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration, LogSubject logSubject) throws Exception
+ {
+ }
+
+ @Override
+ public Transaction newTransaction()
+ {
+ storeTransaction.setState(TransactionState.STARTED);
+ return storeTransaction;
+ }
+
+ };
+ }
+} \ No newline at end of file
diff --git a/qpid/java/build.xml b/qpid/java/build.xml
index 6ed2992a68..9031166d76 100644
--- a/qpid/java/build.xml
+++ b/qpid/java/build.xml
@@ -66,6 +66,10 @@
<iterate target="pom"/>
</target>
+ <target name="release-mvn" description="Install the artifacts into the local repository">
+ <iterate target="release-mvn"/>
+ </target>
+
<target name="compile" description="compile sources">
<iterate target="compile"/>
</target>
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 b483406949..af0d8a3a1d 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
@@ -26,15 +26,12 @@ import java.net.ConnectException;
import java.net.UnknownHostException;
import java.nio.channels.UnresolvedAddressException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionMetaData;
@@ -84,153 +81,6 @@ import org.slf4j.LoggerFactory;
public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable
{
- public static final class ChannelToSessionMap
- {
- private final AMQSession[] _fastAccessSessions = new AMQSession[16];
- private final LinkedHashMap<Integer, AMQSession> _slowAccessSessions = new LinkedHashMap<Integer, AMQSession>();
- private int _size = 0;
- private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
- private AtomicInteger _idFactory = new AtomicInteger(0);
- private int _maxChannelID;
- private boolean _cycledIds;
-
- public AMQSession get(int channelId)
- {
- if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
- {
- return _fastAccessSessions[channelId];
- }
- else
- {
- return _slowAccessSessions.get(channelId);
- }
- }
-
- public AMQSession put(int channelId, AMQSession session)
- {
- AMQSession oldVal;
- if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
- {
- oldVal = _fastAccessSessions[channelId];
- _fastAccessSessions[channelId] = session;
- }
- else
- {
- oldVal = _slowAccessSessions.put(channelId, session);
- }
- if ((oldVal != null) && (session == null))
- {
- _size--;
- }
- else if ((oldVal == null) && (session != null))
- {
- _size++;
- }
-
- return session;
-
- }
-
- public AMQSession remove(int channelId)
- {
- AMQSession session;
- if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
- {
- session = _fastAccessSessions[channelId];
- _fastAccessSessions[channelId] = null;
- }
- else
- {
- session = _slowAccessSessions.remove(channelId);
- }
-
- if (session != null)
- {
- _size--;
- }
- return session;
-
- }
-
- public Collection<AMQSession> values()
- {
- ArrayList<AMQSession> values = new ArrayList<AMQSession>(size());
-
- for (int i = 0; i < 16; i++)
- {
- if (_fastAccessSessions[i] != null)
- {
- values.add(_fastAccessSessions[i]);
- }
- }
- values.addAll(_slowAccessSessions.values());
-
- return values;
- }
-
- public int size()
- {
- return _size;
- }
-
- public void clear()
- {
- _size = 0;
- _slowAccessSessions.clear();
- for (int i = 0; i < 16; i++)
- {
- _fastAccessSessions[i] = null;
- }
- }
-
- /*
- * Synchronized on whole method so that we don't need to consider the
- * increment-then-reset path in too much detail
- */
- public synchronized int getNextChannelId()
- {
- int id = 0;
- if (!_cycledIds)
- {
- id = _idFactory.incrementAndGet();
- if (id == _maxChannelID)
- {
- _cycledIds = true;
- _idFactory.set(0); // Go back to the start
- }
- }
- else
- {
- boolean done = false;
- while (!done)
- {
- // Needs to work second time through
- id = _idFactory.incrementAndGet();
- if (id > _maxChannelID)
- {
- _idFactory.set(0);
- id = _idFactory.incrementAndGet();
- }
- if ((id & FAST_CHANNEL_ACCESS_MASK) == 0)
- {
- done = (_fastAccessSessions[id] == null);
- }
- else
- {
- done = (!_slowAccessSessions.keySet().contains(id));
- }
- }
- }
-
- return id;
- }
-
- public void setMaxChannelID(int maxChannelID)
- {
- _maxChannelID = maxChannelID;
- }
- }
-
private static final Logger _logger = LoggerFactory.getLogger(AMQConnection.class);
@@ -244,9 +94,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
/**
* A channel is roughly analogous to a session. The server can negotiate the maximum number of channels per session
- * and we must prevent the client from opening too many. Zero means unlimited.
+ * and we must prevent the client from opening too many.
*/
- protected long _maximumChannelCount;
+ private long _maximumChannelCount;
/** The maximum size of frame supported by the server */
private long _maximumFrameSize;
@@ -489,7 +339,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
_delegate = new AMQConnectionDelegate_0_10(this);
}
- _sessions.setMaxChannelID(_delegate.getMaxChannelID());
if (_logger.isInfoEnabled())
{
@@ -570,8 +419,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
}
- _logger.info("Connected with ProtocolHandler Version:"+_protocolHandler.getProtocolVersion());
-
if (_logger.isDebugEnabled())
{
_logger.debug("Are we connected:" + _connected);
@@ -579,6 +426,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
if (!_connected)
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Last attempted ProtocolHandler Version:"+_protocolHandler.getProtocolVersion());
+ }
+
String message = null;
if (connectionException != null)
@@ -620,6 +472,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
throw new AMQConnectionFailureException(message, connectionException);
}
+ _logger.info("Connected with ProtocolHandler Version:"+_protocolHandler.getProtocolVersion());
+
+ _sessions.setMaxChannelID(_delegate.getMaxChannelID());
+ _sessions.setMinChannelID(_delegate.getMinChannelID());
+
_connectionMetaData = new QpidConnectionMetaData(this);
}
@@ -647,7 +504,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
Class partypes[] = new Class[1];
partypes[0] = AMQConnection.class;
_delegate = (AMQConnectionDelegate) c.getConstructor(partypes).newInstance(this);
- _sessions.setMaxChannelID(_delegate.getMaxChannelID());
//Update our session to use this new protocol version
_protocolHandler.getProtocolSession().setProtocolVersion(_delegate.getProtocolVersion());
@@ -898,7 +754,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public boolean channelLimitReached()
{
- return (_maximumChannelCount != 0) && (_sessions.size() == _maximumChannelCount);
+ return _sessions.size() >= _maximumChannelCount;
}
public String getClientID() throws JMSException
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
index 5f93ec6c47..9560bd5c7c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
@@ -59,6 +59,8 @@ public interface AMQConnectionDelegate
<T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E;
int getMaxChannelID();
-
+
+ int getMinChannelID();
+
ProtocolVersion getProtocolVersion();
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index adfd178ec3..4b4417b6ef 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -37,6 +37,7 @@ import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.configuration.ClientProperties;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ChannelLimitReachedException;
import org.apache.qpid.jms.Session;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.transport.Connection;
@@ -82,6 +83,12 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
throws JMSException
{
_conn.checkNotClosed();
+
+ if (_conn.channelLimitReached())
+ {
+ throw new ChannelLimitReachedException(_conn.getMaximumChannelCount());
+ }
+
int channelId = _conn.getNextChannelID();
AMQSession session;
try
@@ -120,6 +127,12 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException
{
_conn.checkNotClosed();
+
+ if (_conn.channelLimitReached())
+ {
+ throw new ChannelLimitReachedException(_conn.getMaximumChannelCount());
+ }
+
int channelId = _conn.getNextChannelID();
XASessionImpl session;
try
@@ -165,6 +178,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
_conn._connected = true;
_conn.setUsername(_qpidConnection.getUserID());
+ _conn.setMaximumChannelCount(_qpidConnection.getChannelMax());
_conn._failoverPolicy.attainedConnection();
}
catch (ProtocolVersionException pe)
@@ -293,7 +307,13 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
public int getMaxChannelID()
{
- return Integer.MAX_VALUE;
+ //For a negotiated channelMax N, there are channels 0 to N-1 available.
+ return _qpidConnection.getChannelMax() - 1;
+ }
+
+ public int getMinChannelID()
+ {
+ return Connection.MIN_USABLE_CHANNEL_NUM;
}
public ProtocolVersion getProtocolVersion()
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index 9cee4dab53..40b332d216 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -36,6 +36,7 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.client.failover.FailoverRetrySupport;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
import org.apache.qpid.client.state.AMQState;
import org.apache.qpid.client.state.StateWaiter;
import org.apache.qpid.client.transport.TransportConnection;
@@ -134,7 +135,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
if (_conn.channelLimitReached())
{
- throw new ChannelLimitReachedException(_conn._maximumChannelCount);
+ throw new ChannelLimitReachedException(_conn.getMaximumChannelCount());
}
return new FailoverRetrySupport<org.apache.qpid.jms.Session, JMSException>(
@@ -307,7 +308,14 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
public int getMaxChannelID()
{
- return (int) (Math.pow(2, 16)-1);
+ ConnectionTuneParameters params = _conn.getProtocolHandler().getProtocolSession().getConnectionTuneParameters();
+
+ return params == null ? AMQProtocolSession.MAX_CHANNEL_MAX : params.getChannelMax();
+ }
+
+ public int getMinChannelID()
+ {
+ return AMQProtocolSession.MIN_USABLE_CHANNEL_NUM;
}
public ProtocolVersion getProtocolVersion()
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 f54189db6d..1f940b62f0 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
@@ -119,7 +119,6 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AMQSession<C extends BasicMessageConsumer, P extends BasicMessageProducer> extends Closeable implements Session, QueueSession, TopicSession
{
-
public static final class IdToConsumerMap<C extends BasicMessageConsumer>
{
private final BasicMessageConsumer[] _fastAccessConsumers = new BasicMessageConsumer[16];
@@ -363,7 +362,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/**
* Set when recover is called. This is to handle the case where recover() is called by application code during
- * onMessage() processing to enure that an auto ack is not sent.
+ * onMessage() processing to ensure that an auto ack is not sent.
*/
private boolean _inRecovery;
@@ -383,7 +382,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private final Object _suspensionLock = new Object();
/**
- * Used to ensure that onlt the first call to start the dispatcher can unsuspend the channel.
+ * Used to ensure that only the first call to start the dispatcher can unsuspend the channel.
*
* @todo This is accessed only within a synchronized method, so does not need to be atomic.
*/
@@ -429,7 +428,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
* @param con The connection on which to create the session.
* @param channelId The unique identifier for the session.
* @param transacted Indicates whether or not the session is transactional.
- * @param acknowledgeMode The acknoledgement mode for the session.
+ * @param acknowledgeMode The acknowledgement mode for the session.
* @param messageFactoryRegistry The message factory factory for the session.
* @param defaultPrefetchHighMark The maximum number of messages to prefetched before suspending the session.
* @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session.
@@ -475,7 +474,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// flow control
if (!(_thisSession.isClosed() || _thisSession.isClosing()))
{
- // Only executute change if previous state
+ // Only execute change if previous state
// was False
if (!_suspendState.getAndSet(true))
{
@@ -485,7 +484,14 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
"Above threshold(" + _prefetchHighMark
+ ") so suspending channel. Current value is " + currentValue);
}
- new Thread(new SuspenderRunner(_suspendState)).start();
+ try
+ {
+ Threading.getThreadFactory().createThread(new SuspenderRunner(_suspendState)).start();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create thread", e);
+ }
}
}
}
@@ -496,7 +502,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// flow control
if (!(_thisSession.isClosed() || _thisSession.isClosing()))
{
- // Only executute change if previous state
+ // Only execute change if previous state
// was true
if (_suspendState.getAndSet(false))
{
@@ -507,7 +513,14 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
"Below threshold(" + _prefetchLowMark
+ ") so unsuspending channel. Current value is " + currentValue);
}
- new Thread(new SuspenderRunner(_suspendState)).start();
+ try
+ {
+ Threading.getThreadFactory().createThread(new SuspenderRunner(_suspendState)).start();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create thread", e);
+ }
}
}
}
@@ -531,7 +544,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
* @param con The connection on which to create the session.
* @param channelId The unique identifier for the session.
* @param transacted Indicates whether or not the session is transactional.
- * @param acknowledgeMode The acknoledgement mode for the session.
+ * @param acknowledgeMode The acknowledgement mode for the session.
* @param defaultPrefetchHigh The maximum number of messages to prefetched before suspending the session.
* @param defaultPrefetchLow The number of prefetched messages at which to resume the session.
*/
@@ -562,7 +575,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (IllegalStateException ise)
{
- // if the Connection has closed then we should throw any exception that has occured that we were not waiting for
+ // if the Connection has closed then we should throw any exception that has occurred that we were not waiting for
AMQStateManager manager = _connection.getProtocolHandler().getStateManager();
if (manager.getCurrentState().equals(AMQState.CONNECTION_CLOSED) && manager.getLastException() != null)
@@ -677,11 +690,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/**
* Closes the session.
*
- * <p/>Note that this operation succeeds automatically if a fail-over interupts the sycnronous request to close
+ * <p/>Note that this operation succeeds automatically if a fail-over interrupts the synchronous request to close
* the channel. This is because the channel is marked as closed before the request to close it is made, so the
* fail-over should not re-open it.
*
- * @param timeout The timeout in milliseconds to wait for the session close acknoledgement from the broker.
+ * @param timeout The timeout in milliseconds to wait for the session close acknowledgement from the broker.
*
* @throws JMSException If the JMS provider fails to close the session due to some internal error.
* @todo Be aware of possible changes to parameter order as versions change.
@@ -2566,7 +2579,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
public abstract P createMessageProducer(final Destination destination, final boolean mandatory,
- final boolean immediate, final boolean waitUntilSent, long producerId);
+ final boolean immediate, final boolean waitUntilSent, long producerId) throws JMSException;
private void declareExchange(AMQDestination amqd, AMQProtocolHandler protocolHandler, boolean nowait) throws AMQException
{
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index 297a8da65b..1eaccf53fc 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -660,10 +660,21 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*/
public BasicMessageProducer_0_10 createMessageProducer(final Destination destination, final boolean mandatory,
final boolean immediate, final boolean waitUntilSent,
- long producerId)
+ long producerId) throws JMSException
{
- return new BasicMessageProducer_0_10(_connection, (AMQDestination) destination, _transacted, _channelId, this,
+ try
+ {
+ return new BasicMessageProducer_0_10(_connection, (AMQDestination) destination, _transacted, _channelId, this,
getProtocolHandler(), producerId, immediate, mandatory, waitUntilSent);
+ }
+ catch (AMQException e)
+ {
+ JMSException ex = new JMSException("Error creating producer");
+ ex.initCause(e);
+ ex.setLinkedException(e);
+
+ throw ex;
+ }
}
@@ -698,6 +709,20 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
}
/**
+ * deletes an exchange
+ */
+ public void sendExchangeDelete(final String name, final boolean nowait)
+ throws AMQException, FailoverException
+ {
+ getQpidSession().exchangeDelete(name);
+ // We need to sync so that we get notify of an error.
+ if (!nowait)
+ {
+ sync();
+ }
+ }
+
+ /**
* Declare a queue with the given queueName
*/
public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index 8cca92da1f..f41b1c94fa 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -400,11 +400,21 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public BasicMessageProducer_0_8 createMessageProducer(final Destination destination, final boolean mandatory,
- final boolean immediate, final boolean waitUntilSent, long producerId)
+ final boolean immediate, final boolean waitUntilSent, long producerId) throws JMSException
{
-
- return new BasicMessageProducer_0_8(_connection, (AMQDestination) destination, _transacted, _channelId,
+ try
+ {
+ return new BasicMessageProducer_0_8(_connection, (AMQDestination) destination, _transacted, _channelId,
this, getProtocolHandler(), producerId, immediate, mandatory, waitUntilSent);
+ }
+ catch (AMQException e)
+ {
+ JMSException ex = new JMSException("Error creating producer");
+ ex.initCause(e);
+ ex.setLinkedException(e);
+
+ throw ex;
+ }
}
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 14e1601993..8756ac4d05 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
@@ -127,7 +127,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory,
- boolean waitUntilSent)
+ boolean waitUntilSent) throws AMQException
{
_connection = connection;
_destination = destination;
@@ -175,7 +175,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
}
}
- abstract void declareDestination(AMQDestination destination);
+ abstract void declareDestination(AMQDestination destination) throws AMQException;
public void setDisableMessageID(boolean b) throws JMSException
{
@@ -434,7 +434,18 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
AMQDestination amqDestination = (AMQDestination) destination;
if(!amqDestination.isExchangeExistsChecked())
{
- declareDestination(amqDestination);
+ try
+ {
+ declareDestination(amqDestination);
+ }
+ catch(Exception e)
+ {
+ JMSException ex = new JMSException("Error validating destination");
+ ex.initCause(e);
+ ex.setLinkedException(e);
+
+ throw ex;
+ }
amqDestination.setExchangeExistsChecked(true);
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
index f874ea08f2..53c0457120 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
@@ -56,7 +56,7 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
BasicMessageProducer_0_10(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId,
- boolean immediate, boolean mandatory, boolean waitUntilSent)
+ boolean immediate, boolean mandatory, boolean waitUntilSent) throws AMQException
{
super(connection, destination, transacted, channelId, session, protocolHandler, producerId, immediate,
mandatory, waitUntilSent);
@@ -64,7 +64,7 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
userIDBytes = Strings.toUTF8(_userID);
}
- void declareDestination(AMQDestination destination)
+ void declareDestination(AMQDestination destination) throws AMQException
{
if (destination.getDestSyntax() == DestSyntax.BURL)
{
@@ -83,8 +83,8 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
}
catch(Exception e)
{
- // Idealy this should be thrown to the JMS layer.
- _logger.warn("Exception occured while verifying destination",e);
+ AMQException ex = new AMQException("Exception occured while verifying destination",e);
+ throw ex;
}
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
index b770a8b524..27f7486890 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
@@ -28,6 +28,7 @@ import javax.jms.Topic;
import javax.jms.Queue;
import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
import org.apache.qpid.client.message.AbstractJMSMessage;
import org.apache.qpid.client.message.AMQMessageDelegate;
import org.apache.qpid.client.message.AMQMessageDelegate_0_8;
@@ -46,7 +47,7 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer
BasicMessageProducer_0_8(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory,
- boolean waitUntilSent)
+ boolean waitUntilSent) throws AMQException
{
super(connection, destination,transacted,channelId,session, protocolHandler, producerId, immediate, mandatory,waitUntilSent);
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java b/qpid/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java
new file mode 100644
index 0000000000..2b7e3d44da
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/ChannelToSessionMap.java
@@ -0,0 +1,147 @@
+package org.apache.qpid.client;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class ChannelToSessionMap
+{
+ private final AMQSession[] _fastAccessSessions = new AMQSession[16];
+ private final LinkedHashMap<Integer, AMQSession> _slowAccessSessions = new LinkedHashMap<Integer, AMQSession>();
+ private int _size = 0;
+ private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
+ private AtomicInteger _idFactory = new AtomicInteger(0);
+ private int _maxChannelID;
+ private int _minChannelID;
+
+ public AMQSession get(int channelId)
+ {
+ if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ return _fastAccessSessions[channelId];
+ }
+ else
+ {
+ return _slowAccessSessions.get(channelId);
+ }
+ }
+
+ public AMQSession put(int channelId, AMQSession session)
+ {
+ AMQSession oldVal;
+ if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ oldVal = _fastAccessSessions[channelId];
+ _fastAccessSessions[channelId] = session;
+ }
+ else
+ {
+ oldVal = _slowAccessSessions.put(channelId, session);
+ }
+ if ((oldVal != null) && (session == null))
+ {
+ _size--;
+ }
+ else if ((oldVal == null) && (session != null))
+ {
+ _size++;
+ }
+
+ return session;
+
+ }
+
+ public AMQSession remove(int channelId)
+ {
+ AMQSession session;
+ if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ session = _fastAccessSessions[channelId];
+ _fastAccessSessions[channelId] = null;
+ }
+ else
+ {
+ session = _slowAccessSessions.remove(channelId);
+ }
+
+ if (session != null)
+ {
+ _size--;
+ }
+ return session;
+
+ }
+
+ public Collection<AMQSession> values()
+ {
+ ArrayList<AMQSession> values = new ArrayList<AMQSession>(size());
+
+ for (int i = 0; i < 16; i++)
+ {
+ if (_fastAccessSessions[i] != null)
+ {
+ values.add(_fastAccessSessions[i]);
+ }
+ }
+ values.addAll(_slowAccessSessions.values());
+
+ return values;
+ }
+
+ public int size()
+ {
+ return _size;
+ }
+
+ public void clear()
+ {
+ _size = 0;
+ _slowAccessSessions.clear();
+ for (int i = 0; i < 16; i++)
+ {
+ _fastAccessSessions[i] = null;
+ }
+ }
+
+ /*
+ * Synchronized on whole method so that we don't need to consider the
+ * increment-then-reset path in too much detail
+ */
+ public synchronized int getNextChannelId()
+ {
+ int id = _minChannelID;
+
+ boolean done = false;
+ while (!done)
+ {
+ id = _idFactory.getAndIncrement();
+ if (id == _maxChannelID)
+ {
+ //go back to the start
+ _idFactory.set(_minChannelID);
+ }
+ if ((id & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ done = (_fastAccessSessions[id] == null);
+ }
+ else
+ {
+ done = (!_slowAccessSessions.keySet().contains(id));
+ }
+ }
+
+ return id;
+ }
+
+ public void setMaxChannelID(int maxChannelID)
+ {
+ _maxChannelID = maxChannelID;
+ }
+
+ public void setMinChannelID(int minChannelID)
+ {
+ _minChannelID = minChannelID;
+ _idFactory.set(_minChannelID);
+ }
+} \ No newline at end of file
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
index 287b5957a1..d1b2caf987 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
@@ -55,9 +55,12 @@ public class ConnectionTuneMethodHandler implements StateAwareMethodListener<Con
{
params = new ConnectionTuneParameters();
}
+
+ int maxChannelNumber = frame.getChannelMax();
+ //0 implies no limit, except that forced by protocol limitations (0xFFFF)
+ params.setChannelMax(maxChannelNumber == 0 ? AMQProtocolSession.MAX_CHANNEL_MAX : maxChannelNumber);
params.setFrameMax(frame.getFrameMax());
- params.setChannelMax(frame.getChannelMax());
params.setHeartbeat(Integer.getInteger("amqj.heartbeat.delay", frame.getHeartbeat()));
session.setConnectionTuneParameters(params);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
index 522782a6cf..ed2e96e83b 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
@@ -115,15 +115,28 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate
if (deliveryProps != null)
{
String exchange = deliveryProps.getExchange();
+ checkAndUpdateExchange(exchange,session);
+
+ }
+
+ MessageProperties msgProps = header.get(MessageProperties.class);
+ if (msgProps != null && msgProps.getReplyTo() != null)
+ {
+ String exchange = msgProps.getReplyTo().getExchange();
+ checkAndUpdateExchange(exchange,session);
+
+ }
+ }
+
+ private static void checkAndUpdateExchange(String exchange, org.apache.qpid.transport.Session session)
+ {
+ if (exchange != null && !exchangeMapContains(exchange))
+ {
+ Future<ExchangeQueryResult> future =
+ session.exchangeQuery(exchange.toString());
+ ExchangeQueryResult res = future.get();
- if (exchange != null && !exchangeMapContains(exchange))
- {
- Future<ExchangeQueryResult> future =
- session.exchangeQuery(exchange.toString());
- ExchangeQueryResult res = future.get();
-
- updateExchangeType(exchange, res.getType());
- }
+ updateExchangeType(exchange, res.getType());
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
index 6b90bd3ad2..89fbc9722c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
@@ -95,6 +95,11 @@ public abstract class AbstractAMQMessageDelegate implements AMQMessageDelegate
AMQDestination dest;
ExchangeInfo exchangeInfo = _exchangeMap.get(exchange.asString());
+ if (exchangeInfo == null)
+ {
+ exchangeInfo = new ExchangeInfo(exchange.asString(),"",AMQDestination.UNKNOWN_TYPE);
+ }
+
if ("topic".equals(exchangeInfo.exchangeType))
{
dest = new AMQTopic(exchange, routingKey, null);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index c16941b341..eb5af119b2 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -28,6 +28,7 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.mina.filter.codec.ProtocolCodecException;
@@ -63,6 +64,7 @@ import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQMethodListener;
import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.network.io.IoTransport;
import org.slf4j.Logger;
@@ -100,7 +102,7 @@ import org.slf4j.LoggerFactory;
* connection is shutdown and a new one created. For this reason, an AMQProtocolHandler is created per AMQConnection
* and the protocol session data is held outside of the MINA IOSession.
*
- * <p/>This handler is responsibile for setting up the filter chain to filter all events for this handler through.
+ * <p/>This handler is responsible for setting up the filter chain to filter all events for this handler through.
* The filter chain is set up as a stack of event handers that perform the following functions (working upwards from
* the network traffic at the bottom), handing off incoming events to an asynchronous thread pool to do the work,
* optionally handling secure sockets encoding/decoding, encoding/decoding the AMQP format itself.
@@ -114,8 +116,8 @@ import org.slf4j.LoggerFactory;
* @todo Use a single handler instance, by shifting everything to do with the 'protocol session' state, including
* failover state, into AMQProtocolSession, and tracking that from AMQConnection? The lifecycles of
* AMQProtocolSesssion and AMQConnection will be the same, so if there is high cohesion between them, they could
- * be merged, although there is sense in keeping the session model seperate. Will clarify things by having data
- * held per protocol handler, per protocol session, per network connection, per channel, in seperate classes, so
+ * be merged, although there is sense in keeping the session model separate. Will clarify things by having data
+ * held per protocol handler, per protocol session, per network connection, per channel, in separate classes, so
* that lifecycles of the fields match lifecycles of their containing objects.
*/
public class AMQProtocolHandler implements ProtocolEngine
@@ -158,7 +160,7 @@ public class AMQProtocolHandler implements ProtocolEngine
/** Used to provide a condition to wait upon for operations that are required to wait for failover to complete. */
private CountDownLatch _failoverLatch;
- /** The last failover exception that occured */
+ /** The last failover exception that occurred */
private FailoverException _lastFailoverException;
/** Defines the default timeout to use for synchronous protocol commands. */
@@ -187,6 +189,21 @@ public class AMQProtocolHandler implements ProtocolEngine
_protocolSession = new AMQProtocolSession(this, _connection);
_stateManager = new AMQStateManager(_protocolSession);
_codecFactory = new AMQCodecFactory(false, _protocolSession);
+ _poolReference.setThreadFactory(new ThreadFactory()
+ {
+
+ public Thread newThread(final Runnable runnable)
+ {
+ try
+ {
+ return Threading.getThreadFactory().createThread(runnable);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create thread", e);
+ }
+ }
+ });
_readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true);
_writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false);
_poolReference.acquireExecutorService();
@@ -275,7 +292,15 @@ public class AMQProtocolHandler implements ProtocolEngine
{
if(!_connection.isClosed())
{
- Thread failoverThread = new Thread(_failoverHandler);
+ final Thread failoverThread;
+ try
+ {
+ failoverThread = Threading.getThreadFactory().createThread(_failoverHandler);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create thread", e);
+ }
failoverThread.setName("Failover");
// Do not inherit daemon-ness from current thread as this can be a daemon
// thread such as a AnonymousIoService thread.
@@ -369,7 +394,7 @@ public class AMQProtocolHandler implements ProtocolEngine
}
/**
- * This caters for the case where we only need to propogate an exception to the the frame listeners to interupt any
+ * This caters for the case where we only need to propagate an exception to the the frame listeners to interupt any
* protocol level waits.
*
* This will would normally be used to notify all Frame Listeners that Failover is about to occur and they should
@@ -407,7 +432,7 @@ public class AMQProtocolHandler implements ProtocolEngine
}
//Only notify the Frame listeners that failover is going to occur as the State listeners shouldn't be
- // interupted unless failover cannot restore the state.
+ // interrupted unless failover cannot restore the state.
propagateExceptionToFrameListeners(_lastFailoverException);
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
index f0edd0d7bf..7976760696 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
@@ -54,6 +54,10 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
public static final String PROTOCOL_INITIATION_RECEIVED = "ProtocolInitiatiionReceived";
+ //Usable channels are numbered 1 to <ChannelMax>
+ public static final int MAX_CHANNEL_MAX = 0xFFFF;
+ public static final int MIN_USABLE_CHANNEL_NUM = 1;
+
protected static final String CONNECTION_TUNE_PARAMETERS = "ConnectionTuneParameters";
protected static final String AMQ_CONNECTION = "AMQConnection";
@@ -178,6 +182,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
{
_connectionTuneParameters = params;
AMQConnection con = getAMQConnection();
+
con.setMaximumChannelCount(params.getChannelMax());
con.setMaximumFrameSize(params.getFrameMax());
_protocolHandler.initHeartbeats((int) params.getHeartbeat());
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java
index 3d4a4573ed..e8c2b9d682 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java
@@ -33,9 +33,9 @@ public class ChannelLimitReachedException extends ResourceAllocationException
public ChannelLimitReachedException(long limit)
{
- super("Unable to create session since maximum number of sessions per connection is " +
- limit + ". Either close one or more sessions or increase the " +
- "maximum number of sessions per connection (or contact your AMQP administrator.", ERROR_CODE);
+ super("Unable to create session, the maximum number of sessions per connection is " +
+ limit + ". You must either close one or more sessions or increase the " +
+ "maximum number of sessions available per connection.", ERROR_CODE);
_limit = limit;
}
diff --git a/qpid/java/common/Composite.tpl b/qpid/java/common/Composite.tpl
index 97b7d01f3c..350dd893c8 100644
--- a/qpid/java/common/Composite.tpl
+++ b/qpid/java/common/Composite.tpl
@@ -44,6 +44,8 @@ cls = klass(type)["@name"]
segments = type["segments"]
+connectioncontrol="false"
+
if type.name in ("control", "command"):
base = "Method"
size = 0
@@ -54,6 +56,7 @@ if type.name in ("control", "command"):
payload = "false"
if type.name == "control" and cls == "connection":
track = "Frame.L1"
+ connectioncontrol="true"
elif cls == "session" and type["@name"] in ("attach", "attached", "detach", "detached"):
track = "Frame.L2"
elif type.name == "command":
@@ -100,6 +103,11 @@ public final class $name extends $base {
return $track;
}
+ public final boolean isConnectionControl()
+ {
+ return $connectioncontrol;
+ }
+
${
if pack > 0:
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
index 20a30b3ed3..8152a1f5e9 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
@@ -22,10 +22,12 @@ package org.apache.qpid.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
+
/**
* ReferenceCountingExecutorService wraps an ExecutorService in order to provide shared reference to it. It counts
* the references taken, instantiating the service on the first reference, and shutting it down when the last
@@ -36,7 +38,7 @@ import java.util.concurrent.LinkedBlockingQueue;
*
* <p/><table id="crc><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide a shared exector service. <td> {@link Executors}
+ * <tr><td> Provide a shared executor service. <td> {@link Executors}
* <tr><td> Shutdown the executor service when not needed. <td> {@link ExecutorService}
* <tr><td> Track references to the executor service.
* <tr><td> Provide configuration of the executor service.
@@ -53,13 +55,15 @@ import java.util.concurrent.LinkedBlockingQueue;
* @todo {@link #_poolSize} should be static?
*
* @todo The {@link #getPool()} method breaks the encapsulation of the reference counter. Generally when getPool is used
- * further checks are applied to ensure that the exector service has not been shutdown. This passes responsibility
+ * further checks are applied to ensure that the executor service has not been shutdown. This passes responsibility
* for managing the lifecycle of the reference counted object onto the caller rather than neatly encapsulating it
* here. Could think about adding more state to the lifecycle, to mark ref counted objects as invalid, and have an
* isValid method, or could make calling code deal with RejectedExecutionException raised by shutdown executors.
*/
public class ReferenceCountingExecutorService
{
+
+
/** Defines the smallest thread pool that will be allocated, irrespective of the number of processors. */
private static final int MINIMUM_POOL_SIZE = 4;
@@ -87,6 +91,11 @@ public class ReferenceCountingExecutorService
/** Holds the number of executor threads to create. */
private int _poolSize = Integer.getInteger("amqj.read_write_pool_size", DEFAULT_POOL_SIZE);
+ /** Thread Factory used to create thread of the pool. Uses the default implementation provided by
+ * {@link java.util.concurrent.Executors#defaultThreadFactory()} unless reset by the caller.
+ */
+ private ThreadFactory _threadFactory = Executors.defaultThreadFactory();
+
private final boolean _useBiasedPool = Boolean.getBoolean("org.apache.qpid.use_write_biased_pool");
/**
@@ -116,19 +125,23 @@ public class ReferenceCountingExecutorService
{
if (_refCount++ == 0)
{
-// _pool = Executors.newFixedThreadPool(_poolSize);
-
// Use a job queue that biases to writes
if(_useBiasedPool)
{
_pool = new ThreadPoolExecutor(_poolSize, _poolSize,
0L, TimeUnit.MILLISECONDS,
- new ReadWriteJobQueue());
+ new ReadWriteJobQueue(),
+ _threadFactory);
+
}
else
{
- _pool = Executors.newFixedThreadPool(_poolSize);
+ _pool = new ThreadPoolExecutor(_poolSize, _poolSize,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<Runnable>(),
+ _threadFactory);
}
+
}
@@ -137,7 +150,7 @@ public class ReferenceCountingExecutorService
}
/**
- * Releases a reference to a shared executor service, decrementing the reference count. If the refence count falls
+ * Releases a reference to a shared executor service, decrementing the reference count. If the reference count falls
* to zero, the executor service is shut down.
*/
public void releaseExecutorService()
@@ -169,4 +182,34 @@ public class ReferenceCountingExecutorService
{
return _refCount;
}
+
+ /**
+ *
+ * Return the thread factory used by the {@link ThreadPoolExecutor} to create new threads.
+ *
+ * @return thread factory
+ */
+ public ThreadFactory getThreadFactory()
+ {
+ return _threadFactory;
+ }
+
+ /**
+ * Sets the thread factory used by the {@link ThreadPoolExecutor} to create new threads.
+ * <p>
+ * If the pool has been already created, the change will have no effect until
+ * {@link #getReferenceCount()} reaches zero and the pool recreated. For this reason,
+ * callers must invoke this method <i>before</i> calling {@link #acquireExecutorService()}.
+ *
+ * @param threadFactory thread factory
+ */
+ public void setThreadFactory(final ThreadFactory threadFactory)
+ {
+ if (threadFactory == null)
+ {
+ throw new NullPointerException("threadFactory cannot be null");
+ }
+ _threadFactory = threadFactory;
+ }
+
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
index 9786d8fc3f..a96dac4109 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
@@ -1,4 +1,3 @@
-package org.apache.qpid.thread;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,29 +19,25 @@ package org.apache.qpid.thread;
*
*/
+package org.apache.qpid.thread;
-public class DefaultThreadFactory implements ThreadFactory
-{
-
- private static class QpidThread extends Thread
- {
- private QpidThread(final Runnable target)
- {
- super(target);
- }
- }
+public class DefaultThreadFactory implements ThreadFactory
+{
+ private final LoggingUncaughtExceptionHandler _loggingUncaughtExceptionHandler = new LoggingUncaughtExceptionHandler();
public Thread createThread(Runnable r)
{
- return new Thread(r);
+ Thread t = new Thread(r);
+ t.setUncaughtExceptionHandler(_loggingUncaughtExceptionHandler);
+ return t;
}
public Thread createThread(Runnable r, int priority)
{
- Thread t = new Thread(r);
+ Thread t = createThread(r);
t.setPriority(priority);
return t;
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/thread/LoggingUncaughtExceptionHandler.java b/qpid/java/common/src/main/java/org/apache/qpid/thread/LoggingUncaughtExceptionHandler.java
new file mode 100644
index 0000000000..192675edcd
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/thread/LoggingUncaughtExceptionHandler.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.thread;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * An {@link UncaughtExceptionHandler} that writes the exception to the application log via
+ * the SLF4J framework. Once registered with {@link Thread#setUncaughtExceptionHandler(UncaughtExceptionHandler)}
+ * it will be invoked by the JVM when a thread has been <i>abruptly</i> terminated due to an uncaught exception.
+ * Owing to the contract of {@link Runnable#run()}, the only possible exception types which can cause such a termination
+ * are instances of {@link RuntimeException} and {@link Error}. These exceptions are catastrophic and the client must
+ * restart the JVM.
+ * <p>
+ * The implementation also invokes {@link ThreadGroup#uncaughtException(Thread, Throwable)}. This
+ * is done to retain compatibility with any monitoring solutions (for example, log scraping of
+ * standard error) that existing users of older Qpid client libraries may have in place.
+ *
+ */
+public class LoggingUncaughtExceptionHandler implements UncaughtExceptionHandler
+{
+ private static final Logger _logger = LoggerFactory.getLogger(LoggingUncaughtExceptionHandler.class);
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e)
+ {
+ try
+ {
+ _logger.error("Uncaught exception in thread \"{}\"", t.getName(), e);
+ }
+ finally
+ {
+ // Invoke the thread group's handler too for compatibility with any
+ // existing clients who are already scraping stderr for such conditions.
+ t.getThreadGroup().uncaughtException(t, e);
+ }
+ }
+} \ No newline at end of file
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
index 0507b3108f..95a8d192c5 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
@@ -25,6 +25,8 @@ import java.lang.reflect.Constructor;
public class RealtimeThreadFactory implements ThreadFactory
{
+ private final LoggingUncaughtExceptionHandler _loggingUncaughtExceptionHandler = new LoggingUncaughtExceptionHandler();
+
private Class threadClass;
private Constructor threadConstructor;
private Constructor priorityParameterConstructor;
@@ -62,7 +64,9 @@ public class RealtimeThreadFactory implements ThreadFactory
public Thread createThread(Runnable r, int priority) throws Exception
{
Object priorityParams = priorityParameterConstructor.newInstance(priority);
- return (Thread)threadConstructor.newInstance(priorityParams,null,null,null,null,r);
+ Thread thread = (Thread)threadConstructor.newInstance(priorityParams,null,null,null,null,r);
+ thread.setUncaughtExceptionHandler(_loggingUncaughtExceptionHandler);
+ return thread;
}
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
index 82fb57eb7d..bce64075e5 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
@@ -86,7 +86,8 @@ public class ClientDelegate extends ConnectionDelegate
}
}
- @Override public void connectionStart(Connection conn, ConnectionStart start)
+ @Override
+ public void connectionStart(Connection conn, ConnectionStart start)
{
Map<String,Object> clientProperties = new HashMap<String,Object>();
@@ -156,7 +157,8 @@ public class ClientDelegate extends ConnectionDelegate
}
}
- @Override public void connectionSecure(Connection conn, ConnectionSecure secure)
+ @Override
+ public void connectionSecure(Connection conn, ConnectionSecure secure)
{
SaslClient sc = conn.getSaslClient();
try
@@ -170,9 +172,9 @@ public class ClientDelegate extends ConnectionDelegate
}
}
- @Override public void connectionTune(Connection conn, ConnectionTune tune)
+ @Override
+ public void connectionTune(Connection conn, ConnectionTune tune)
{
- conn.setChannelMax(tune.getChannelMax());
int hb_interval = calculateHeartbeatInterval(conSettings.getHeartbeatInterval(),
tune.getHeartbeatMin(),
tune.getHeartbeatMax()
@@ -182,10 +184,17 @@ public class ClientDelegate extends ConnectionDelegate
hb_interval);
// The idle timeout is twice the heartbeat amount (in milisecs)
conn.setIdleTimeout(hb_interval*1000*2);
+
+ int channelMax = tune.getChannelMax();
+ //0 means no implied limit, except available server resources
+ //(or that forced by protocol limitations [0xFFFF])
+ conn.setChannelMax(channelMax == 0 ? Connection.MAX_CHANNEL_MAX : channelMax);
+
conn.connectionOpen(conSettings.getVhost(), null, Option.INSIST);
}
- @Override public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
+ @Override
+ public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
{
SaslClient sc = conn.getSaslClient();
if (sc != null)
@@ -210,12 +219,14 @@ public class ClientDelegate extends ConnectionDelegate
conn.setState(OPEN);
}
- @Override public void connectionRedirect(Connection conn, ConnectionRedirect redir)
+ @Override
+ public void connectionRedirect(Connection conn, ConnectionRedirect redir)
{
throw new UnsupportedOperationException();
}
- @Override public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
+ @Override
+ public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
{
conn.connectionHeartbeat();
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index fa3c1737a7..fd19fa0512 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -59,6 +59,9 @@ public class Connection extends ConnectionInvoker
protected static final Logger log = Logger.get(Connection.class);
+ //Usable channels are numbered 0 to <ChannelMax> - 1
+ public static final int MAX_CHANNEL_MAX = 0xFFFF;
+ public static final int MIN_USABLE_CHANNEL_NUM = 0;
public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD }
@@ -404,7 +407,8 @@ public class Connection extends ConnectionInvoker
{
synchronized (lock)
{
- for (int i = 1; i <= getChannelMax(); i++)
+ //For a negotiated channelMax N, there are channels 0 to N-1 available.
+ for (int i = 0; i < getChannelMax(); i++)
{
if (!channels.containsKey(i))
{
@@ -434,7 +438,7 @@ public class Connection extends ConnectionInvoker
}
}
- Session getSession(int channel)
+ protected Session getSession(int channel)
{
synchronized (lock)
{
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolError.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolError.java
index bd6ab81997..8a5edc302e 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolError.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolError.java
@@ -60,6 +60,11 @@ public final class ProtocolError implements NetworkEvent, ProtocolEvent
return track;
}
+ public boolean isConnectionControl()
+ {
+ return false;
+ }
+
public String getMessage()
{
return String.format(format, args);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolEvent.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolEvent.java
index 60234c1537..b51a540701 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolEvent.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolEvent.java
@@ -37,4 +37,5 @@ public interface ProtocolEvent
<C> void delegate(C context, ProtocolDelegate<C> delegate);
+ boolean isConnectionControl();
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
index 00ea55ff96..e5b93e40a9 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
@@ -88,6 +88,11 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
return Frame.L1;
}
+ public boolean isConnectionControl()
+ {
+ return false;
+ }
+
public ByteBuffer toByteBuffer()
{
ByteBuffer buf = ByteBuffer.allocate(8);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
index 644a2daa58..b8e7616a37 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
@@ -30,6 +30,8 @@ import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* ServerDelegate
@@ -38,8 +40,8 @@ import javax.security.sasl.SaslServer;
public class ServerDelegate extends ConnectionDelegate
{
+ protected static final Logger _logger = LoggerFactory.getLogger(ServerDelegate.class);
- private SaslServer saslServer;
private List<Object> _locales;
private List<Object> _mechanisms;
private Map<String, Object> _clientProperties;
@@ -47,7 +49,7 @@ public class ServerDelegate extends ConnectionDelegate
public ServerDelegate()
{
- this(null, Collections.EMPTY_LIST, Collections.singletonList((Object)"utf8"));
+ this(null, Collections.emptyList(), Collections.singletonList((Object)"utf8"));
}
protected ServerDelegate(Map<String, Object> clientProperties, List<Object> mechanisms, List<Object> locales)
@@ -64,7 +66,8 @@ public class ServerDelegate extends ConnectionDelegate
conn.connectionStart(_clientProperties, _mechanisms, _locales);
}
- @Override public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ @Override
+ public void connectionStartOk(Connection conn, ConnectionStartOk ok)
{
conn.setLocale(ok.getLocale());
String mechanism = ok.getMechanism();
@@ -75,9 +78,9 @@ public class ServerDelegate extends ConnectionDelegate
if (mechanism == null || mechanism.length() == 0)
{
conn.connectionTune
- (Integer.MAX_VALUE,
+ (getChannelMax(),
org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
- 0, Integer.MAX_VALUE);
+ 0, getHeartbeatMax());
return;
}
@@ -118,7 +121,7 @@ public class ServerDelegate extends ConnectionDelegate
{
ss.dispose();
conn.connectionTune
- (Integer.MAX_VALUE,
+ (getChannelMax(),
org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
0, getHeartbeatMax());
conn.setAuthorizationID(ss.getAuthorizationID());
@@ -140,19 +143,42 @@ public class ServerDelegate extends ConnectionDelegate
return Integer.MAX_VALUE;
}
- @Override public void connectionSecureOk(Connection conn, ConnectionSecureOk ok)
+ protected int getChannelMax()
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public void connectionSecureOk(Connection conn, ConnectionSecureOk ok)
{
secure(conn, ok.getResponse());
}
- @Override public void connectionTuneOk(Connection conn, ConnectionTuneOk ok)
+ @Override
+ public void connectionTuneOk(Connection conn, ConnectionTuneOk ok)
{
+ int okChannelMax = ok.getChannelMax();
+ if (okChannelMax > getChannelMax())
+ {
+ _logger.error("Connection '" + conn.getConnectionId() + "' being severed, " +
+ "client connectionTuneOk returned a channelMax (" + okChannelMax +
+ ") above the servers offered limit (" + getChannelMax() +")");
+
+ //Due to the error we must forcefully close the connection without negotiation
+ conn.getSender().close();
+ return;
+ }
+
+ //0 means no implied limit, except available server resources
+ //(or that forced by protocol limitations [0xFFFF])
+ conn.setChannelMax(okChannelMax == 0 ? Connection.MAX_CHANNEL_MAX : okChannelMax);
}
- @Override public void connectionOpen(Connection conn, ConnectionOpen open)
+ @Override
+ public void connectionOpen(Connection conn, ConnectionOpen open)
{
- conn.connectionOpenOk(Collections.EMPTY_LIST);
+ conn.connectionOpenOk(Collections.emptyList());
conn.setState(OPEN);
}
@@ -168,7 +194,8 @@ public class ServerDelegate extends ConnectionDelegate
return new Session(conn, new Binary(atc.getName()), 0);
}
- @Override public void sessionAttach(Connection conn, SessionAttach atc)
+ @Override
+ public void sessionAttach(Connection conn, SessionAttach atc)
{
Session ssn = getSession(conn, atc);
conn.map(ssn, atc.getChannel());
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
index 4e6d2130ae..dd6a37eca2 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -52,7 +52,6 @@ public class IoNetworkTransport implements NetworkTransport, IoContext
private long timeout = 60000;
private ConnectionSettings settings;
- @Override
public void init(ConnectionSettings settings)
{
try
@@ -84,20 +83,17 @@ public class IoNetworkTransport implements NetworkTransport, IoContext
}
}
- @Override
public void receiver(Receiver<ByteBuffer> delegate)
{
receiver = new IoReceiver(this, delegate,
2*settings.getReadBufferSize() , timeout);
}
- @Override
public Sender<ByteBuffer> sender()
{
return new IoSender(this, 2*settings.getWriteBufferSize(), timeout);
}
-
- @Override
+
public void close()
{
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
index 1a2869a815..0f2c0d0226 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
@@ -83,6 +83,14 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver
private static final Logger _logger = LoggerFactory.getLogger(MINANetworkDriver.class);
+ static
+ {
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
+
+ //override the MINA defaults to prevent use of the PooledByteBufferAllocator
+ org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ }
+
public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO)
{
_useNIO = useNIO;
@@ -209,14 +217,6 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver
// connector
}
- org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
- // the MINA default is currently to use the pooled allocator although this may change in future
- // once more testing of the performance of the simple allocator has been done
- if (!Boolean.getBoolean("amqj.enablePooledAllocator"))
- {
- org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
- }
-
SocketConnectorConfig cfg = (SocketConnectorConfig) _socketConnector.getDefaultConfig();
String s = "";
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java b/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java
new file mode 100644
index 0000000000..35998de3a1
--- /dev/null
+++ b/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.pool;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+
+public class ReferenceCountingExecutorServiceTest extends TestCase
+{
+
+
+ private ReferenceCountingExecutorService _executorService = ReferenceCountingExecutorService.getInstance(); // Class under test
+ private ThreadFactory _beforeExecutorThreadFactory;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _beforeExecutorThreadFactory = _executorService.getThreadFactory();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ _executorService.setThreadFactory(_beforeExecutorThreadFactory);
+ }
+
+
+
+ /**
+ * Tests that the ReferenceCountingExecutorService correctly manages the reference count.
+ */
+ public void testReferenceCounting() throws Exception
+ {
+ final int countBefore = _executorService.getReferenceCount();
+
+ try
+ {
+ _executorService.acquireExecutorService();
+ _executorService.acquireExecutorService();
+
+ assertEquals("Reference count should now be +2", countBefore + 2, _executorService.getReferenceCount());
+ }
+ finally
+ {
+ _executorService.releaseExecutorService();
+ _executorService.releaseExecutorService();
+ }
+ assertEquals("Reference count should have returned to the initial value", countBefore, _executorService.getReferenceCount());
+ }
+
+ /**
+ * Tests that the executor creates and executes a task using the default thread pool.
+ */
+ public void testExecuteCommandWithDefaultExecutorThreadFactory() throws Exception
+ {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Set<ThreadGroup> threadGroups = new HashSet<ThreadGroup>();
+
+ _executorService.acquireExecutorService();
+
+ try
+ {
+ _executorService.getPool().execute(createRunnable(latch, threadGroups));
+
+ latch.await(3, TimeUnit.SECONDS);
+
+ assertTrue("Expect that executor created a thread using default thread factory",
+ threadGroups.contains(Thread.currentThread().getThreadGroup()));
+ }
+ finally
+ {
+ _executorService.releaseExecutorService();
+ }
+ }
+
+ /**
+ * Tests that the executor creates and executes a task using an overridden thread pool.
+ */
+ public void testExecuteCommandWithOverriddenExecutorThreadFactory() throws Exception
+ {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ThreadGroup expectedThreadGroup = new ThreadGroup("junit");
+ _executorService.setThreadFactory(new ThreadGroupChangingThreadFactory(expectedThreadGroup));
+ _executorService.acquireExecutorService();
+
+ final Set<ThreadGroup> threadGroups = new HashSet<ThreadGroup>();
+
+ try
+ {
+ _executorService.getPool().execute(createRunnable(latch, threadGroups));
+
+ latch.await(3, TimeUnit.SECONDS);
+
+ assertTrue("Expect that executor created a thread using overridden thread factory",
+ threadGroups.contains(expectedThreadGroup));
+ }
+ finally
+ {
+ _executorService.releaseExecutorService();
+ }
+ }
+
+ private Runnable createRunnable(final CountDownLatch latch, final Set<ThreadGroup> threadGroups)
+ {
+ return new Runnable()
+ {
+
+ public void run()
+ {
+ threadGroups.add(Thread.currentThread().getThreadGroup());
+ latch.countDown();
+ }
+
+ };
+ }
+
+ private final class ThreadGroupChangingThreadFactory implements ThreadFactory
+ {
+ private final ThreadGroup _newGroup;
+
+ private ThreadGroupChangingThreadFactory(final ThreadGroup newGroup)
+ {
+ this._newGroup = newGroup;
+ }
+
+ public Thread newThread(Runnable r)
+ {
+ return new Thread(_newGroup, r);
+ }
+ }
+
+}
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java b/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
index 7f17592893..7b0f93700a 100644
--- a/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
+++ b/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
@@ -1,4 +1,3 @@
-package org.apache.qpid.thread;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,18 +19,22 @@ package org.apache.qpid.thread;
*
*/
+package org.apache.qpid.thread;
import junit.framework.TestCase;
+/**
+ * Tests the ThreadFactory.
+ */
public class ThreadFactoryTest extends TestCase
{
public void testThreadFactory()
{
- Class threadFactoryClass = null;
+ Class<? extends ThreadFactory> threadFactoryClass = null;
try
{
threadFactoryClass = Class.forName(System.getProperty("qpid.thread_factory",
- "org.apache.qpid.thread.DefaultThreadFactory"));
+ "org.apache.qpid.thread.DefaultThreadFactory")).asSubclass(ThreadFactory.class);
}
// If the thread factory class was wrong it will flagged way before it gets here.
catch(Exception e)
@@ -41,20 +44,19 @@ public class ThreadFactoryTest extends TestCase
assertEquals(threadFactoryClass, Threading.getThreadFactory().getClass());
}
-
- public void testThreadCreate()
+
+ /**
+ * Tests creating a thread without a priority. Also verifies that the factory sets the
+ * uncaught exception handler so uncaught exceptions are logged to SLF4J.
+ */
+ public void testCreateThreadWithDefaultPriority()
{
- Runnable r = new Runnable(){
-
- public void run(){
-
- }
- };
+ Runnable r = createRunnable();
Thread t = null;
try
{
- t = Threading.getThreadFactory().createThread(r,5);
+ t = Threading.getThreadFactory().createThread(r);
}
catch(Exception e)
{
@@ -62,6 +64,41 @@ public class ThreadFactoryTest extends TestCase
}
assertNotNull(t);
- assertEquals(5,t.getPriority());
+ assertEquals(Thread.NORM_PRIORITY, t.getPriority());
+ assertTrue(t.getUncaughtExceptionHandler() instanceof LoggingUncaughtExceptionHandler);
+ }
+
+ /**
+ * Tests creating thread with a priority. Also verifies that the factory sets the
+ * uncaught exception handler so uncaught exceptions are logged to SLF4J.
+ */
+ public void testCreateThreadWithSpecifiedPriority()
+ {
+ Runnable r = createRunnable();
+
+ Thread t = null;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r, 4);
+ }
+ catch(Exception e)
+ {
+ fail("Error creating thread using Qpid thread factory");
+ }
+
+ assertNotNull(t);
+ assertEquals(4, t.getPriority());
+ assertTrue(t.getUncaughtExceptionHandler() instanceof LoggingUncaughtExceptionHandler);
+ }
+
+ private Runnable createRunnable()
+ {
+ Runnable r = new Runnable(){
+
+ public void run(){
+
+ }
+ };
+ return r;
}
}
diff --git a/qpid/java/genpom b/qpid/java/genpom
index 92822a08ae..39eccd4c3e 100755
--- a/qpid/java/genpom
+++ b/qpid/java/genpom
@@ -32,9 +32,11 @@ parser.add_option("-a", "--artifact")
parser.add_option("-v", "--version")
parser.add_option("-d", "--description", default="")
parser.add_option("-u", "--url", default="")
-parser.add_option("-i", "--ignore", action="store_true", help="ignore missing poms")
+parser.add_option("-m", "--modules", help="modules dependencies")
+parser.add_option("-p", "--prefix", help="prefix of the project's artifacts names")
+parser.add_option("-i", "--ignore", action="store_true", help="ignore missing deps")
parser.add_option("-s", "--search-path", action="append",
- help="the path to search for poms")
+ help="the path to search for deps")
parser.add_option("-S", "--scope", metavar="ARTIFACT=SCOPE", action="append",
default=[],
help="specify scope for an artifact")
@@ -62,16 +64,18 @@ if opts.version is None:
if opts.name is None and opts.artifact is None:
die("one of name or artifact must be supplied")
+if opts.prefix is not None:
+ opts.artifact = opts.prefix + "-" + opts.artifact
+
if opts.name is None:
opts.name = opts.artifact
if opts.artifact is None:
opts.artifact = opts.name
-def lookup(pom, attr):
- nd = pom["project"][attr]
+def lookup(dep, attr):
+ nd = dep["dep"][attr]
if nd is None:
- nd = pom["project/parent"][attr]
if nd is None:
return None
return nd.text()
@@ -90,17 +94,35 @@ for s in opts.scope:
scopes[m.group(1)] = m.group(2)
deps = []
+module_depends = []
+if opts.modules is not None:
+ module_depends = opts.modules.replace("/", "-").split();
+
+for module in module_depends:
+ if opts.prefix is None:
+ artifactId = module
+ else:
+ artifactId = opts.prefix + "-" + module
+
+ deps.append("""
+ <dependency>
+ <groupId>%s</groupId>
+ <artifactId>%s</artifactId>
+ <version>%s</version>
+ </dependency>
+""" % (opts.group, artifactId, opts.version))
+
for jar in jars:
base, ext = os.path.splitext(os.path.basename(jar))
- pom = search(expanded_path, "%s.pom" % base)
- if pom is None:
+ dep = search(expanded_path, "%s.xml" % base)
+ if dep is None:
if opts.ignore:
continue
else:
- die("unable to locate pom for %s" % jar)
- group = lookup(pom, "groupId")
- artifactId = lookup(pom, "artifactId")
- version = lookup(pom, "version")
+ die("unable to locate xml for %s" % jar)
+ group = lookup(dep, "groupId")
+ artifactId = lookup(dep, "artifactId")
+ version = lookup(dep, "version")
deps.append("""
<dependency>
<groupId>%s</groupId>
@@ -119,22 +141,27 @@ TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<groupId>%(group)s</groupId>
<artifactId>%(artifact)s</artifactId>
<version>%(version)s</version>
+
<name>%(name)s</name>
<url>%(url)s</url>
<description>%(description)s</description>
+
<organization>
<name>The Apache Software Foundation</name>
<url>http://www.apache.org</url>
</organization>
+
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
</license>
</licenses>
+
<dependencies>
%(dependencies)s
</dependencies>
+
</project>
"""
diff --git a/qpid/java/lib/maven-ant-tasks-2.1.1.jar b/qpid/java/lib/maven-ant-tasks-2.1.1.jar
new file mode 100644
index 0000000000..7810a541b8
--- /dev/null
+++ b/qpid/java/lib/maven-ant-tasks-2.1.1.jar
Binary files differ
diff --git a/qpid/java/lib/poms/backport-util-concurrent-2.2.pom b/qpid/java/lib/poms/backport-util-concurrent-2.2.pom
deleted file mode 100644
index ea281da344..0000000000
--- a/qpid/java/lib/poms/backport-util-concurrent-2.2.pom
+++ /dev/null
@@ -1,25 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>backport-util-concurrent</groupId>
- <artifactId>backport-util-concurrent</artifactId>
- <version>2.2</version>
- <packaging>jar</packaging>
- <name>Backport of JSR 166</name>
- <url>http://www.mathcs.emory.edu/dcl/util/backport-util-concurrent/</url>
- <description>Dawid Kurzyniec's backport of JSR 166</description>
- <licenses>
- <license>
- <name>Public Domain</name>
- <url>http://creativecommons.org/licenses/publicdomain</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <url>http://dcl.mathcs.emory.edu/cgi-bin/viewcvs.cgi/software/util/backport-util-concurrent/</url>
- </scm>
- <organization>
- <name>Dawid Kurzyniec</name>
- <url>http://www.mathcs.emory.edu/~dawidk/</url>
- </organization>
- <dependencies/>
-</project>
diff --git a/qpid/java/lib/poms/backport-util-concurrent-2.2.xml b/qpid/java/lib/poms/backport-util-concurrent-2.2.xml
new file mode 100644
index 0000000000..6df4cfca40
--- /dev/null
+++ b/qpid/java/lib/poms/backport-util-concurrent-2.2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>backport-util-concurrent</groupId>
+ <artifactId>backport-util-concurrent</artifactId>
+ <version>2.2</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-beanutils-core-1.8.0.pom b/qpid/java/lib/poms/commons-beanutils-core-1.8.0.xml
index 30d29c9048..612b45e1a6 100644
--- a/qpid/java/lib/poms/commons-beanutils-core-1.8.0.pom
+++ b/qpid/java/lib/poms/commons-beanutils-core-1.8.0.xml
@@ -1,42 +1,22 @@
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<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>
- <parent>
- <groupId>org.apache</groupId>
- <artifactId>apache</artifactId>
- <version>4</version>
- </parent>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils-core</artifactId>
- <version>1.8.0</version>
- <name>Commons BeanUtils Core</name>
- <url>http://commons.apache.org/beanutils/</url>
-
- <dependencies>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.1.1</version>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils-core</artifactId>
+ <version>1.8.0</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-cli-1.0.pom b/qpid/java/lib/poms/commons-cli-1.0.pom
deleted file mode 100644
index cfc5a04d78..0000000000
--- a/qpid/java/lib/poms/commons-cli-1.0.pom
+++ /dev/null
@@ -1,76 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-cli</groupId>
- <artifactId>commons-cli</artifactId>
- <name>CLI</name>
- <version>1.0</version>
- <description>Commons CLI provides a simple API for working with the command line arguments and options.</description>
- <inceptionYear>2002</inceptionYear>
- <developers>
- <developer>
- <id>jstrachan</id>
- <name>James Strachan</name>
- <email>jstrachan@apache.org</email>
- <organization>SpiritSoft, Inc.</organization>
- </developer>
- <developer>
- <id>bob</id>
- <name>bob mcwhirter</name>
- <email>bob@werken.com</email>
- <organization>Werken</organization>
- </developer>
- <developer>
- <id>jkeyes</id>
- <name>John Keyes</name>
- <email>jbjk@mac.com</email>
- <organization>integral Source</organization>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>Berin Loritsch</name>
- <email>bloritsch@apache.org</email>
- <roles>
- <role>helped in the Avalon CLI merge</role>
- </roles>
- </contributor>
- <contributor>
- <name>Peter Maddocks</name>
- <email>peter_maddocks@hp.com</email>
- <organization>Hewlett-Packard</organization>
- <roles>
- <role>supplied patch</role>
- </roles>
- </contributor>
- </contributors>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/*Test*.java</include>
- </includes>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.0</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>1.0</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.7</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-cli-1.0.xml b/qpid/java/lib/poms/commons-cli-1.0.xml
new file mode 100644
index 0000000000..77b47f63f1
--- /dev/null
+++ b/qpid/java/lib/poms/commons-cli-1.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.0</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-codec-1.3.pom b/qpid/java/lib/poms/commons-codec-1.3.pom
deleted file mode 100644
index dab16e299b..0000000000
--- a/qpid/java/lib/poms/commons-codec-1.3.pom
+++ /dev/null
@@ -1,178 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <name>Codec</name>
- <version>1.3</version>
- <description>The codec package contains simple encoder and decoders for
- various formats such as Base64 and Hexadecimal. In addition to these
- widely used encoders and decoders, the codec package also maintains a
- collection of phonetic encoding utilities.</description>
- <url>http://jakarta.apache.org/commons/codec/</url>
- <issueManagement>
- <url>http://nagoya.apache.org/bugzilla/buglist.cgi?bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;email1=&amp;emailtype1=substring&amp;emailassigned_to1=1&amp;email2=&amp;emailtype2=substring&amp;emailreporter2=1&amp;bugidtype=include&amp;bug_id=&amp;changedin=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;product=Commons&amp;component=Codec&amp;short_desc=&amp;short_desc_type=allwordssubstr&amp;long_desc=&amp;long_desc_type=allwordssubstr&amp;bug_file_loc=&amp;bug_file_loc_type=allwordssubstr&amp;keywords=&amp;keywords_type=anywords&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;cmdtype=doit&amp;newqueryname=&amp;order=Reuse+same+sort+as+last+time</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <address>commons-dev@jakarta.apache.org</address>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2002</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>bayard</id>
- <name>Henri Yandell</name>
- <email>bayard@generationjava.com</email>
- </developer>
- <developer>
- <id>tobrien</id>
- <name>Tim OBrien</name>
- <email>tobrien@apache.org</email>
- <timezone>-6</timezone>
- </developer>
- <developer>
- <id>sanders</id>
- <name>Scott Sanders</name>
- <email>sanders@totalsync.com</email>
- </developer>
- <developer>
- <id>rwaldhoff</id>
- <name>Rodney Waldhoff</name>
- <email>rwaldhoff@apache.org</email>
- </developer>
- <developer>
- <id>dlr</id>
- <name>Daniel Rall</name>
- <email>dlr@finemaltcoding.com</email>
- </developer>
- <developer>
- <id>jon</id>
- <name>Jon S. Stevens</name>
- <email>jon@collab.net</email>
- </developer>
- <developer>
- <id>ggregory</id>
- <name>Gary D. Gregory</name>
- <email>ggregory@seagullsw.com</email>
- <organization>Seagull Software</organization>
- <timezone>-8</timezone>
- </developer>
- <developer>
- <id>dgraham</id>
- <name>David Graham</name>
- <email>dgraham@apache.org</email>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>Christopher O'Brien</name>
- <email>siege@preoccupied.net</email>
- </contributor>
- <contributor>
- <name>Martin Redington</name>
- </contributor>
- <contributor>
- <name>Jeffery Dever</name>
- </contributor>
- <contributor>
- <name>Steve Zimmermann</name>
- <email>steve.zimmermann@heii.com</email>
- </contributor>
- <contributor>
- <name>Benjamin Walstrum</name>
- <email>ben@walstrum.com</email>
- </contributor>
- <contributor>
- <name>Oleg Kalnichevski</name>
- <email>oleg@ural.ru</email>
- </contributor>
- <contributor>
- <name>Dave Dribin</name>
- <email>apache@dave.dribin.org</email>
- </contributor>
- <contributor>
- <name>Alex Karasulu</name>
- <email>aok123 at bellsouth.net</email>
- </contributor>
- <contributor>
- <name>Matthew Inger</name>
- <email>mattinger at yahoo.com</email>
- </contributor>
- </contributors>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/codec</connection>
- <url>http://cvs.apache.org/viewcvs/jakarta-commons/codec/</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://jakarta.apache.org</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <testResources>
- <testResource>
- <directory>src/test</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </testResource>
- </testResources>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/Test*.java</include>
- <include>**/*Test.java</include>
- </includes>
- <excludes>
- <exclude>**/*AbstractTest.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>file:///www/jakarta.apache.org/builds/jakarta-commons/codec/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://jakarta.apache.org//www/jakarta.apache.org/commons/codec/</url>
- </site>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-codec-1.3.xml b/qpid/java/lib/poms/commons-codec-1.3.xml
new file mode 100644
index 0000000000..772ff6ab71
--- /dev/null
+++ b/qpid/java/lib/poms/commons-codec-1.3.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.3</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-collections-3.2.pom b/qpid/java/lib/poms/commons-collections-3.2.pom
deleted file mode 100644
index 88e5860df3..0000000000
--- a/qpid/java/lib/poms/commons-collections-3.2.pom
+++ /dev/null
@@ -1,420 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- <name>Collections</name>
- <version>3.2</version>
- <description>Types that extend and augment the Java Collections Framework.</description>
- <url>http://jakarta.apache.org/commons/collections/</url>
- <issueManagement>
- <url>http://issues.apache.org/bugzilla/</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <configuration>
- <address>commons-dev@jakarta.apache.org</address>
- </configuration>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2001</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>scolebourne</id>
- <name>Stephen Colebourne</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>morgand</id>
- <name>Morgan Delagrange</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>matth</id>
- <name>Matthew Hawthorne</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>geirm</id>
- <name>Geir Magnusson</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>craigmcc</id>
- <name>Craig McClanahan</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>psteitz</id>
- <name>Phil Steitz</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>amamment</id>
- <name>Arun M. Thomas</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>rwaldhoff</id>
- <name>Rodney Waldhoff</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>bayard</id>
- <name>Henri Yandell</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>jcarman</id>
- <name>James Carman</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>rdonkin</id>
- <name>Robert Burrell Donkin</name>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>Rafael U. C. Afonso</name>
- </contributor>
- <contributor>
- <name>Max Rydahl Andersen</name>
- </contributor>
- <contributor>
- <name>Federico Barbieri</name>
- </contributor>
- <contributor>
- <name>Arron Bates</name>
- </contributor>
- <contributor>
- <name>Nicola Ken Barozzi</name>
- </contributor>
- <contributor>
- <name>Sebastian Bazley</name>
- </contributor>
- <contributor>
- <name>Matt Benson</name>
- </contributor>
- <contributor>
- <name>Ola Berg</name>
- </contributor>
- <contributor>
- <name>Christopher Berry</name>
- </contributor>
- <contributor>
- <name>Nathan Beyer</name>
- </contributor>
- <contributor>
- <name>Janek Bogucki</name>
- </contributor>
- <contributor>
- <name>Chuck Burdick</name>
- </contributor>
- <contributor>
- <name>Dave Bryson</name>
- </contributor>
- <contributor>
- <name>Julien Buret</name>
- </contributor>
- <contributor>
- <name>Jonathan Carlson</name>
- </contributor>
- <contributor>
- <name>Ram Chidambaram</name>
- </contributor>
- <contributor>
- <name>Steve Clark</name>
- </contributor>
- <contributor>
- <name>Eric Crampton</name>
- </contributor>
- <contributor>
- <name>Dimiter Dimitrov</name>
- </contributor>
- <contributor>
- <name>Peter Donald</name>
- </contributor>
- <contributor>
- <name>Steve Downey</name>
- </contributor>
- <contributor>
- <name>Rich Dougherty</name>
- </contributor>
- <contributor>
- <name>Tom Dunham</name>
- </contributor>
- <contributor>
- <name>Stefano Fornari</name>
- </contributor>
- <contributor>
- <name>Andrew Freeman</name>
- </contributor>
- <contributor>
- <name>Gerhard Froehlich</name>
- </contributor>
- <contributor>
- <name>Paul Jack</name>
- </contributor>
- <contributor>
- <name>Eric Johnson</name>
- </contributor>
- <contributor>
- <name>Kent Johnson</name>
- </contributor>
- <contributor>
- <name>Marc Johnson</name>
- </contributor>
- <contributor>
- <name>Nissim Karpenstein</name>
- </contributor>
- <contributor>
- <name>Shinobu Kawai</name>
- </contributor>
- <contributor>
- <name>Mohan Kishore</name>
- </contributor>
- <contributor>
- <name>Simon Kitching</name>
- </contributor>
- <contributor>
- <name>Thomas Knych</name>
- </contributor>
- <contributor>
- <name>Serge Knystautas</name>
- </contributor>
- <contributor>
- <name>Peter KoBek</name>
- </contributor>
- <contributor>
- <name>Jordan Krey</name>
- </contributor>
- <contributor>
- <name>Olaf Krische</name>
- </contributor>
- <contributor>
- <name>Guilhem Lavaux</name>
- </contributor>
- <contributor>
- <name>Paul Legato</name>
- </contributor>
- <contributor>
- <name>David Leppik</name>
- </contributor>
- <contributor>
- <name>Berin Loritsch</name>
- </contributor>
- <contributor>
- <name>Stefano Mazzocchi</name>
- </contributor>
- <contributor>
- <name>Brian McCallister</name>
- </contributor>
- <contributor>
- <name>Steven Melzer</name>
- </contributor>
- <contributor>
- <name>Leon Messerschmidt</name>
- </contributor>
- <contributor>
- <name>Mauricio S. Moura</name>
- </contributor>
- <contributor>
- <name>Kasper Nielsen</name>
- </contributor>
- <contributor>
- <name>Stanislaw Osinski</name>
- </contributor>
- <contributor>
- <name>Alban Peignier</name>
- </contributor>
- <contributor>
- <name>Mike Pettypiece</name>
- </contributor>
- <contributor>
- <name>Steve Phelps</name>
- </contributor>
- <contributor>
- <name>Ilkka Priha</name>
- </contributor>
- <contributor>
- <name>Jonas Van Poucke</name>
- </contributor>
- <contributor>
- <name>Will Pugh</name>
- </contributor>
- <contributor>
- <name>Herve Quiroz</name>
- </contributor>
- <contributor>
- <name>Daniel Rall</name>
- </contributor>
- <contributor>
- <name>Robert Ribnitz</name>
- </contributor>
- <contributor>
- <name>Huw Roberts</name>
- </contributor>
- <contributor>
- <name>Henning P. Schmiedehausen</name>
- </contributor>
- <contributor>
- <name>Howard Lewis Ship</name>
- </contributor>
- <contributor>
- <name>Joe Raysa</name>
- </contributor>
- <contributor>
- <name>Thomas Schapitz</name>
- </contributor>
- <contributor>
- <name>Jon Schewe</name>
- </contributor>
- <contributor>
- <name>Andreas Schlosser</name>
- </contributor>
- <contributor>
- <name>Christian Siefkes</name>
- </contributor>
- <contributor>
- <name>Michael Smith</name>
- </contributor>
- <contributor>
- <name>Stephen Smith</name>
- </contributor>
- <contributor>
- <name>Jan Sorensen</name>
- </contributor>
- <contributor>
- <name>Jon S. Stevens</name>
- </contributor>
- <contributor>
- <name>James Strachan</name>
- </contributor>
- <contributor>
- <name>Leo Sutic</name>
- </contributor>
- <contributor>
- <name>Chris Tilden</name>
- </contributor>
- <contributor>
- <name>Neil O'Toole</name>
- </contributor>
- <contributor>
- <name>Jeff Turner</name>
- </contributor>
- <contributor>
- <name>Kazuya Ujihara</name>
- </contributor>
- <contributor>
- <name>Jeff Varszegi</name>
- </contributor>
- <contributor>
- <name>Ralph Wagner</name>
- </contributor>
- <contributor>
- <name>David Weinrich</name>
- </contributor>
- <contributor>
- <name>Dieter Wimberger</name>
- </contributor>
- <contributor>
- <name>Serhiy Yevtushenko</name>
- </contributor>
- <contributor>
- <name>Jason van Zyl</name>
- </contributor>
- </contributors>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk</connection>
- <url>http://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://jakarta.apache.org</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <resources>
- <resource>
- <targetPath>META-INF</targetPath>
- <directory>.</directory>
- <includes>
- <include>NOTICE.txt</include>
- </includes>
- </resource>
- </resources>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>org/apache/commons/collections/TestAllPackages.java</include>
- </includes>
- </configuration>
- </plugin>
- <plugin>
- <groupId>maven-plugins</groupId>
- <artifactId>maven-cobertura-plugin</artifactId>
- <version>1.1.1</version>
- <configuration>
- <scope>test</scope>
- <comment>Required only for generating test coverage reports.</comment>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>file:///www/jakarta.apache.org/builds/jakarta-commons/collections/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://people.apache.org//www/jakarta.apache.org/commons/collections/</url>
- </site>
- <status>converted</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-collections-3.2.xml b/qpid/java/lib/poms/commons-collections-3.2.xml
new file mode 100644
index 0000000000..3a07dc4a9d
--- /dev/null
+++ b/qpid/java/lib/poms/commons-collections-3.2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-configuration-1.6.pom b/qpid/java/lib/poms/commons-configuration-1.6.pom
deleted file mode 100644
index 1597869b3a..0000000000
--- a/qpid/java/lib/poms/commons-configuration-1.6.pom
+++ /dev/null
@@ -1,419 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-configuration</groupId>
- <artifactId>commons-configuration</artifactId>
- <name>Commons Configuration</name>
- <version>1.6</version>
- <description>Tools to assist in the reading of configuration/preferences files in
- various formats</description>
- <url>http://commons.apache.org/${pom.artifactId.substring(8)}/</url>
- <issueManagement>
- <url>http://issues.apache.org/jira/browse/CONFIGURATION</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <configuration>
- <address>dev@commons.apache.org</address>
- </configuration>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2001</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>dev-subscribe@commons.apache.org</subscribe>
- <unsubscribe>dev-unsubscribe@commons.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/mod_mbox/commons-dev/</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>user-subscribe@commons.apache.org</subscribe>
- <unsubscribe>user-unsubscribe@commons.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/mod_mbox/commons-user/</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>dlr</id>
- <name>Daniel Rall</name>
- <email>dlr@finemaltcoding.com</email>
- <organization>CollabNet, Inc.</organization>
- </developer>
- <developer>
- <id>jvanzyl</id>
- <name>Jason van Zyl</name>
- <email>jason@zenplex.com</email>
- <organization>Zenplex</organization>
- </developer>
- <developer>
- <id>mpoeschl</id>
- <name>Martin Poeschl</name>
- <email>mpoeschl@marmot.at</email>
- <organization>tucana.at</organization>
- </developer>
- <developer>
- <id>dion</id>
- <name>dIon Gillard</name>
- <email>dion@multitask.com.au</email>
- <organization>Multitask Consulting</organization>
- </developer>
- <developer>
- <id>henning</id>
- <name>Henning P. Schmiedehausen</name>
- <email>hps@intermeta.de</email>
- <organization>INTERMETA - Gesellschaft fuer Mehrwertdienste mbH</organization>
- <timezone>2</timezone>
- </developer>
- <developer>
- <id>epugh</id>
- <name>Eric Pugh</name>
- <email>epugh@upstate.com</email>
- <organization>upstate.com</organization>
- </developer>
- <developer>
- <id>bdunbar</id>
- <name>Brian E. Dunbar</name>
- <email>bdunbar@dunbarconsulting.org</email>
- <organization>dunbarconsulting.org</organization>
- </developer>
- <developer>
- <id>ebourg</id>
- <name>Emmanuel Bourg</name>
- <email>ebourg@apache.org</email>
- <organization>Ariane Software</organization>
- <timezone>+1</timezone>
- </developer>
- <developer>
- <id>oheger</id>
- <name>Oliver Heger</name>
- <email>oheger@apache.org</email>
- <organization>Agfa HealthCare</organization>
- <timezone>+1</timezone>
- </developer>
- <developer>
- <id>joehni</id>
- <name>Jörg Schaible</name>
- <email>joerg.schaible@gmx.de</email>
- <timezone>+1</timezone>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>Konstantin Shaposhnikov</name>
- <email>ksh@scand.com</email>
- <organization>scand.com</organization>
- </contributor>
- <contributor>
- <name>Jamie M. Guillemette</name>
- <email>JMGuillemette@gmail.com</email>
- <organization>TD Bank</organization>
- </contributor>
- <contributor>
- <name>Jorge Ferrer</name>
- <email>jorge.ferrer@gmail.com</email>
- <organization></organization>
- </contributor>
- <contributor>
- <name>Gabriele Garuglieri</name>
- <email>gabriele.garuglieri@infoblu.it</email>
- <organization>Infoblu S.p.A</organization>
- </contributor>
- <contributor>
- <name>Nicolas De Loof</name>
- <email>nicolas.deloof@gmail.com</email>
- <organization>Cap Gemini</organization>
- </contributor>
- </contributors>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/${pom.artifactId.substring(8)}/trunk</connection>
- <url>http://svn.apache.org/repos/asf/commons/proper/${pom.artifactId.substring(8)}/trunk</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://commons.apache.org/</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <resources>
- <resource>
- <directory>conf</directory>
- <includes>
- <include>digesterRules.xml</include>
- <include>properties.dtd</include>
- <include>PropertyList-1.0.dtd</include>
- </includes>
- </resource>
- <resource>
- <targetPath>META-INF</targetPath>
- <directory>${basedir}</directory>
- <includes>
- <include>NOTICE.txt</include>
- </includes>
- </resource>
- </resources>
- <testResources>
- <testResource>
- <directory>conf</directory>
- <includes>
- <include>*.xml</include>
- </includes>
- </testResource>
- <testResource>
- <directory>conf</directory>
- <includes>
- <include>testClasspath.properties</include>
- <include>testdb.script</include>
- <include>*.properties</include>
- <include>*.dtd</include>
- </includes>
- </testResource>
- <testResource>
- <targetPath>org/apache/commons/configuration</targetPath>
- <directory>conf</directory>
- <includes>
- <include>test.properties</include>
- <include>include.properties</include>
- </includes>
- </testResource>
- <testResource>
- <targetPath>config</targetPath>
- <directory>conf/config</directory>
- <includes>
- <include>**/*.properties</include>
- </includes>
- </testResource>
- </testResources>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/*Test*.java</include>
- </includes>
- <excludes>
- <exclude>**/TestBasePropertiesConfiguration.java</exclude>
- <exclude>**/NonStringTestHolder.java</exclude>
- <exclude>**/TestAbstractConfiguration.java</exclude>
- <exclude>**/AbstractXPathTest.java</exclude>
- <exclude>**/AbstractCombinerTest.java</exclude>
- <exclude>**/AbstractTestConfigurationEvents.java</exclude>
- <exclude>**/AbstractTestFileConfigurationEvents.java</exclude>
- <exclude>**/AbstractTestPListEvents.java</exclude>
- <exclude>**/InterpolationTestHelper.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- <plugin>
- <groupId>maven-plugins</groupId>
- <artifactId>maven-tasks-plugin</artifactId>
- <version>1.1.0</version>
- <configuration />
- </plugin>
- <plugin>
- <groupId>maven-plugins</groupId>
- <artifactId>maven-findbugs-plugin</artifactId>
- <version>1.4</version>
- <configuration />
- </plugin>
- <plugin>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <version>3.0.1</version>
- <configuration />
- </plugin>
- <plugin>
- <groupId>maven-plugins</groupId>
- <artifactId>maven-cobertura-plugin</artifactId>
- <version>1.2</version>
- <configuration />
- </plugin>
- <plugin>
- <artifactId>maven-changes-plugin</artifactId>
- <version>1.6</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.6 (minimum)
- required for building the site documentation.</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-xdoc-plugin</artifactId>
- <version>1.8</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.8 (minimum)
- required for building the site documentation.</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-scm-plugin</artifactId>
- <version>1.5</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-jdiff-plugin</artifactId>
- <version>1.5</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>1.8</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.8 (minimum)</comment>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- <version>3.2.1</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>commons-digester</groupId>
- <artifactId>commons-digester</artifactId>
- <version>1.8</version>
- </dependency>
- <dependency>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils-core</artifactId>
- <version>1.8.0</version>
- </dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.3</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>commons-jxpath</groupId>
- <artifactId>commons-jxpath</artifactId>
- <version>1.3</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.3.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>xalan</groupId>
- <artifactId>xalan</artifactId>
- <version>2.7.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>1.0.b2</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant</artifactId>
- <version>1.6.5</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>commons-dbcp</groupId>
- <artifactId>commons-dbcp</artifactId>
- <version>1.2.2</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>commons-pool</groupId>
- <artifactId>commons-pool</artifactId>
- <version>1.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>hsqldb</groupId>
- <artifactId>hsqldb</artifactId>
- <version>1.7.2.2</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>dbunit</groupId>
- <artifactId>dbunit</artifactId>
- <version>2.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit-addons</groupId>
- <artifactId>junit-addons</artifactId>
- <version>1.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>mockobjects</groupId>
- <artifactId>mockobjects-core</artifactId>
- <version>0.09</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>mockobjects</groupId>
- <artifactId>mockobjects-jdk1.4-j2ee1.3</artifactId>
- <version>0.09</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.8</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>www.apache.org//www/www.apache.org/dist/java-repository/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://people.apache.org//www/commons.apache.org/${pom.artifactId.substring(8)}/</url>
- </site>
- <status>converted</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-configuration-1.6.xml b/qpid/java/lib/poms/commons-configuration-1.6.xml
new file mode 100644
index 0000000000..523310f10a
--- /dev/null
+++ b/qpid/java/lib/poms/commons-configuration-1.6.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-configuration</groupId>
+ <artifactId>commons-configuration</artifactId>
+ <version>1.6</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-digester-1.8.1.pom b/qpid/java/lib/poms/commons-digester-1.8.1.pom
deleted file mode 100644
index 5470526527..0000000000
--- a/qpid/java/lib/poms/commons-digester-1.8.1.pom
+++ /dev/null
@@ -1,316 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<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">
-
-<!-- TODO:
-* include dtds as resources
-* build src jars
--->
-
- <parent>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-parent</artifactId>
- <version>11</version>
- </parent>
-
- <modelVersion>4.0.0</modelVersion>
- <name>Commons Digester</name>
- <groupId>commons-digester</groupId>
- <artifactId>commons-digester</artifactId>
- <version>1.8.1</version>
-
- <inceptionYear>2001</inceptionYear>
- <description>
- The Digester package lets you configure an XML to Java object mapping module
- which triggers certain actions called rules whenever a particular
- pattern of nested XML elements is recognized.
- </description>
-
- <url>http://commons.apache.org/digester/</url>
-
- <issueManagement>
- <system>jira</system>
- <url>http://issues.apache.org/jira/browse/DIGESTER</url>
- </issueManagement>
-
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/digester/tags/DIGESTER_1_8_1</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/digester/tags/DIGESTER_1_8_1</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/digester/tags/DIGESTER_1_8_1</url>
- </scm>
-
- <developers>
- <developer>
- <name>Craig McClanahan</name>
- <id>craigmcc</id>
- <email>craigmcc@apache.org</email>
- </developer>
- <developer>
- <name>Robert Burrell Donkin</name>
- <id>rdonkin</id>
- <email>rdonkin@apache.org</email>
- </developer>
- <developer>
- <name>Scott Sanders</name>
- <id>sanders</id>
- <email>sanders@totalsync.com</email>
- </developer>
- <developer>
- <name>James Strachan</name>
- <id>jstrachan</id>
- <email>jstrachan@apache.org</email>
- </developer>
- <developer>
- <name>Jason van Zyl</name>
- <id>jvanzyl</id>
- <email>jvanzyl@apache.org</email>
- </developer>
- <developer>
- <name>Tim OBrien</name>
- <id>tobrien</id>
- <email>tobrien@apache.org</email>
- </developer>
- <developer>
- <name>Jean-Francois Arcand</name>
- <id>jfarcand</id>
- <email>jfarcand@apache.org</email>
- </developer>
- <developer>
- <name>Simon Kitching</name>
- <id>skitching</id>
- <email>skitching@apache.org</email>
- </developer>
- <developer>
- <name>Rahul Akolkar</name>
- <id>rahul</id>
- <email>rahul AT apache DOT org</email>
- </developer>
- </developers>
-
- <contributors>
- <contributor>
- <name>Bradley M. Handy</name>
- <email>bhandy@users.sf.net</email>
- </contributor>
- <contributor>
- <name>Christopher Lenz</name>
- </contributor>
- <contributor>
- <name>Ted Husted</name>
- </contributor>
- <contributor>
- <name>David H. Martin</name>
- </contributor>
- <contributor>
- <name>Henri Chen</name>
- </contributor>
- <contributor>
- <name>Janek Bogucki</name>
- </contributor>
- <contributor>
- <name>Mark Huisman</name>
- </contributor>
- <contributor>
- <name>Paul Jack</name>
- </contributor>
- <contributor>
- <name>Anton Maslovsky</name>
- </contributor>
- <contributor>
- <name>Matt Cleveland</name>
- </contributor>
- <contributor>
- <name>Gabriele Carcassi</name>
- </contributor>
- <contributor>
- <name>Wendy Smoak</name>
- <email>java@wendysmoak.com</email>
- </contributor>
- <contributor>
- <name>Kevin Ross</name>
- <email>kevin.ross@iverticalleap.com</email>
- </contributor>
- </contributors>
-
- <distributionManagement>
- <!-- Cannot define in parent ATM, see COMMONSSITE-26 -->
- <site>
- <id>apache.website</id>
- <name>Apache Commons Site</name>
- <url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/digester</url>
- </site>
- </distributionManagement>
-
- <properties>
- <maven.compile.source>1.2</maven.compile.source>
- <maven.compile.target>1.2</maven.compile.target>
- <commons.componentid>digester</commons.componentid>
- <commons.release.version>1.8.1</commons.release.version>
- <commons.rc.version>RC1</commons.rc.version>
- <commons.jira.id>DIGESTER</commons.jira.id>
- <commons.jira.pid>12310471</commons.jira.pid>
- </properties>
-
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
-
- <resources>
- <resource>
- <directory>.</directory>
- <targetPath>META-INF</targetPath>
- <includes>
- <include>NOTICE.txt</include>
- <include>LICENSE.txt</include>
- </includes>
- </resource>
- <resource>
- <directory>src/java</directory>
- <filtering>false</filtering>
- <includes>
- <include>**/*.dtd</include>
- </includes>
- </resource>
- </resources>
-
- <testResources>
- <testResource>
- <directory>src/test</directory>
- <filtering>false</filtering>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </testResource>
- </testResources>
-
- <plugins>
- <plugin>
- <!--
- - A number of the pre-maven test case "suport" classes have names starting with Test.
- - This confuses the maven surefire "auto-detect test case" functionality, so we
- - need to manually exclude them.
- -->
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludes>
- <exclude>**/TestBean.java</exclude>
- <exclude>**/TestRule.java</exclude>
- <exclude>**/TestRuleSet.java</exclude>
- <exclude>**/Test*$*.java</exclude>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <configuration>
- <descriptors>
- <descriptor>src/assembly/bin.xml</descriptor>
- <descriptor>src/assembly/src.xml</descriptor>
- </descriptors>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils</artifactId>
- <version>1.8.0</version>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>1.0.b2</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-changes-plugin</artifactId>
- <version>2.0</version>
- <configuration>
- <issueLinkTemplate>%URL%/../%ISSUE%</issueLinkTemplate>
- </configuration>
- <reportSets>
- <reportSet>
- <reports>
- <report>changes-report</report>
- <report>jira-report</report>
- </reports>
- </reportSet>
- </reportSets>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <version>2.1</version>
- <configuration>
- <configLocation>${basedir}/checkstyle.xml</configLocation>
- <enableRulesSummary>false</enableRulesSummary>
- <headerFile>${basedir}/file-header.txt</headerFile>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-pmd-plugin</artifactId>
- <version>2.3</version>
- <!--Use default rules-->
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>2.2.1</version>
- <configuration>
- <comparisonVersion>1.8</comparisonVersion>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
-
- <profiles>
- <profile>
- <id>rc</id>
- <distributionManagement>
- <!-- Cannot define in parent ATM, see COMMONSSITE-26 -->
- <site>
- <id>apache.website</id>
- <name>Apache Commons Release Candidate Staging Site</name>
- <url>${commons.deployment.protocol}://people.apache.org/www/people.apache.org/builds/commons/${commons.componentid}/${commons.release.version}/${commons.rc.version}/site</url>
- </site>
- </distributionManagement>
- </profile>
- </profiles>
-
-</project>
diff --git a/qpid/java/lib/poms/commons-digester-1.8.1.xml b/qpid/java/lib/poms/commons-digester-1.8.1.xml
new file mode 100644
index 0000000000..1edee7b5f0
--- /dev/null
+++ b/qpid/java/lib/poms/commons-digester-1.8.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-digester</groupId>
+ <artifactId>commons-digester</artifactId>
+ <version>1.8.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-lang-2.2.pom b/qpid/java/lib/poms/commons-lang-2.2.pom
deleted file mode 100644
index 9337a4374b..0000000000
--- a/qpid/java/lib/poms/commons-lang-2.2.pom
+++ /dev/null
@@ -1,414 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <name>Lang</name>
- <version>2.2</version>
- <description>Commons.Lang, a package of Java utility classes for the
- classes that are in java.lang's hierarchy, or are considered to be so
- standard as to justify existence in java.lang.</description>
- <url>http://jakarta.apache.org/commons/lang/</url>
- <issueManagement>
- <url>http://issues.apache.org/jira/</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <configuration>
- <address>commons-dev@jakarta.apache.org</address>
- </configuration>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2001</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>dlr</id>
- <name>Daniel Rall</name>
- <email>dlr@finemaltcoding.com</email>
- <organization>CollabNet, Inc.</organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>scolebourne</id>
- <name>Stephen Colebourne</name>
- <email>scolebourne@joda.org</email>
- <organization>SITA ATS Ltd</organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- <timezone>0</timezone>
- </developer>
- <developer>
- <id>bayard</id>
- <name>Henri Yandell</name>
- <email>bayard@generationjava.com</email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>scaswell</id>
- <name>Steven Caswell</name>
- <email>stevencaswell@apache.org</email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- <timezone>-5</timezone>
- </developer>
- <developer>
- <id>rdonkin</id>
- <name>Robert Burrell Donkin</name>
- <email>rdonkin@apache.org</email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>ggregory</id>
- <name>Gary D. Gregory</name>
- <email>ggregory@seagullsw.com</email>
- <organization>Seagull Software</organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- <timezone>-8</timezone>
- </developer>
- <developer>
- <id>psteitz</id>
- <name>Phil Steitz</name>
- <email>phil@steitz.com</email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>fredrik</id>
- <name>Fredrik Westermarck</name>
- <email></email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>jcarman</id>
- <name>James Carman</name>
- <email>jcarman@apache.org</email>
- <organization>Carman Consulting, Inc.</organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>C. Scott Ananian</name>
- </contributor>
- <contributor>
- <name>Chris Audley</name>
- </contributor>
- <contributor>
- <name>Stephane Bailliez</name>
- </contributor>
- <contributor>
- <name>Michael Becke</name>
- </contributor>
- <contributor>
- <name>Ola Berg</name>
- </contributor>
- <contributor>
- <name>Nathan Beyer</name>
- </contributor>
- <contributor>
- <name>Stefan Bodewig</name>
- </contributor>
- <contributor>
- <name>Janek Bogucki</name>
- </contributor>
- <contributor>
- <name>Mike Bowler</name>
- </contributor>
- <contributor>
- <name>Sean Brown</name>
- </contributor>
- <contributor>
- <name>Alexander Day Chaffee</name>
- </contributor>
- <contributor>
- <name>Al Chou</name>
- </contributor>
- <contributor>
- <name>Greg Coladonato</name>
- </contributor>
- <contributor>
- <name>Maarten Coene</name>
- </contributor>
- <contributor>
- <name>Justin Couch</name>
- </contributor>
- <contributor>
- <name>Michael Davey</name>
- </contributor>
- <contributor>
- <name>Norm Deane</name>
- </contributor>
- <contributor>
- <name>Ringo De Smet</name>
- </contributor>
- <contributor>
- <name>Russel Dittmar</name>
- </contributor>
- <contributor>
- <name>Steve Downey</name>
- </contributor>
- <contributor>
- <name>Matthias Eichel</name>
- </contributor>
- <contributor>
- <name>Christopher Elkins</name>
- </contributor>
- <contributor>
- <name>Chris Feldhacker</name>
- </contributor>
- <contributor>
- <name>Pete Gieser</name>
- </contributor>
- <contributor>
- <name>Jason Gritman</name>
- </contributor>
- <contributor>
- <name>Matthew Hawthorne</name>
- </contributor>
- <contributor>
- <name>Michael Heuer</name>
- </contributor>
- <contributor>
- <name>Oliver Heger</name>
- </contributor>
- <contributor>
- <name>Chris Hyzer</name>
- </contributor>
- <contributor>
- <name>Marc Johnson</name>
- </contributor>
- <contributor>
- <name>Shaun Kalley</name>
- </contributor>
- <contributor>
- <name>Tetsuya Kaneuchi</name>
- </contributor>
- <contributor>
- <name>Nissim Karpenstein</name>
- </contributor>
- <contributor>
- <name>Ed Korthof</name>
- </contributor>
- <contributor>
- <name>Holger Krauth</name>
- </contributor>
- <contributor>
- <name>Rafal Krupinski</name>
- </contributor>
- <contributor>
- <name>Rafal Krzewski</name>
- </contributor>
- <contributor>
- <name>Craig R. McClanahan</name>
- </contributor>
- <contributor>
- <name>Rand McNeely</name>
- </contributor>
- <contributor>
- <name>Nikolay Metchev</name>
- </contributor>
- <contributor>
- <name>Kasper Nielsen</name>
- </contributor>
- <contributor>
- <name>Tim O'Brien</name>
- </contributor>
- <contributor>
- <name>Brian S O'Neill</name>
- </contributor>
- <contributor>
- <name>Andrew C. Oliver</name>
- </contributor>
- <contributor>
- <name>Alban Peignier</name>
- </contributor>
- <contributor>
- <name>Moritz Petersen</name>
- </contributor>
- <contributor>
- <name>Dmitri Plotnikov</name>
- </contributor>
- <contributor>
- <name>Neeme Praks</name>
- </contributor>
- <contributor>
- <name>Eric Pugh</name>
- </contributor>
- <contributor>
- <name>Stephen Putman</name>
- </contributor>
- <contributor>
- <name>Travis Reeder</name>
- </contributor>
- <contributor>
- <name>Antony Riley</name>
- </contributor>
- <contributor>
- <name>Scott Sanders</name>
- </contributor>
- <contributor>
- <name>Ralph Schaer</name>
- </contributor>
- <contributor>
- <name>Henning P. Schmiedehausen</name>
- </contributor>
- <contributor>
- <name>Sean Schofield</name>
- </contributor>
- <contributor>
- <name>Reuben Sivan</name>
- </contributor>
- <contributor>
- <name>Ville Skytta</name>
- </contributor>
- <contributor>
- <name>Jan Sorensen</name>
- </contributor>
- <contributor>
- <name>Glen Stampoultzis</name>
- </contributor>
- <contributor>
- <name>Scott Stanchfield</name>
- </contributor>
- <contributor>
- <name>Jon S. Stevens</name>
- </contributor>
- <contributor>
- <name>Sean C. Sullivan</name>
- </contributor>
- <contributor>
- <name>Ashwin Suresh</name>
- </contributor>
- <contributor>
- <name>Helge Tesgaard</name>
- </contributor>
- <contributor>
- <name>Arun Mammen Thomas</name>
- </contributor>
- <contributor>
- <name>Masato Tezuka</name>
- </contributor>
- <contributor>
- <name>Jeff Varszegi</name>
- </contributor>
- <contributor>
- <name>Chris Webb</name>
- </contributor>
- <contributor>
- <name>Mario Winterer</name>
- </contributor>
- </contributors>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk</connection>
- <url>http://svn.apache.org/viewvc/jakarta/commons/proper/lang/trunk</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://jakarta.apache.org</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <resources>
- <resource>
- <targetPath>META-INF</targetPath>
- <directory>.</directory>
- <includes>
- <include>NOTICE.txt</include>
- </includes>
- </resource>
- </resources>
- <testResources>
- <testResource>
- <directory>${pom.build.unitTestSourceDirectory}</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </testResource>
- </testResources>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/*TestSuite.java</include>
- </includes>
- <excludes>
- <exclude>**/AllLangTestSuite.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- <plugin>
- <groupId>maven-plugins</groupId>
- <artifactId>maven-cobertura-plugin</artifactId>
- <version>1.1.1</version>
- <configuration>
- <scope>test</scope>
- <comment>Required only for generating test coverage reports.</comment>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>file:///www/jakarta.apache.org/builds/jakarta-commons/lang/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://people.apache.org//www/jakarta.apache.org/commons/lang/</url>
- </site>
- <status>converted</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-lang-2.2.xml b/qpid/java/lib/poms/commons-lang-2.2.xml
new file mode 100644
index 0000000000..b0bef7ca04
--- /dev/null
+++ b/qpid/java/lib/poms/commons-lang-2.2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.2</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-logging-1.0.4.pom b/qpid/java/lib/poms/commons-logging-1.0.4.pom
deleted file mode 100644
index 7c1017dc2a..0000000000
--- a/qpid/java/lib/poms/commons-logging-1.0.4.pom
+++ /dev/null
@@ -1,165 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <name>Logging</name>
- <version>1.0.4</version>
- <description>Commons Logging is a thin adapter allowing configurable bridging to other,
- well known logging systems.</description>
- <url>http://jakarta.apache.org/commons/logging/</url>
- <issueManagement>
- <url>http://issues.apache.org/bugzilla/</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <configuration>
- <address>commons-dev@jakarta.apache.org</address>
- </configuration>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2001</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
- <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
- <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>morgand</id>
- <name>Morgan Delagrange</name>
- <email>morgand at apache dot org</email>
- <organization>Apache</organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- <developer>
- <id>rwaldhoff</id>
- <name>Rodney Waldhoff</name>
- <email>rwaldhoff at apache org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>craigmcc</id>
- <name>Craig McClanahan</name>
- <email>craigmcc at apache org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>sanders</id>
- <name>Scott Sanders</name>
- <email>sanders at apache dot org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>rdonkin</id>
- <name>Robert Burrell Donkin</name>
- <email>rdonkin at apache dot org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>donaldp</id>
- <name>Peter Donald</name>
- <email>donaldp at apache dot org</email>
- <organization></organization>
- </developer>
- <developer>
- <id>costin</id>
- <name>Costin Manolache</name>
- <email>costin at apache dot org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>rsitze</id>
- <name>Richard Sitze</name>
- <email>rsitze at apache dot org</email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>baliuka</id>
- <name>Juozas Baliuka</name>
- <email>baliuka@apache.org</email>
- <organization></organization>
- <roles>
- <role>Java Developer</role>
- </roles>
- </developer>
- </developers>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/logging</connection>
- <url>http://cvs.apache.org/viewcvs/jakarta-commons/logging/</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://jakarta.apache.org</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/AvalonLoggerTest.java</include>
- </includes>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.6</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>logkit</groupId>
- <artifactId>logkit</artifactId>
- <version>1.0.1</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.7</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>avalon-framework</groupId>
- <artifactId>avalon-framework</artifactId>
- <version>4.1.3</version>
- <optional>true</optional>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>file:///www/jakarta.apache.org/builds/jakarta-commons/logging/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://jakarta.apache.org//www/jakarta.apache.org/commons/logging/</url>
- </site>
- </distributionManagement>
-</project>
diff --git a/qpid/java/lib/poms/commons-logging-1.0.4.xml b/qpid/java/lib/poms/commons-logging-1.0.4.xml
new file mode 100644
index 0000000000..c85d0f7b29
--- /dev/null
+++ b/qpid/java/lib/poms/commons-logging-1.0.4.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.4</version>
+</dep>
diff --git a/qpid/java/lib/poms/commons-pool-1.4.pom b/qpid/java/lib/poms/commons-pool-1.4.pom
deleted file mode 100644
index 3dd87ae576..0000000000
--- a/qpid/java/lib/poms/commons-pool-1.4.pom
+++ /dev/null
@@ -1,209 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>commons-pool</groupId>
- <artifactId>commons-pool</artifactId>
- <name>Commons Pool</name>
- <version>1.4</version>
- <description>Commons Object Pooling Library</description>
- <url>http://commons.apache.org/pool/</url>
- <issueManagement>
- <url>http://issues.apache.org/jira/</url>
- </issueManagement>
- <ciManagement>
- <notifiers>
- <notifier>
- <configuration>
- <address>dev@commons.apache.org</address>
- </configuration>
- </notifier>
- </notifiers>
- </ciManagement>
- <inceptionYear>2001</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Commons Dev List</name>
- <subscribe>dev-subscribe@commons.apache.org</subscribe>
- <unsubscribe>dev-unsubscribe@commons.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/mod_mbox/commons-dev/</archive>
- </mailingList>
- <mailingList>
- <name>Commons User List</name>
- <subscribe>user-subscribe@commons.apache.org</subscribe>
- <unsubscribe>user-unsubscribe@commons.apache.org</unsubscribe>
- <archive>http://mail-archives.apache.org/mod_mbox/commons-user/</archive>
- </mailingList>
- </mailingLists>
- <developers>
- <developer>
- <id>morgand</id>
- <name>Morgan Delagrange</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>geirm</id>
- <name>Geir Magnusson</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>craigmcc</id>
- <name>Craig McClanahan</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>rwaldhoff</id>
- <name>Rodney Waldhoff</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>dweinr1</id>
- <name>David Weinrich</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>dirkv</id>
- <name>Dirk Verbeeck</name>
- <email></email>
- <organization></organization>
- </developer>
- <developer>
- <id>rdonkin</id>
- <name>Robert Burrell Donkin</name>
- <email></email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>sandymac</id>
- <name>Sandy McArthur</name>
- <email></email>
- <organization>Apache Software Foundation</organization>
- </developer>
- <developer>
- <id>psteitz</id>
- <name>Phil Steitz</name>
- <email></email>
- <organization>Apache Software Foundation</organization>
- </developer>
- </developers>
- <contributors>
- <contributor>
- <name>Todd Carmichael</name>
- <email>toddc@concur.com</email>
- </contributor>
- </contributors>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>/LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/pool/trunk</connection>
- <url>http://svn.apache.org/repos/asf/commons/proper/pool/trunk</url>
- </scm>
- <organization>
- <name>The Apache Software Foundation</name>
- <url>http://commons.apache.org/</url>
- </organization>
- <build>
- <sourceDirectory>src/java</sourceDirectory>
- <testSourceDirectory>src/test</testSourceDirectory>
- <resources>
- <resource>
- <targetPath>META-INF</targetPath>
- <directory>${basedir}</directory>
- <includes>
- <include>NOTICE.txt</include>
- </includes>
- </resource>
- </resources>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>org/apache/commons/pool/TestBaseObjectPool.java</include>
- <include>org/apache/commons/pool/TestBaseKeyedObjectPool.java</include>
- <include>org/apache/commons/pool/TestBasePoolableObjectFactory.java</include>
- <include>org/apache/commons/pool/TestBaseKeyedPoolableObjectFactory.java</include>
- <include>org/apache/commons/pool/TestPoolUtils.java</include>
- <include>org/apache/commons/pool/impl/TestStackObjectPool.java</include>
- <include>org/apache/commons/pool/impl/TestStackKeyedObjectPool.java</include>
- <include>org/apache/commons/pool/impl/TestGenericObjectPool.java</include>
- <include>org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java</include>
- <include>org/apache/commons/pool/impl/TestSoftReferenceObjectPool.java</include>
- <include>org/apache/commons/pool/impl/TestGenericObjectPoolFactory.java</include>
- <include>org/apache/commons/pool/impl/TestStackObjectPoolFactory.java</include>
- <include>org/apache/commons/pool/impl/TestGenericKeyedObjectPoolFactory.java</include>
- <include>org/apache/commons/pool/impl/TestStackKeyedObjectPoolFactory.java</include>
- <include>org/apache/commons/pool/composite/TestFifoLender.java</include>
- <include>org/apache/commons/pool/composite/TestIdleEvictorLender.java</include>
- <include>org/apache/commons/pool/composite/TestInvalidEvictorLender.java</include>
- <include>org/apache/commons/pool/composite/TestLifoLender.java</include>
- <include>org/apache/commons/pool/composite/TestNullLender.java</include>
- <include>org/apache/commons/pool/composite/TestSoftLender.java</include>
- <include>org/apache/commons/pool/composite/TestFailManager.java</include>
- <include>org/apache/commons/pool/composite/TestGrowManager.java</include>
- <include>org/apache/commons/pool/composite/TestIdleLimitManager.java</include>
- <include>org/apache/commons/pool/composite/TestFailLimitManager.java</include>
- <include>org/apache/commons/pool/composite/TestWaitLimitManager.java</include>
- <include>org/apache/commons/pool/composite/TestNullTracker.java</include>
- <include>org/apache/commons/pool/composite/TestReferenceTracker.java</include>
- <include>org/apache/commons/pool/composite/TestDebugTracker.java</include>
- <include>org/apache/commons/pool/composite/TestSimpleTracker.java</include>
- <include>org/apache/commons/pool/composite/TestCompositeObjectPool.java</include>
- <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPool.java</include>
- <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPool2.java</include>
- <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPoolFactory.java</include>
- </includes>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-jdiff-plugin</artifactId>
- <version>1.5</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-changes-plugin</artifactId>
- <version>1.6</version>
- <configuration>
- <comment>&lt;strong>Site Only&lt;/strong> - v1.6 (minimum)</comment>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>1.8</version>
- <configuration>
- <comment>&lt;b>Site&lt;/b> only</comment>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.2</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>default</id>
- <name>Default Repository</name>
- <url>file:///www/people.apache.org/builds/commons/pool/</url>
- </repository>
- <site>
- <id>default</id>
- <name>Default Site</name>
- <url>scp://people.apache.org//www/commons.apache.org/pool/</url>
- </site>
- <status>converted</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/commons-pool-1.4.xml b/qpid/java/lib/poms/commons-pool-1.4.xml
new file mode 100644
index 0000000000..21a18596b9
--- /dev/null
+++ b/qpid/java/lib/poms/commons-pool-1.4.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ <version>1.4</version>
+</dep>
diff --git a/qpid/java/lib/poms/derby-10.3.2.1.pom b/qpid/java/lib/poms/derby-10.3.2.1.pom
deleted file mode 100644
index 175046203d..0000000000
--- a/qpid/java/lib/poms/derby-10.3.2.1.pom
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <name>Derby Engine</name>
- <version>10.3.2.1</version>
- <description></description>
- <url>http://db.apache.org/derby/</url>
- <issueManagement>
- <url>http://issues.apache.org/jira/browse/DERBY</url>
- </issueManagement>
- <inceptionYear>2004</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Derby User List</name>
- <subscribe>derby-user-subscribe@db.apache.org</subscribe>
- <unsubscribe>derby-user-unsubscribe@db.apache.org</unsubscribe>
- <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-user@db.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Derby Developer List</name>
- <subscribe>derby-dev-subscribe@db.apache.org</subscribe>
- <unsubscribe>derby-dev-unsubscribe@db.apache.org</unsubscribe>
- <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-dev@db.apache.org</archive>
- </mailingList>
- <mailingList>
- <name>Derby Commit List</name>
- <subscribe>derby-commits-subscribe@db.apache.org</subscribe>
- <unsubscribe>derby-commits-unsubscribe@db.apache.org</unsubscribe>
- <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-commits@db.apache.org</archive>
- </mailingList>
- </mailingLists>
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/db/derby/code/trunk</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/db/derby/code/trunk</developerConnection>
- <url>http://svn.apache.org/viewcvs.cgi/db/derby/code/trunk/?root=Apache-SVN</url>
- </scm>
- <organization>
- <name>Apache Software Foundation</name>
- <url>http://db.apache.org/</url>
- </organization>
- <build />
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/derby-10.6.1.0.xml b/qpid/java/lib/poms/derby-10.6.1.0.xml
new file mode 100644
index 0000000000..de6a4d79f3
--- /dev/null
+++ b/qpid/java/lib/poms/derby-10.6.1.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.6.1.0</version>
+</dep>
diff --git a/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom b/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom
deleted file mode 100644
index bde503231e..0000000000
--- a/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom
+++ /dev/null
@@ -1,6 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- <version>1.0</version>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.xml b/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.xml
new file mode 100644
index 0000000000..0fe38d5477
--- /dev/null
+++ b/qpid/java/lib/poms/geronimo-jms_1.1_spec-1.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jms_1.1_spec</artifactId>
+ <version>1.0</version>
+</dep>
diff --git a/qpid/java/lib/poms/junit-3.8.1.pom b/qpid/java/lib/poms/junit-3.8.1.pom
deleted file mode 100644
index 2169a65d76..0000000000
--- a/qpid/java/lib/poms/junit-3.8.1.pom
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <name>JUnit</name>
- <url>http://junit.org</url>
- <description>
- JUnit is a regression testing framework written by Erich Gamma and Kent Beck. It is used by the developer who implements unit tests in Java.
- </description>
- <organization>
- <name>JUnit</name>
- <url>http://www.junit.org</url>
- </organization>
- <licenses>
- <license>
- <name>Common Public License Version 1.0</name>
- <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
- </license>
- </licenses>
- <scm>
- <url>http://junit.cvs.sourceforge.net/junit/</url>
- </scm>
- <dependencies>
- </dependencies>
-</project>
diff --git a/qpid/java/lib/poms/junit-3.8.1.xml b/qpid/java/lib/poms/junit-3.8.1.xml
new file mode 100644
index 0000000000..0462e9c0d2
--- /dev/null
+++ b/qpid/java/lib/poms/junit-3.8.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/log4j-1.2.12.pom b/qpid/java/lib/poms/log4j-1.2.12.pom
deleted file mode 100644
index 8c10608604..0000000000
--- a/qpid/java/lib/poms/log4j-1.2.12.pom
+++ /dev/null
@@ -1,6 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.12</version>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/log4j-1.2.12.xml b/qpid/java/lib/poms/log4j-1.2.12.xml
new file mode 100644
index 0000000000..87331f4acc
--- /dev/null
+++ b/qpid/java/lib/poms/log4j-1.2.12.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.12</version>
+</dep>
diff --git a/qpid/java/lib/poms/mina-core-1.0.1.pom b/qpid/java/lib/poms/mina-core-1.0.1.pom
deleted file mode 100644
index def70418c9..0000000000
--- a/qpid/java/lib/poms/mina-core-1.0.1.pom
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?><project>
- <parent>
- <artifactId>build</artifactId>
- <groupId>org.apache.mina</groupId>
- <version>1.0.1</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>mina-core</artifactId>
- <name>Apache MINA Core API</name>
- <version>1.0.1</version>
- <dependencies>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- <version>1.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>backport-util-concurrent</groupId>
- <artifactId>backport-util-concurrent</artifactId>
- <version>2.2</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>easymock</groupId>
- <artifactId>easymock</artifactId>
- <version>1.2_Java1.3</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <status>deployed</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/mina-core-1.0.1.xml b/qpid/java/lib/poms/mina-core-1.0.1.xml
new file mode 100644
index 0000000000..87fb96999f
--- /dev/null
+++ b/qpid/java/lib/poms/mina-core-1.0.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.mina</groupId>
+ <artifactId>mina-core</artifactId>
+ <version>1.0.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/mina-filter-ssl-1.0.1.pom b/qpid/java/lib/poms/mina-filter-ssl-1.0.1.pom
deleted file mode 100644
index 1d5a1ec18c..0000000000
--- a/qpid/java/lib/poms/mina-filter-ssl-1.0.1.pom
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?><project>
- <parent>
- <artifactId>build</artifactId>
- <groupId>org.apache.mina</groupId>
- <version>1.0.1</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>mina-filter-ssl</artifactId>
- <name>Apache MINA SSL Filter</name>
- <version>1.0.1</version>
- <dependencies>
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-core</artifactId>
- <version>1.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- <version>1.0</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <status>deployed</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/mina-filter-ssl-1.0.1.xml b/qpid/java/lib/poms/mina-filter-ssl-1.0.1.xml
new file mode 100644
index 0000000000..ae41d7ed63
--- /dev/null
+++ b/qpid/java/lib/poms/mina-filter-ssl-1.0.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.mina</groupId>
+ <artifactId>mina-filter-ssl</artifactId>
+ <version>1.0.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/org.apache.felix.framework-1.0.0.pom b/qpid/java/lib/poms/org.apache.felix.framework-1.0.0.pom
deleted file mode 100644
index c7e6cd489e..0000000000
--- a/qpid/java/lib/poms/org.apache.felix.framework-1.0.0.pom
+++ /dev/null
@@ -1,66 +0,0 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project>
- <parent>
- <groupId>org.apache.felix</groupId>
- <artifactId>felix</artifactId>
- <version>1.0.0</version>
- <relativePath>../pom/pom.xml</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <packaging>bundle</packaging>
- <name>Apache Felix Framework</name>
- <artifactId>org.apache.felix.framework</artifactId>
- <version>1.0.0</version>
- <dependencies>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>1.0.0</version>
- </dependency>
- <!--dependency>
- We include ServiceTracker source code directly to avoid some
- packaging issues. Will need to edit main pom to exclude this
- dependency once it is added back in.
- <groupId>${pom.groupId}</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- <version>0.9.0-SNAPSHOT</version>
- </dependency-->
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>1.0.0</version>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Bundle-Name>Apache Felix Framework</Bundle-Name>
- <Bundle-Description>OSGi R4 framework implementation.</Bundle-Description>
- <Export-Package>org.osgi.framework,org.osgi.service.packageadmin,org.osgi.service.url,org.osgi.service.startlevel,org.osgi.util.tracker</Export-Package>
- <Private-Package>org.apache.felix.moduleloader.*,org.apache.felix.framework.*</Private-Package>
- <Import-Package>!*</Import-Package>
- <Include-Resource>{src/main/resources/},org/osgi/framework/=target/classes/org/osgi/framework/</Include-Resource>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/qpid/java/lib/poms/org.apache.felix.framework-2.0.5.xml b/qpid/java/lib/poms/org.apache.felix.framework-2.0.5.xml
new file mode 100644
index 0000000000..cef17fe589
--- /dev/null
+++ b/qpid/java/lib/poms/org.apache.felix.framework-2.0.5.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>2.0.5</version>
+</dep>
diff --git a/qpid/java/lib/poms/org.osgi.core-1.0.0.pom b/qpid/java/lib/poms/org.osgi.core-1.0.0.pom
deleted file mode 100644
index 4e512c06a4..0000000000
--- a/qpid/java/lib/poms/org.osgi.core-1.0.0.pom
+++ /dev/null
@@ -1,56 +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.
--->
-<project>
- <parent>
- <groupId>org.apache.felix</groupId>
- <artifactId>felix</artifactId>
- <version>1.0.0</version>
- <relativePath>../pom/pom.xml</relativePath>
- </parent>
- <organization>
- <name>OSGi Alliance</name>
- <url>http://www.osgi.org/</url>
- </organization>
- <modelVersion>4.0.0</modelVersion>
- <name>OSGi R4 Core Bundle</name>
- <description>OSGi Service Platform Release 4 Core Interfaces and Classes.</description>
- <artifactId>org.osgi.core</artifactId>
- <version>1.0.0</version>
- <packaging>bundle</packaging>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>1.0.0</version>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Bundle-SymbolicName>org.osgi.core</Bundle-SymbolicName>
- <Export-Package>org.osgi.framework, org.osgi.service.condpermadmin, org.osgi.service.packageadmin, org.osgi.service.permissionadmin, org.osgi.service.startlevel, org.osgi.service.url</Export-Package>
- <Import-Package>org.osgi.framework,org.osgi.service.packageadmin,org.osgi.service.startlevel,org.osgi.service.url,!org.osgi.*,*</Import-Package>
- <Bundle-Version>4</Bundle-Version>
- <Bundle-Copyright>Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.</Bundle-Copyright>
- <Bundle-Category>osgi</Bundle-Category>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/qpid/java/lib/poms/org.osgi.core-1.0.0.xml b/qpid/java/lib/poms/org.osgi.core-1.0.0.xml
new file mode 100644
index 0000000000..833cc91729
--- /dev/null
+++ b/qpid/java/lib/poms/org.osgi.core-1.0.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.0.0</version>
+</dep>
diff --git a/qpid/java/lib/poms/slf4j-api-1.4.0.pom b/qpid/java/lib/poms/slf4j-api-1.4.0.pom
deleted file mode 100644
index 13e1418d2b..0000000000
--- a/qpid/java/lib/poms/slf4j-api-1.4.0.pom
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0"?><project>
- <parent>
- <artifactId>slf4j-parent</artifactId>
- <groupId>org.slf4j</groupId>
- <version>1.4.0</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <name>SLF4J API Module</name>
- <version>1.4.0</version>
- <description>The slf4j API</description>
- <url>http://www.slf4j.org</url>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>once</forkMode>
- <reportFormat>plain</reportFormat>
- <trimStackTrace>false</trimStackTrace>
- <excludes>
- <exclude>**/AllTest.java</exclude>
- <exclude>**/PackageTest.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <id>bundle-test-jar</id>
- <phase>package</phase>
- <goals>
- <goal>jar</goal>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <archive>
- <manifestEntries>
- <Bundle-Version>${pv4osgi}</Bundle-Version>
- <Bundle-Description>${project.description}</Bundle-Description>
- <Implementation-Version>1.4.0</Implementation-Version>
- </manifestEntries>
- <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
- </archive>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <phase>process-classes</phase>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <tasks>
- <echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
- <delete dir="target/classes/org/slf4j/impl"></delete>
- </tasks>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <distributionManagement>
- <status>deployed</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/slf4j-api-1.6.1.xml b/qpid/java/lib/poms/slf4j-api-1.6.1.xml
new file mode 100644
index 0000000000..e3f989bd4e
--- /dev/null
+++ b/qpid/java/lib/poms/slf4j-api-1.6.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/slf4j-log4j12-1.4.0.pom b/qpid/java/lib/poms/slf4j-log4j12-1.4.0.pom
deleted file mode 100644
index 29302557e6..0000000000
--- a/qpid/java/lib/poms/slf4j-log4j12-1.4.0.pom
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0"?><project>
- <parent>
- <artifactId>slf4j-parent</artifactId>
- <groupId>org.slf4j</groupId>
- <version>1.4.0</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <name>SLF4J LOG4J-12 Binding</name>
- <version>1.4.0</version>
- <description>The slf4j log4j-12 binding</description>
- <url>http://www.slf4j.org</url>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifestEntries>
- <Bundle-Version>${pv4osgi}</Bundle-Version>
- <Bundle-Description>${project.description}</Bundle-Description>
- <Implementation-Version>1.4.0</Implementation-Version>
- </manifestEntries>
- <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
- </archive>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
- </dependencies>
- <distributionManagement>
- <status>deployed</status>
- </distributionManagement>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/slf4j-log4j12-1.6.1.xml b/qpid/java/lib/poms/slf4j-log4j12-1.6.1.xml
new file mode 100644
index 0000000000..482bbec894
--- /dev/null
+++ b/qpid/java/lib/poms/slf4j-log4j12-1.6.1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.1</version>
+</dep>
diff --git a/qpid/java/lib/poms/xalan-2.7.0.pom b/qpid/java/lib/poms/xalan-2.7.0.pom
deleted file mode 100644
index f543d7e6e2..0000000000
--- a/qpid/java/lib/poms/xalan-2.7.0.pom
+++ /dev/null
@@ -1,19 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>xalan</groupId>
- <artifactId>xalan</artifactId>
- <version>2.7.0</version>
- <dependencies>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>2.0.2</version>
- </dependency>
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.6.0</version>
- <optional>true</optional>
- </dependency>
- </dependencies>
-</project> \ No newline at end of file
diff --git a/qpid/java/lib/poms/xalan-2.7.0.xml b/qpid/java/lib/poms/xalan-2.7.0.xml
new file mode 100644
index 0000000000..73ea2df7e2
--- /dev/null
+++ b/qpid/java/lib/poms/xalan-2.7.0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<dep>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.0</version>
+</dep>
diff --git a/qpid/java/module.xml b/qpid/java/module.xml
index d4007e067c..877ca130af 100644
--- a/qpid/java/module.xml
+++ b/qpid/java/module.xml
@@ -18,10 +18,15 @@
- under the License.
-
-->
-<project name="module">
+<project name="module" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<import file="common.xml"/>
+ <path id="maven-ant-tasks.classpath" path="${project.root}/lib/maven-ant-tasks-2.1.1.jar" />
+ <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
+ uri="antlib:org.apache.maven.artifact.ant"
+ classpathref="maven-ant-tasks.classpath" />
+
<map property="module" value="${basedir}" split="${path.separator}">
<globmapper from="${project.root}${file.separator}*" to="*"/>
</map>
@@ -74,6 +79,9 @@
<available property="module.etc.exists" file="${module.etc}"/>
<available property="module.bin.exists" file="${module.bin}"/>
+ <property name="module.source.jar"
+ location="${build.lib}/${project.name}-${module.name}-${project.version}-sources.jar"/>
+
<!-- module.depends and module.test.depends are supplied by the importing file -->
<property name="module.depends" value=""/>
<property name="module.test.depends" value=""/>
@@ -209,18 +217,34 @@
<target name="pom" depends="prepare" if="module.genpom">
<jython path="${mllib.dir}">
<args>
- <arg line="${project.root}/genpom"/>
- <arg line="-s ${project.root}/lib/poms"/>
- <arg line="-o ${build}/${module.name}.pom"/>
+ <arg line='"${project.root}/genpom"'/>
+ <arg line='-s "${project.root}/lib/poms"'/>
+ <arg line='-o "${build}/qpid-${module.name}.pom"'/>
+ <arg line="-u http://qpid.apache.org"/>
<arg line="-g org.apache.qpid"/>
- <arg line="-a ${module.name}"/>
<arg line="-v ${project.version}"/>
+ <arg line="-p qpid"/>
+ <arg line='-m "${module.depends}"'/>
+ <arg line="-a ${module.name}"/>
<arg line="${module.genpom.args}"/>
<arg line="${module.libs}"/>
</args>
</jython>
</target>
+ <target name="release-mvn" depends="pom" if="module.genpom" description="Install the artifacts into the local repository and prepare the release">
+ <antcall target="build"/>
+
+ <artifact:pom id="module.pom" file="${build}/qpid-${module.name}.pom"/>
+
+ <artifact:install file="${module.jar}" pomRefId="module.pom"/>
+
+ <artifact:deploy file="${module.jar}" pomRefId="module.pom">
+ <attach file="${module.source.jar}" classifier="sources"/>
+ <remoteRepository url="file://${module.release.base}/maven"/>
+ </artifact:deploy>
+ </target>
+
<target name="precompile"/>
<target name="compile" depends="prepare,precompile" description="compile sources">
@@ -228,7 +252,7 @@
<echo message="Targeting : ${java.target}" level="info"/>
<javac source="${java.source}" target="${java.target}"
- destdir="${module.classes}" debug="on" includeantruntime="false"
+ destdir="${module.classes}" debug="on" debuglevel="lines,vars,source" includeantruntime="false"
deprecation="${javac.deprecation}">
<compilerarg line="${javac.compiler.args}"/>
<src refid="module.src.path"/>
@@ -407,7 +431,7 @@
<target name="postbuild" description="run after a build"/>
- <target name="build" depends="jar,jar-tests,libs,copy-bin,copy-etc,postbuild" description="compile and copy resources into build tree"/>
+ <target name="build" depends="jar,jar-tests,jar-sources,libs,copy-bin,copy-etc,postbuild" description="compile and copy resources into build tree"/>
<target name="jar.manifest" depends="compile" if="module.manifest">
<jar destfile="${module.jar}" basedir="${module.classes}" manifest="${module.manifest}"/>
</target>
@@ -424,6 +448,17 @@
<jar destfile="${module.test.jar}" basedir="${module.test.classes}"/>
</target>
+ <target name="jar-sources" depends="prepare" description="create sources jar">
+ <jar destfile="${module.source.jar}">
+ <fileset dir="${project.root}/resources">
+ <include name="LICENSE"/>
+ <include name="NOTICE"/>
+ </fileset>
+ <fileset dir="${module.src}" includes="**/*.java"/>
+ <fileset dir="${module.precompiled}" includes="**/*.java"/>
+ </jar>
+ </target>
+
<target name="libs" description="copy dependencies into build tree">
<copylist todir="${build.lib}" dir="${project.root}" files="${module.libs}"/>
</target>
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
index 11d9ce2bbc..e4d1c72208 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
@@ -20,12 +20,16 @@
*/
package org.apache.qpid.client;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.LogMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
@@ -46,14 +50,15 @@ import java.util.concurrent.TimeUnit;
* 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 MessageListenerTest extends QpidBrokerTestCase implements MessageListener
+public class MessageListenerTest extends QpidBrokerTestCase implements MessageListener, ExceptionListener
{
private static final Logger _logger = LoggerFactory.getLogger(MessageListenerTest.class);
Context _context;
private static final int MSG_COUNT = 5;
- private int receivedCount = 0;
+ private int _receivedCount = 0;
+ private int _errorCount = 0;
private MessageConsumer _consumer;
private Connection _clientConnection;
private CountDownLatch _awaitMessages = new CountDownLatch(MSG_COUNT);
@@ -94,11 +99,14 @@ public class MessageListenerTest extends QpidBrokerTestCase implements MessageLi
protected void tearDown() throws Exception
{
- _clientConnection.close();
+ if (_clientConnection != null)
+ {
+ _clientConnection.close();
+ }
super.tearDown();
}
- public void testSynchronousRecieve() throws Exception
+ public void testSynchronousReceive() throws Exception
{
for (int msg = 0; msg < MSG_COUNT; msg++)
{
@@ -106,15 +114,15 @@ public class MessageListenerTest extends QpidBrokerTestCase implements MessageLi
}
}
- public void testSynchronousRecieveNoWait() throws Exception
+ public void testSynchronousReceiveNoWait() throws Exception
{
for (int msg = 0; msg < MSG_COUNT; msg++)
{
- assertTrue(_consumer.receiveNoWait() != null);
+ assertTrue("Failed to receive message " + msg, _consumer.receiveNoWait() != null);
}
}
- public void testAsynchronousRecieve() throws Exception
+ public void testAsynchronousReceive() throws Exception
{
_consumer.setMessageListener(this);
@@ -128,18 +136,17 @@ public class MessageListenerTest extends QpidBrokerTestCase implements MessageLi
{
// do nothing
}
- // Should have recieved all async messages
- assertEquals(MSG_COUNT, receivedCount);
+ // Should have received all async messages
+ assertEquals(MSG_COUNT, _receivedCount);
}
- public void testRecieveThenUseMessageListener() throws Exception
+ public void testReceiveThenUseMessageListener() throws Exception
{
-
_logger.error("Test disabled as initial receive is not called first");
// Perform initial receive to start connection
assertTrue(_consumer.receive(2000) != null);
- receivedCount++;
+ _receivedCount++;
// Sleep to ensure remaining 4 msgs end up on _synchronousQueue
Thread.sleep(1000);
@@ -157,8 +164,8 @@ public class MessageListenerTest extends QpidBrokerTestCase implements MessageLi
{
// do nothing
}
- // Should have recieved all async messages
- assertEquals(MSG_COUNT, receivedCount);
+ // Should have received all async messages
+ assertEquals(MSG_COUNT, _receivedCount);
_clientConnection.close();
@@ -172,14 +179,81 @@ public class MessageListenerTest extends QpidBrokerTestCase implements MessageLi
assertTrue(cons.receive(2000) == null);
}
+ /**
+ * Tests the case where the message listener throws an java.lang.Error.
+ *
+ */
+ public void testMessageListenerThrowsError() throws Exception
+ {
+ final String javaLangErrorMessageText = "MessageListener failed with java.lang.Error";
+ _clientConnection.setExceptionListener(this);
+
+ _awaitMessages = new CountDownLatch(1);
+
+ _consumer.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ try
+ {
+ _logger.debug("onMessage called");
+ _receivedCount++;
+
+
+ throw new Error(javaLangErrorMessageText);
+ }
+ finally
+ {
+ _awaitMessages.countDown();
+ }
+ }
+ });
+
+
+ _logger.info("Waiting 3 seconds for message");
+ _awaitMessages.await(3000, TimeUnit.MILLISECONDS);
+
+ assertEquals("onMessage should have been called", 1, _receivedCount);
+ assertEquals("onException should NOT have been called", 0, _errorCount);
+
+ // Check that Error has been written to the application log.
+
+ LogMonitor _monitor = new LogMonitor(_outputFile);
+ assertTrue("The expected message not written to log file.",
+ _monitor.waitForMessage(javaLangErrorMessageText, LOGMONITOR_TIMEOUT));
+
+ if (_clientConnection != null)
+ {
+ try
+ {
+ _clientConnection.close();
+ }
+ catch (JMSException e)
+ {
+ // Ignore connection close errors for this test.
+ }
+ finally
+ {
+ _clientConnection = null;
+ }
+ }
+ }
+
public void onMessage(Message message)
{
- _logger.info("Received Message(" + receivedCount + "):" + message);
+ _logger.info("Received Message(" + _receivedCount + "):" + message);
- receivedCount++;
+ _receivedCount++;
_awaitMessages.countDown();
}
+ @Override
+ public void onException(JMSException e)
+ {
+ _logger.info("Exception received", e);
+ _errorCount++;
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(MessageListenerTest.class);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java
index 7b59266eb3..f56f428f0b 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java
@@ -20,19 +20,6 @@
*/
package org.apache.qpid.server.logging;
-import org.apache.qpid.server.configuration.ServerConfiguration;
-import org.apache.qpid.server.configuration.VirtualHostConfiguration;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.server.logging.actors.TestLogActor;
-import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.store.SkeletonMessageStore;
-import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import org.apache.qpid.server.util.TestApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.test.utils.QpidBrokerTestCase;
-import org.apache.qpid.util.LogMonitor;
-
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
@@ -40,6 +27,14 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.LogMonitor;
+
/**
* Abstract superclass for logging test set up and utility methods.
*
@@ -50,7 +45,6 @@ public class AbstractTestLogging extends QpidBrokerTestCase
public static final long DEFAULT_LOG_WAIT = 2000;
public static final String TEST_LOG_PREFIX = "MESSAGE";
protected LogMonitor _monitor;
- ServerConfiguration _serverConfiguration;
InternalBrokerBaseCase _configLoader;
@@ -61,61 +55,32 @@ public class AbstractTestLogging extends QpidBrokerTestCase
super.setUp();
_monitor = new LogMonitor(_outputFile);
+ }
+ protected ServerConfiguration getServerConfig() throws ConfigurationException
+ {
+ ServerConfiguration _serverConfiguration;
if (isExternalBroker())
{
- _serverConfiguration = new ServerConfiguration(_configFile);
-
- _configLoader = new InternalBrokerBaseCase()
+ _serverConfiguration = new ServerConfiguration(_configFile)
{
@Override
- protected void createBroker() throws Exception
- {
- setStarted(true);
- CurrentActor.set(new TestLogActor(new SystemOutMessageLogger()));
-
- // Prevent the InVM broker from logging and spoiling tests.
- _serverConfiguration.getConfig().setProperty(ServerConfiguration.STATUS_UPDATES, "off");
-
- setConfiguration(_serverConfiguration);
- setRegistry(new TestApplicationRegistry(getConfiguration())
- {
- /**
- * Create a virtualhost with a {@link org.apache.qpid.server.store.SkeletonMessageStore} instead
- * of the configured one, but remember the original configuration.
- */
- @Override
- public VirtualHost createVirtualHost(final VirtualHostConfiguration vhostConfig) throws Exception
- {
- String oldClass = vhostConfig.getMessageStoreClass();
- vhostConfig.setMessageStoreClass(SkeletonMessageStore.class.getName());
- VirtualHost host = super.createVirtualHost(vhostConfig);
- vhostConfig.setMessageStoreClass(oldClass);
- return host;
- }
- });
- ApplicationRegistry.initialise(getRegistry());
-
- }
-
- @Override
- protected void stopBroker()
+ public void initialise() throws ConfigurationException
{
- ApplicationRegistry.remove();
+ //Overriding initialise to only setup the vhosts and not
+ //perform the ConfigurationPlugin setup, removing need for
+ //an ApplicationRegistry to be loaded.
+ setupVirtualHosts(getConfig());
}
};
-
- // Set the test name as this will be used to define some default queues
- // VirtualHost, use test as this is a default vhost name.
- _configLoader.setName("test");
-
- _configLoader.setUp();
+ _serverConfiguration.initialise();
}
else
{
_serverConfiguration = ApplicationRegistry.getInstance().getConfiguration();
}
+ return _serverConfiguration;
}
protected void setLogMessagePrefix()
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
index 495a8c33c6..05aaf16af1 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
@@ -132,6 +132,7 @@ public class AlertingTest extends AbstractTestLogging
{
sendMessage(_session, _destination, _numMessages + 1);
_session.commit();
+ _connection.close();
stopBroker();
// Rest the monitoring clearing the current output file.
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java
index 51815e2adc..97914f84a5 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java
@@ -191,6 +191,16 @@ public class BindingLoggingTest extends AbstractTestLogging
// and so unbind.
_session.createConsumer(_session.createTemporaryQueue()).close();
+ if(isBroker010())
+ {
+ //auto-delete is at session close for 0-10
+ _session.close();
+ }
+
+ //wait for the deletion messages to be logged
+ waitForMessage("BND-1002");
+
+ //gather all the BND messages
List<String> results = waitAndFindMatches(BND_PREFIX);
// We will have two binds as we bind all queues to the default exchange
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java
index bd9b18d848..02d0d6f334 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java
@@ -75,7 +75,7 @@ public class ChannelLoggingTest extends AbstractTestLogging
String log = getLogMessage(results, 0);
// MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1001 : Create
validateMessageID("CHN-1001", log);
- assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log)));
+ assertEquals("Incorrect Channel in actor:"+fromActor(log), isBroker010()? 0 : 1, getChannelID(fromActor(log)));
if (isBroker08())
{
@@ -89,7 +89,7 @@ public class ChannelLoggingTest extends AbstractTestLogging
log = getLogMessage(results, 0);
// MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number}
validateMessageID("CHN-1004", log);
- assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log)));
+ assertEquals("Incorrect Channel in actor:"+fromActor(log), isBroker010()? 0 : 1, getChannelID(fromActor(log)));
assertTrue("Prefetch Count not correct",getMessageString(fromMessage(log)).endsWith("Count "+PREFETCH));
}
@@ -306,7 +306,7 @@ public class ChannelLoggingTest extends AbstractTestLogging
validateMessageID("CHN-1001", open);
validateMessageID("CHN-1003", close);
assertEquals("Message should be Close", "Close", getMessageString(fromMessage(close)));
- assertEquals("Incorrect Channel ID closed", 1, getChannelID(fromSubject(close)));
+ assertEquals("Incorrect Channel ID closed", isBroker010()? 0 : 1, getChannelID(fromSubject(close)));
assertEquals("Channel IDs should be the same", getChannelID(fromActor(open)), getChannelID(fromSubject(close)));
assertEquals("Connection IDs should be the same", getConnectionID(fromActor(open)), getConnectionID(fromSubject(close)));
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java
index 67ff8a4328..1e48f34f99 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.logging;
import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession_0_10;
import org.apache.qpid.framing.AMQFrame;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ExchangeDeleteBody;
@@ -65,7 +66,7 @@ public class ExchangeLoggingTest extends AbstractTestLogging
_session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
_type = "direct";
- _name = "testName";
+ _name = getTestQueueName()+ "-exchange";
_queue = _session.createQueue(_type + "://" + _name + "/queue/queue");
@@ -177,15 +178,24 @@ public class ExchangeLoggingTest extends AbstractTestLogging
//Ignore broker startup messages
_monitor.reset();
+ //create the exchange by creating a consumer
_session.createConsumer(_queue);
- MethodRegistry_8_0 registry = new MethodRegistry_8_0();
+ //now delete the exchange
+ if(isBroker010())
+ {
+ ((AMQSession_0_10) _session).sendExchangeDelete(_name, false);
+ }
+ else
+ {
+ MethodRegistry_8_0 registry = new MethodRegistry_8_0();
- ExchangeDeleteBody body = registry.createExchangeDeleteBody(0, new AMQShortString(_name), false, true);
+ ExchangeDeleteBody body = registry.createExchangeDeleteBody(0, new AMQShortString(_name), false, true);
- AMQFrame exchangeDeclare = body.generateFrame(0);
+ AMQFrame exchangeDeclare = body.generateFrame(0);
- ((AMQConnection) _connection).getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeleteOkBody.class);
+ ((AMQConnection) _connection).getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeleteOkBody.class);
+ }
//Wait and ensure we get our last EXH-1002 msg
waitForMessage("EXH-1002");
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
index 877560ea14..34d9e1f057 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
@@ -92,7 +92,7 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
results = waitAndFindMatches("MST-1001");
// Load VirtualHost list from file.
- List<String> vhosts = Arrays.asList(_serverConfiguration.getVirtualHosts());
+ List<String> vhosts = Arrays.asList(getServerConfig().getVirtualHosts());
assertEquals("Each vhost did not create a store.", vhosts.size(), results.size());
@@ -105,7 +105,7 @@ public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
// Get the store class used in the configuration for the virtualhost.
- String fullStoreName = _serverConfiguration.getVirtualHostConfig(vhostName).getMessageStoreClass();
+ String fullStoreName = getServerConfig().getVirtualHostConfig(vhostName).getMessageStoreClass();
// Get the Simple class name from the expected class name of o.a.q.s.s.MMS
String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java
index 14e0904b78..b8a42c0ab3 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java
@@ -147,6 +147,12 @@ public class QueueLoggingTest extends AbstractTestLogging
// then close the consumer it will be autoDeleted.
_session.createConsumer(_session.createTemporaryQueue()).close();
+ if(isBroker010())
+ {
+ //auto-delete is at session close for 0-10
+ _session.close();
+ }
+
// Validation
//Ensure that we wait for the QUE log message
waitAndFindMatches("QUE-1002");
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
index a0b81a7658..6e156f091e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
@@ -181,7 +181,10 @@ public class SubscriptionLoggingTest extends AbstractTestLogging
String message = getMessageString(fromMessage(log));
assertTrue("Browser not on log message:" + message, message.contains("Browser"));
- assertTrue("AutoClose not on log message:" + message, message.contains("AutoClose"));
+ if(!isBroker010())
+ {
+ assertTrue("AutoClose not on log message:" + message, message.contains("AutoClose"));
+ }
// Beacause it is an auto close and we have no messages on the queue we
// will get a close message
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
index 17423123ca..a23e40ecce 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
@@ -68,7 +68,7 @@ public class VirtualHostLoggingTest extends AbstractTestLogging
try
{
- List<String> vhosts = Arrays.asList(_serverConfiguration.getVirtualHosts());
+ List<String> vhosts = Arrays.asList(getServerConfig().getVirtualHosts());
assertEquals("Each vhost did not create a store.", vhosts.size(), results.size());
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
index 1d1f4a53d5..51589c705f 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java
@@ -93,7 +93,7 @@ public class AddressBasedDestinationTest extends QpidBrokerTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue1' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
@@ -121,7 +121,7 @@ public class AddressBasedDestinationTest extends QpidBrokerTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name supplied in the address " +
+ assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue2' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
@@ -156,7 +156,7 @@ public class AddressBasedDestinationTest extends QpidBrokerTestCase
}
catch(JMSException e)
{
- assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " +
+ assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue3' supplied in the address " +
"doesn't resolve to an exchange or a queue"));
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
index 5e83b0569d..292bcd6039 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
@@ -266,19 +266,22 @@ public class AMQConnectionTest extends QpidBrokerTestCase
}
}
- public void testGetChannelID()
+ public void testGetChannelID() throws Exception
{
- int maxChannelID = 65536;
+ long maxChannelID = _connection.getMaximumChannelCount();
if (isBroker010())
{
- maxChannelID = Integer.MAX_VALUE+1;
+ //Usable numbers are 0 to N-1 when using 0-10
+ //and 1 to N for 0-8/0-9
+ maxChannelID = maxChannelID-1;
}
for (int j = 0; j < 3; j++)
{
- for (int i = 1; i < maxChannelID; i++)
+ int i = isBroker010() ? 0 : 1;
+ for ( ; i <= maxChannelID; i++)
{
int id = _connection.getNextChannelID();
- assertEquals("On iterartion "+j, i, id);
+ assertEquals("Unexpected number on iteration "+j, i, id);
_connection.deregisterSession(id);
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
index 512c3edca0..6d1b6de238 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
@@ -47,7 +47,7 @@ public class ConnectionCloseTest extends QpidBrokerTestCase
{
Map<Thread,StackTraceElement[]> before = Thread.getAllStackTraces();
- for (int i = 0; i < 500; i++)
+ for (int i = 0; i < 50; i++)
{
if ((i % 10) == 0)
{
@@ -81,7 +81,7 @@ public class ConnectionCloseTest extends QpidBrokerTestCase
}
Map<Thread,StackTraceElement[]> after = Thread.getAllStackTraces();
-
+
Map<Thread,StackTraceElement[]> delta = new HashMap<Thread,StackTraceElement[]>(after);
for (Thread t : before.keySet())
{
@@ -90,9 +90,12 @@ public class ConnectionCloseTest extends QpidBrokerTestCase
dumpStacks(delta);
+ int deltaThreshold = (isExternalBroker()? 1 : 2) //InVM creates more thread pools in the same VM
+ * (Runtime.getRuntime().availableProcessors() + 1) + 5;
+
assertTrue("Spurious thread creation exceeded threshold, " +
delta.size() + " threads created.",
- delta.size() < 10);
+ delta.size() < deltaThreshold);
}
private void dumpStacks(Map<Thread,StackTraceElement[]> map)
diff --git a/qpid/java/test-profiles/08StandaloneExcludes b/qpid/java/test-profiles/08StandaloneExcludes
index 214ee83bb2..b482a14c6d 100644
--- a/qpid/java/test-profiles/08StandaloneExcludes
+++ b/qpid/java/test-profiles/08StandaloneExcludes
@@ -34,6 +34,6 @@ org.apache.qpid.test.client.queue.QueuePolicyTest#testRejectPolicy
// Those tests are written against the 0.10 path
org.apache.qpid.test.unit.message.UTF8Test#*
-org.apache.qpid.client.MessageListenerTest#testSynchronousRecieveNoWait
+org.apache.qpid.client.MessageListenerTest#testSynchronousReceiveNoWait
org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnsupportedSASLMechanism
diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes
index 224d6abd10..3486d5c70c 100755
--- a/qpid/java/test-profiles/Java010Excludes
+++ b/qpid/java/test-profiles/Java010Excludes
@@ -40,26 +40,10 @@ org.apache.qpid.server.exchange.ReturnUnroutableMandatoryMessageTest#*
// QPID-1727 , QPID-1726 :c++ broker does not support flow to disk on transient queues. Also it requries a persistent store impl. for Apache
org.apache.qpid.test.client.QueueBrowsingFlowToDiskTest#*
-// 0-10 Broker does not follow the same Logging convention as the Java broker
-org.apache.qpid.server.logging.AccessControlLoggingTest#*
-org.apache.qpid.server.logging.AlertingTest#*
-org.apache.qpid.server.logging.BindingLoggingTest#*
-org.apache.qpid.server.logging.BrokerLoggingTest#*
+// 0-10 and 0-9 connections dont generate the exact same logging due to protocol differences
org.apache.qpid.server.logging.ChannelLoggingTest#testChannelStartsFlowStopped
org.apache.qpid.server.logging.ChannelLoggingTest#testChannelStartConsumerFlowStarted
-org.apache.qpid.server.logging.ChannelLoggingTest#testChannelStartConsumerFlowStarted
-org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#*
-org.apache.qpid.server.logging.DurableQueueLoggingTest#*
-org.apache.qpid.server.logging.ExchangeLoggingTest#*
-org.apache.qpid.server.logging.ManagementLoggingTest#*
-org.apache.qpid.server.logging.MemoryMessageStoreLoggingTest#*
-org.apache.qpid.server.logging.QueueLoggingTest#*
-org.apache.qpid.server.logging.SubscriptionLoggingTest#*
-org.apache.qpid.server.logging.TransientQueueLoggingTest#*
-org.apache.qpid.server.logging.VirtualHostLoggingTest#*
-org.apache.qpid.server.logging.messages.*
-org.apache.qpid.server.logging.subjects.*
-org.apache.qpid.server.logging.actors.*
+org.apache.qpid.server.logging.SubscriptionLoggingTest#testSubscriptionSuspend
// 0-10 Broker does not have a JMX connection MBean
org.apache.qpid.management.jmx.ManagementActorLoggingTest#testConnectionCloseViaManagement
@@ -93,6 +77,5 @@ org.apache.qpid.test.unit.ack.RecoverTest#testRecoverInAutoAckListener
//Temporarily adding the following until the issues are sorted out.
//Should probably raise JIRAs for them.
org.apache.qpid.transport.network.mina.MINANetworkDriverTest#*
-org.apache.qpid.test.unit.basic.LargeMessageTest#*
org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testCreateExchange
org.apache.qpid.test.client.destination.AddressBasedDestinationTest#testBrowseMode
diff --git a/qpid/tools/src/py/qmf-tool b/qpid/tools/src/py/qmf-tool
index f22caa90c7..e366d04709 100755
--- a/qpid/tools/src/py/qmf-tool
+++ b/qpid/tools/src/py/qmf-tool
@@ -128,12 +128,16 @@ class Mcli(Cmd):
try:
self.dataObject.do_query(data)
except Exception, e:
+ if e.message.__class__ == qmf2.Data:
+ e = e.message.getProperties()
print "Exception in query command:", e
def do_call(self, data):
try:
self.dataObject.do_call(data)
except Exception, e:
+ if e.message.__class__ == qmf2.Data:
+ e = e.message.getProperties()
print "Exception in call command:", e
def do_clear(self, data):
@@ -306,7 +310,15 @@ class QmfData:
methodName = tokens[1]
args = []
for arg in tokens[2:]:
- if arg[0] == '{' or arg[0] == '[' or arg.isdigit():
+ ##
+ ## If the argument is a map, list, boolean, integer, or floating (one decimal point),
+ ## run it through the Python evaluator so it is converted to the correct type.
+ ##
+ ## TODO: use a regex for this instead of this convoluted logic
+ if arg[0] == '{' or arg[0] == '[' or arg == "True" or arg == "False" or \
+ ((arg.count('.') < 2 and (arg.count('-') == 0 or \
+ (arg.count('-') == 1 and arg[0] == '-')) and \
+ arg.replace('.','').replace('-','').isdigit())):
args.append(eval(arg))
else:
args.append(arg)
diff --git a/qpid/tools/src/py/qpid-config b/qpid/tools/src/py/qpid-config
index 6686431730..9ff405541c 100755
--- a/qpid/tools/src/py/qpid-config
+++ b/qpid/tools/src/py/qpid-config
@@ -25,6 +25,56 @@ import sys
import locale
from qmf.console import Session
+usage = """
+Usage: qpid-config [OPTIONS]
+ qpid-config [OPTIONS] exchanges [filter-string]
+ qpid-config [OPTIONS] queues [filter-string]
+ qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]
+ qpid-config [OPTIONS] del exchange <name>
+ qpid-config [OPTIONS] add queue <name> [AddQueueOptions]
+ qpid-config [OPTIONS] del queue <name> [DelQueueOptions]
+ qpid-config [OPTIONS] bind <exchange-name> <queue-name> [binding-key]
+ <for type xml> [-f -|filename]
+ <for type header> [all|any] k1=v1 [, k2=v2...]
+ qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]"""
+
+description = """
+ADDRESS syntax:
+
+ [username/password@] hostname
+ ip-address [:<port>]
+
+Examples:
+
+$ qpid-config add queue q
+$ qpid-config add exchange direct d localhost:5672
+$ qpid-config exchanges 10.1.1.7:10000
+$ qpid-config queues guest/guest@broker-host:10000
+
+Add Exchange <type> values:
+
+ direct Direct exchange for point-to-point communication
+ fanout Fanout exchange for broadcast communication
+ topic Topic exchange that routes messages using binding keys with wildcards
+ headers Headers exchange that matches header fields against the binding keys
+ xml XML Exchange - allows content filtering using an XQuery
+
+
+Queue Limit Actions
+
+ none (default) - Use broker's default policy
+ reject - Reject enqueued messages
+ flow-to-disk - Page messages to disk
+ ring - Replace oldest unacquired message with new
+ ring-strict - Replace oldest message, reject if oldest is acquired
+
+Queue Ordering Policies
+
+ fifo (default) - First in, first out
+ lvq - Last Value Queue ordering, allows queue browsing
+ lvq-no-browse - Last Value Queue ordering, browsing clients may lose data"""
+
+
class Config:
def __init__(self):
self._recursive = False
@@ -85,7 +135,7 @@ class JHelpFormatter(IndentedHelpFormatter):
return ""
def Usage():
- print "qpid-config: invalid arguments. Try $ qpid-config --help"
+ print usage
exit(-1)
def OptionsAndArguments(argv):
@@ -93,54 +143,6 @@ def OptionsAndArguments(argv):
global config
- usage = """
- Usage: qpid-config [OPTIONS]
- qpid-config [OPTIONS] exchanges [filter-string]
- qpid-config [OPTIONS] queues [filter-string]
- qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]
- qpid-config [OPTIONS] del exchange <name>
- qpid-config [OPTIONS] add queue <name> [AddQueueOptions]
- qpid-config [OPTIONS] del queue <name> [DelQueueOptions]
- qpid-config [OPTIONS] bind <exchange-name> <queue-name> [binding-key]
- <for type xml> [-f -|filename]
- <for type header> [all|any] k1=v1 [, k2=v2...]
- qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]"""
-
- description = """
- ADDRESS syntax:
-
- [username/password@] hostname
- ip-address [:<port>]
-
- Examples:
-
- $ qpid-config add queue q
- $ qpid-config add exchange direct d localhost:5672
- $ qpid-config exchanges 10.1.1.7:10000
- $ qpid-config queues guest/guest@broker-host:10000
-
- Add Exchange <type> values:
-
- direct Direct exchange for point-to-point communication
- fanout Fanout exchange for broadcast communication
- topic Topic exchange that routes messages using binding keys with wildcards
- headers Headers exchange that matches header fields against the binding keys
- xml XML Exchange - allows content filtering using an XQuery
-
-
- Queue Limit Actions
-
- none (default) - Use broker's default policy
- reject - Reject enqueued messages
- flow-to-disk - Page messages to disk
- ring - Replace oldest unacquired message with new
- ring-strict - Replace oldest message, reject if oldest is acquired
-
- Queue Ordering Policies
-
- fifo (default) - First in, first out
- lvq - Last Value Queue ordering, allows queue browsing
- lvq-no-browse - Last Value Queue ordering, browsing clients may lose data"""
parser = OptionParser(usage=usage,
description=description,
@@ -264,7 +266,7 @@ def OptionsAndArguments(argv):
#
# accept -f followed by either
-# a filename or "-", for stdin. pull the bits into a string, to be
+# a filename or "-", for stdin. pull the bits into a string, to be
# passed to the xml binding.
#
def snarf_xquery_args():
@@ -278,7 +280,7 @@ def snarf_xquery_args():
res = f.read()
f.close()
return [True, res]
-
+
#
# look for "any"/"all" and grok the rest of argv into a map
#
@@ -303,7 +305,7 @@ class BrokerManager:
self.brokerName = None
self.qmf = None
self.broker = None
- self.mechanism = None
+ self.mechanism = None
def SetBroker(self, brokerUrl, mechanism):
self.url = brokerUrl
@@ -379,7 +381,7 @@ class BrokerManager:
if queue != None:
qname = queue.name
print " bind [%s] => %s" % (bind.bindingKey, qname)
-
+
def QueueList(self, filter):
queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
@@ -540,7 +542,7 @@ class BrokerManager:
# this checks/imports the -f arg
[ok, xquery] = snarf_xquery_args()
_args = { "xquery" : xquery }
- else:
+ else:
if res.type == "headers":
[ok, op, kv] = snarf_header_args(args[3:])
_args = kv
@@ -657,4 +659,4 @@ def main(argv=None):
if __name__ == "__main__":
sys.exit(main())
-
+
diff --git a/qpid/tools/src/py/qpid-route b/qpid/tools/src/py/qpid-route
index 6449ad6372..3c4de85d1e 100755
--- a/qpid/tools/src/py/qpid-route
+++ b/qpid/tools/src/py/qpid-route
@@ -26,6 +26,31 @@ import os
import locale
from qmf.console import Session, BrokerURL
+usage = """
+Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list]
+ qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange>
+
+ qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list] [mechanism]
+ qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key>
+ qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue>
+ qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue>
+ qpid-route [OPTIONS] route list [<dest-broker>]
+ qpid-route [OPTIONS] route flush [<dest-broker>]
+ qpid-route [OPTIONS] route map [<broker>]
+
+ qpid-route [OPTIONS] link add <dest-broker> <src-broker>
+ qpid-route [OPTIONS] link del <dest-broker> <src-broker>
+ qpid-route [OPTIONS] link list [<dest-broker>]"""
+
+description = """
+ADDRESS syntax:
+
+ [username/password@] hostname
+ ip-address [:<port>]"""
+
+def Usage():
+ print usage
+
class Config:
def __init__(self):
self._verbose = False
@@ -54,35 +79,7 @@ class JHelpFormatter(IndentedHelpFormatter):
else:
return ""
-def usage(parser):
- parser.print_help()
- exit(-1)
-
-usage = """
-Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list]
- qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange>
-
- qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list] [mechanism]
- qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key>
- qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue>
- qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue>
- qpid-route [OPTIONS] route list [<dest-broker>]
- qpid-route [OPTIONS] route flush [<dest-broker>]
- qpid-route [OPTIONS] route map [<broker>]
-
- qpid-route [OPTIONS] link add <dest-broker> <src-broker>
- qpid-route [OPTIONS] link del <dest-broker> <src-broker>
- qpid-route [OPTIONS] link list [<dest-broker>]"""
-
-description = """
-ADDRESS syntax:
-
- [username/password@] hostname
- ip-address [:<port>]"""
-
-
def OptionsAndArguments(argv):
-
parser = OptionParser(usage=usage,
description=description,
formatter=JHelpFormatter())
@@ -472,7 +469,7 @@ class RoutePair:
self.bidir = True
return True
return False
-
+
def YN(val):
if val == 1:
@@ -485,7 +482,8 @@ def main(argv=None):
args = OptionsAndArguments(argv)
nargs = len(args)
if nargs < 2:
- usage(parser)
+ Usage()
+ return(-1)
if nargs == 2:
localBroker = socket.gethostname()
@@ -507,11 +505,13 @@ def main(argv=None):
if group == "link":
if cmd == "add":
if nargs != 4:
- usage(parser)
+ Usage()
+ return(-1)
rm.addLink(remoteBroker)
elif cmd == "del":
if nargs != 4:
- usage(parser)
+ Usage()
+ return(-1)
rm.delLink(remoteBroker)
elif cmd == "list":
rm.listLinks()
@@ -519,35 +519,39 @@ def main(argv=None):
elif group == "dynamic":
if cmd == "add":
if nargs < 5 or nargs > 7:
- usage(parser)
+ Usage()
+ return(-1)
tag = ""
excludes = ""
mech = "PLAIN"
- if nargs > 5: tag = args[5]
- if nargs > 6: excludes = args[6]
+ if nargs > 5: tag = args[5]
+ if nargs > 6: excludes = args[6]
rm.addRoute(remoteBroker, args[4], "", tag, excludes, mech, dynamic=True)
elif cmd == "del":
if nargs != 5:
- usage(parser)
+ Usage()
+ return(-1)
else:
rm.delRoute(remoteBroker, args[4], "", dynamic=True)
elif group == "route":
if cmd == "add":
if nargs < 6 or nargs > 9:
- usage(parser)
+ Usage()
+ return(-1)
tag = ""
excludes = ""
mech = "PLAIN"
- if nargs > 6: tag = args[6]
+ if nargs > 6: tag = args[6]
if nargs > 7: excludes = args[7]
if nargs > 8: mech = args[8]
rm.addRoute(remoteBroker, args[4], args[5], tag, excludes, mech, dynamic=False)
elif cmd == "del":
if nargs != 6:
- usage(parser)
+ Usage()
+ return(-1)
rm.delRoute(remoteBroker, args[4], args[5], dynamic=False)
elif cmd == "map":
rm.mapRoutes()
@@ -557,17 +561,20 @@ def main(argv=None):
elif cmd == "flush":
rm.clearAllRoutes()
else:
- usage(parser)
+ Usage()
+ return(-1)
elif group == "queue":
if nargs != 6:
- usage(parser)
+ Usage()
+ return(-1)
if cmd == "add":
rm.addQueueRoute(remoteBroker, exchange=args[4], queue=args[5])
elif cmd == "del":
rm.delQueueRoute(remoteBroker, exchange=args[4], queue=args[5])
else:
- usage(parser)
+ Usage()
+ return(-1)
except Exception,e:
if rm: