summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2013-03-27 21:58:51 +0000
committerRobert Godfrey <rgodfrey@apache.org>2013-03-27 21:58:51 +0000
commit32972ee3c75877f960c42401ddab86e0f1f02bef (patch)
tree851e925c187741f10e3e1700a1d26104c0582efc
parentf576e5bc80863ac9a2f89bef42d1414d7f9a4605 (diff)
downloadqpid-python-32972ee3c75877f960c42401ddab86e0f1f02bef.tar.gz
NO-JIRA : merging from trunk to keep branch up to date
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-4659@1461870 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/QPID_VERSION.txt2
-rw-r--r--qpid/cpp/examples/messaging/client.cpp4
-rw-r--r--qpid/cpp/include/qpid/messaging/Address.h1
-rw-r--r--qpid/cpp/include/qpid/messaging/Receiver.h6
-rw-r--r--qpid/cpp/include/qpid/messaging/Sender.h6
-rw-r--r--qpid/cpp/src/CMakeLists.txt1
-rw-r--r--qpid/cpp/src/Makefile.am1
-rw-r--r--qpid/cpp/src/qpid/amqp/descriptors.h3
-rw-r--r--qpid/cpp/src/qpid/broker/Selector.cpp7
-rw-r--r--qpid/cpp/src/qpid/broker/SelectorExpression.cpp169
-rw-r--r--qpid/cpp/src/qpid/broker/SelectorToken.cpp11
-rw-r--r--qpid/cpp/src/qpid/broker/SelectorToken.h16
-rw-r--r--qpid/cpp/src/qpid/broker/SelectorValue.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/SemanticState.cpp4
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Connection.cpp8
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Connection.h4
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Filter.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Interconnect.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/ProtocolPlugin.cpp25
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Sasl.cpp4
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Sasl.h2
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Session.cpp38
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Session.h1
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp9
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp5
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h1
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp5
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h1
-rw-r--r--qpid/cpp/src/qpid/messaging/Address.cpp48
-rw-r--r--qpid/cpp/src/qpid/messaging/AddressImpl.h45
-rw-r--r--qpid/cpp/src/qpid/messaging/AddressParser.cpp6
-rw-r--r--qpid/cpp/src/qpid/messaging/Receiver.cpp2
-rw-r--r--qpid/cpp/src/qpid/messaging/ReceiverImpl.h2
-rw-r--r--qpid/cpp/src/qpid/messaging/Sender.cpp3
-rw-r--r--qpid/cpp/src/qpid/messaging/SenderImpl.h2
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp36
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp22
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp2
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp30
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp5
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.h1
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp23
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/SenderContext.h3
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp5
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/SenderHandle.h1
-rw-r--r--qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp6
-rw-r--r--qpid/cpp/src/qpid/xml/XmlExchange.cpp13
-rw-r--r--qpid/cpp/src/qpid/xml/XmlExchange.h2
-rw-r--r--qpid/cpp/src/tests/CMakeLists.txt2
-rw-r--r--qpid/cpp/src/tests/Makefile.am4
-rw-r--r--qpid/cpp/src/tests/Selector.cpp6
-rwxr-xr-xqpid/cpp/src/tests/ping_broker7
-rw-r--r--qpid/cpp/src/tests/qpidt141
-rw-r--r--qpid/cpp/src/tests/ssl.mk2
-rwxr-xr-xqpid/cpp/src/tests/ssl_test145
-rw-r--r--qpid/doc/book/src/java-broker/commonEntities.xml2
-rwxr-xr-xqpid/extras/qmf/setup.py2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java20
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js142
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js365
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html133
-rwxr-xr-xqpid/java/broker/src/main/java/broker.bnd2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationEntryStore.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/AuthenticationProviderRecoverer.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java13
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java24
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/updater/ChangeAttributesTask.java62
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java54
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java34
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactory.java24
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java300
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java48
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java78
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java16
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractPrincipalDatabaseAuthManagerFactory.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java40
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java2
-rw-r--r--qpid/java/broker/src/main/resources/initial-store.json1
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java4
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java5
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java16
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java10
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactoryTest.java50
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java8
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java6
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java4
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java53
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexServerTest.java2
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java4
-rwxr-xr-xqpid/java/client/src/main/java/client.bnd2
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java15
-rw-r--r--qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java8
-rw-r--r--qpid/java/common.xml4
-rwxr-xr-xqpid/java/common/src/main/java/common.bnd2
-rw-r--r--qpid/java/management/common/src/main/java/management-common.bnd2
-rw-r--r--qpid/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json2425
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java13
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java106
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java12
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java2
-rw-r--r--qpid/packaging/windows/INSTALL_NOTES.html8
-rw-r--r--qpid/packaging/windows/installer.proj2
-rw-r--r--qpid/python/qpid/messaging/endpoints.py5
-rw-r--r--qpid/python/qpid/messaging/transports.py71
-rwxr-xr-xqpid/python/setup.py2
-rwxr-xr-xqpid/tests/setup.py2
-rwxr-xr-xqpid/tools/setup.py2
-rw-r--r--qpid/tools/src/ruby/qpid_management/.gitignore3
-rw-r--r--qpid/tools/src/ruby/qpid_management/.rspec1
-rw-r--r--qpid/tools/src/ruby/qpid_management/Gemfile30
-rw-r--r--qpid/tools/src/ruby/qpid_management/Gemfile.lock55
-rw-r--r--qpid/tools/src/ruby/qpid_management/Rakefile27
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb81
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb38
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb31
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb39
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb278
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb173
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb126
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb26
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb51
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb28
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb44
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb26
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb35
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb34
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb97
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb38
-rw-r--r--qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb35
-rw-r--r--qpid/tools/src/ruby/qpid_management/qpid_management.gemspec36
-rw-r--r--qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb43
-rw-r--r--qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb373
-rw-r--r--qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb21
147 files changed, 4166 insertions, 2853 deletions
diff --git a/qpid/QPID_VERSION.txt b/qpid/QPID_VERSION.txt
index 5320adc1c9..39010d220e 100644
--- a/qpid/QPID_VERSION.txt
+++ b/qpid/QPID_VERSION.txt
@@ -1 +1 @@
-0.21
+0.23
diff --git a/qpid/cpp/examples/messaging/client.cpp b/qpid/cpp/examples/messaging/client.cpp
index f0ecd96206..983f0a8878 100644
--- a/qpid/cpp/examples/messaging/client.cpp
+++ b/qpid/cpp/examples/messaging/client.cpp
@@ -48,8 +48,8 @@ int main(int argc, char** argv) {
Sender sender = session.createSender("service_queue");
//create temp queue & receiver...
- Address responseQueue("#response-queue; {create:always, delete:always}");
- Receiver receiver = session.createReceiver(responseQueue);
+ Receiver receiver = session.createReceiver("#");
+ Address responseQueue = receiver.getAddress();
// Now send some messages ...
string s[] = {
diff --git a/qpid/cpp/include/qpid/messaging/Address.h b/qpid/cpp/include/qpid/messaging/Address.h
index 63dce0c49d..224a70b193 100644
--- a/qpid/cpp/include/qpid/messaging/Address.h
+++ b/qpid/cpp/include/qpid/messaging/Address.h
@@ -153,6 +153,7 @@ class QPID_MESSAGING_CLASS_EXTERN Address
QPID_MESSAGING_EXTERN bool operator !() const;
private:
AddressImpl* impl;
+ friend class AddressImpl;
};
#ifndef SWIG
diff --git a/qpid/cpp/include/qpid/messaging/Receiver.h b/qpid/cpp/include/qpid/messaging/Receiver.h
index 13317dfcbd..6c6fdaa7cb 100644
--- a/qpid/cpp/include/qpid/messaging/Receiver.h
+++ b/qpid/cpp/include/qpid/messaging/Receiver.h
@@ -34,6 +34,7 @@ namespace messaging {
template <class> class PrivateImplRef;
#endif
+class Address;
class Message;
class ReceiverImpl;
class Session;
@@ -134,6 +135,11 @@ class QPID_MESSAGING_CLASS_EXTERN Receiver : public qpid::messaging::Handle<Rece
*/
QPID_MESSAGING_EXTERN Session getSession() const;
+ /**
+ * Returns an address for this receiver.
+ */
+ QPID_MESSAGING_EXTERN Address getAddress() const;
+
#ifndef SWIG
private:
friend class qpid::messaging::PrivateImplRef<Receiver>;
diff --git a/qpid/cpp/include/qpid/messaging/Sender.h b/qpid/cpp/include/qpid/messaging/Sender.h
index 8e1c5846e9..9c7bca1905 100644
--- a/qpid/cpp/include/qpid/messaging/Sender.h
+++ b/qpid/cpp/include/qpid/messaging/Sender.h
@@ -34,6 +34,7 @@ namespace messaging {
#ifndef SWIG
template <class> class PrivateImplRef;
#endif
+class Address;
class Message;
class SenderImpl;
class Session;
@@ -89,6 +90,11 @@ class QPID_MESSAGING_CLASS_EXTERN Sender : public qpid::messaging::Handle<Sender
* Returns a handle to the session associated with this sender.
*/
QPID_MESSAGING_EXTERN Session getSession() const;
+
+ /**
+ * Returns an address for this sender.
+ */
+ QPID_MESSAGING_EXTERN Address getAddress() const;
#ifndef SWIG
private:
friend class qpid::messaging::PrivateImplRef<Sender>;
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index ef68d79fb2..bb00046857 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -1063,6 +1063,7 @@ install_pdb (qpidclient ${QPID_COMPONENT_CLIENT})
set (qpidmessaging_SOURCES_hidden
qpid/messaging/AddressParser.h
+ qpid/messaging/AddressImpl.h
qpid/messaging/ConnectionImpl.h
qpid/messaging/ReceiverImpl.h
qpid/messaging/SessionImpl.h
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 42d5c60475..cad41bca86 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -935,6 +935,7 @@ libqpidtypes_la_LDFLAGS = -version-info $(QPIDTYPES_VERSION_INFO)
libqpidmessaging_la_LIBADD = libqpidclient.la libqpidtypes.la
libqpidmessaging_la_SOURCES = \
qpid/messaging/Address.cpp \
+ qpid/messaging/AddressImpl.h \
qpid/messaging/AddressParser.h \
qpid/messaging/AddressParser.cpp \
qpid/messaging/Connection.cpp \
diff --git a/qpid/cpp/src/qpid/amqp/descriptors.h b/qpid/cpp/src/qpid/amqp/descriptors.h
index 0a3e71fe6d..11bb7df6bb 100644
--- a/qpid/cpp/src/qpid/amqp/descriptors.h
+++ b/qpid/cpp/src/qpid/amqp/descriptors.h
@@ -78,10 +78,11 @@ const Descriptor SASL_OUTCOME(SASL_OUTCOME_CODE);
namespace filters {
const std::string LEGACY_DIRECT_FILTER_SYMBOL("apache.org:legacy-amqp-direct-binding:string");
const std::string LEGACY_TOPIC_FILTER_SYMBOL("apache.org:legacy-amqp-topic-binding:string");
-const std::string QPID_SELECTOR_FILTER_SYMBOL("qpid.apache.org:selector-filter:string");
+const std::string SELECTOR_FILTER_SYMBOL("apache.org:selector-filter:string");
const uint64_t LEGACY_DIRECT_FILTER_CODE(0x0000468C00000000ULL);
const uint64_t LEGACY_TOPIC_FILTER_CODE(0x0000468C00000001ULL);
+const uint64_t SELECTOR_FILTER_CODE(0x0000468C00000004ULL);
}
}} // namespace qpid::amqp
diff --git a/qpid/cpp/src/qpid/broker/Selector.cpp b/qpid/cpp/src/qpid/broker/Selector.cpp
index a6378f1910..3e7e044d5d 100644
--- a/qpid/cpp/src/qpid/broker/Selector.cpp
+++ b/qpid/cpp/src/qpid/broker/Selector.cpp
@@ -147,7 +147,8 @@ const Value& MessageSelectorEnv::value(const string& identifier) const
return returnedValues[identifier];
}
-Selector::Selector(const string& e) :
+Selector::Selector(const string& e)
+try :
parse(TopExpression::parse(e)),
expression(e)
{
@@ -159,6 +160,10 @@ Selector::Selector(const string& e) :
QPID_LOG(debug, "Selector parsed[" << e << "] into: " << ss.str());
}
}
+catch (std::range_error& ex) {
+ QPID_LOG(debug, "Selector failed[" << e << "] -> " << ex.what());
+ throw;
+}
Selector::~Selector()
{
diff --git a/qpid/cpp/src/qpid/broker/SelectorExpression.cpp b/qpid/cpp/src/qpid/broker/SelectorExpression.cpp
index 2eaffd7ccb..e64fd327d5 100644
--- a/qpid/cpp/src/qpid/broker/SelectorExpression.cpp
+++ b/qpid/cpp/src/qpid/broker/SelectorExpression.cpp
@@ -132,12 +132,11 @@ public:
virtual BoolOrNone eval(Expression&, Expression&, const SelectorEnv&) const = 0;
};
-template <typename T>
class UnaryBooleanOperator {
public:
virtual ~UnaryBooleanOperator() {}
virtual void repr(ostream&) const = 0;
- virtual BoolOrNone eval(T&, const SelectorEnv&) const = 0;
+ virtual BoolOrNone eval(Expression&, const SelectorEnv&) const = 0;
};
class ArithmeticOperator {
@@ -170,8 +169,7 @@ ostream& operator<<(ostream& os, const ComparisonOperator& e)
return os;
}
-template <typename T>
-ostream& operator<<(ostream& os, const UnaryBooleanOperator<T>& e)
+ostream& operator<<(ostream& os, const UnaryBooleanOperator& e)
{
e.repr(os);
return os;
@@ -260,13 +258,12 @@ public:
}
};
-template <typename T>
class UnaryBooleanExpression : public BoolExpression {
- UnaryBooleanOperator<T>* op;
- boost::scoped_ptr<T> e1;
+ UnaryBooleanOperator* op;
+ boost::scoped_ptr<Expression> e1;
public:
- UnaryBooleanExpression(UnaryBooleanOperator<T>* o, T* e) :
+ UnaryBooleanExpression(UnaryBooleanOperator* o, Expression* e) :
op(o),
e1(e)
{}
@@ -287,7 +284,7 @@ class LikeExpression : public BoolExpression {
static string toRegex(const string& s, const string& escape) {
string regex("^");
- if (escape.size()>1) throw std::range_error("Illegal escape char");
+ if (escape.size()>1) throw std::logic_error("Internal error");
char e = 0;
if (escape.size()==1) {
e = escape[0];
@@ -594,7 +591,7 @@ class Greq : public ComparisonOperator {
};
// "IS NULL"
-class IsNull : public UnaryBooleanOperator<Expression> {
+class IsNull : public UnaryBooleanOperator {
void repr(ostream& os) const {
os << "IsNull";
}
@@ -605,7 +602,7 @@ class IsNull : public UnaryBooleanOperator<Expression> {
};
// "IS NOT NULL"
-class IsNonNull : public UnaryBooleanOperator<Expression> {
+class IsNonNull : public UnaryBooleanOperator {
void repr(ostream& os) const {
os << "IsNonNull";
}
@@ -616,7 +613,7 @@ class IsNonNull : public UnaryBooleanOperator<Expression> {
};
// "NOT"
-class Not : public UnaryBooleanOperator<Expression> {
+class Not : public UnaryBooleanOperator {
void repr(ostream& os) const {
os << "NOT";
}
@@ -696,14 +693,6 @@ Div div;
////////////////////////////////////////////////////
-Expression* parseOrExpression(Tokeniser&);
-Expression* parseAndExpression(Tokeniser&);
-Expression* parseComparisonExpression(Tokeniser&);
-Expression* parseAddExpression(Tokeniser&);
-Expression* parseMultiplyExpression(Tokeniser&);
-Expression* parseUnaryArithExpression(Tokeniser&);
-Expression* parsePrimaryExpression(Tokeniser&);
-
// Top level parser
class TopBoolExpression : public TopExpression {
boost::scoped_ptr<Expression> expression;
@@ -724,24 +713,28 @@ public:
{}
};
-TopExpression* TopExpression::parse(const string& exp)
-{
- string::const_iterator s = exp.begin();
- string::const_iterator e = exp.end();
- Tokeniser tokeniser(s,e);
- std::auto_ptr<Expression> b(parseOrExpression(tokeniser));
- if (!b.get()) throw std::range_error("Illegal selector: couldn't parse");
- if (tokeniser.nextToken().type != T_EOS) throw std::range_error("Illegal selector: too much input");
- return new TopBoolExpression(b.release());
+void throwParseError(Tokeniser& tokeniser, const string& msg) {
+ tokeniser.returnTokens();
+ string error("Illegal selector: '");
+ error += tokeniser.nextToken().val;
+ error += "': ";
+ error += msg;
+ throw std::range_error(error);
}
-Expression* parseOrExpression(Tokeniser& tokeniser)
+class Parse {
+
+friend TopExpression* TopExpression::parse(const string&);
+
+string error;
+
+Expression* orExpression(Tokeniser& tokeniser)
{
- std::auto_ptr<Expression> e(parseAndExpression(tokeniser));
+ std::auto_ptr<Expression> e(andExpression(tokeniser));
if (!e.get()) return 0;
while ( tokeniser.nextToken().type==T_OR ) {
std::auto_ptr<Expression> e1(e);
- std::auto_ptr<Expression> e2(parseAndExpression(tokeniser));
+ std::auto_ptr<Expression> e2(andExpression(tokeniser));
if (!e2.get()) return 0;
e.reset(new OrExpression(e1.release(), e2.release()));
}
@@ -749,13 +742,13 @@ Expression* parseOrExpression(Tokeniser& tokeniser)
return e.release();
}
-Expression* parseAndExpression(Tokeniser& tokeniser)
+Expression* andExpression(Tokeniser& tokeniser)
{
- std::auto_ptr<Expression> e(parseComparisonExpression(tokeniser));
+ std::auto_ptr<Expression> e(comparisonExpression(tokeniser));
if (!e.get()) return 0;
while ( tokeniser.nextToken().type==T_AND ) {
std::auto_ptr<Expression> e1(e);
- std::auto_ptr<Expression> e2(parseComparisonExpression(tokeniser));
+ std::auto_ptr<Expression> e2(comparisonExpression(tokeniser));
if (!e2.get()) return 0;
e.reset(new AndExpression(e1.release(), e2.release()));
}
@@ -763,15 +756,24 @@ Expression* parseAndExpression(Tokeniser& tokeniser)
return e.release();
}
-BoolExpression* parseSpecialComparisons(Tokeniser& tokeniser, std::auto_ptr<Expression> e1) {
+BoolExpression* specialComparisons(Tokeniser& tokeniser, std::auto_ptr<Expression> e1) {
switch (tokeniser.nextToken().type) {
case T_LIKE: {
const Token t = tokeniser.nextToken();
- if ( t.type!=T_STRING ) return 0;
+ if ( t.type!=T_STRING ) {
+ error = "expected string after LIKE";
+ return 0;
+ }
// Check for "ESCAPE"
if ( tokeniser.nextToken().type==T_ESCAPE ) {
const Token e = tokeniser.nextToken();
- if ( e.type!=T_STRING ) return 0;
+ if ( e.type!=T_STRING ) {
+ error = "expected string after ESCAPE";
+ return 0;
+ }
+ if (e.val.size()>1) {
+ throwParseError(tokeniser, "single character string required after ESCAPE");
+ }
return new LikeExpression(e1.release(), t.val, e.val);
} else {
tokeniser.returnTokens();
@@ -779,41 +781,51 @@ BoolExpression* parseSpecialComparisons(Tokeniser& tokeniser, std::auto_ptr<Expr
}
}
case T_BETWEEN: {
- std::auto_ptr<Expression> lower(parseAddExpression(tokeniser));
+ std::auto_ptr<Expression> lower(addExpression(tokeniser));
if ( !lower.get() ) return 0;
- if ( tokeniser.nextToken().type!=T_AND ) return 0;
- std::auto_ptr<Expression> upper(parseAddExpression(tokeniser));
+ if ( tokeniser.nextToken().type!=T_AND ) {
+ error = "expected AND after BETWEEN";
+ return 0;
+ }
+ std::auto_ptr<Expression> upper(addExpression(tokeniser));
if ( !upper.get() ) return 0;
return new BetweenExpression(e1.release(), lower.release(), upper.release());
}
case T_IN: {
- if ( tokeniser.nextToken().type!=T_LPAREN ) return 0;
+ if ( tokeniser.nextToken().type!=T_LPAREN ) {
+ error = "missing '(' after IN";
+ return 0;
+ }
boost::ptr_vector<Expression> list;
do {
- std::auto_ptr<Expression> e(parseAddExpression(tokeniser));
+ std::auto_ptr<Expression> e(addExpression(tokeniser));
if (!e.get()) return 0;
list.push_back(e.release());
} while (tokeniser.nextToken().type==T_COMMA);
tokeniser.returnTokens();
- if ( tokeniser.nextToken().type!=T_RPAREN ) return 0;
+ if ( tokeniser.nextToken().type!=T_RPAREN ) {
+ error = "missing ',' or ')' after IN";
+ return 0;
+ }
return new InExpression(e1.release(), list);
}
default:
+ error = "expected LIKE, IN or BETWEEN";
return 0;
}
}
-Expression* parseComparisonExpression(Tokeniser& tokeniser)
+Expression* comparisonExpression(Tokeniser& tokeniser)
{
const Token t = tokeniser.nextToken();
if ( t.type==T_NOT ) {
- std::auto_ptr<Expression> e(parseComparisonExpression(tokeniser));
+ std::auto_ptr<Expression> e(comparisonExpression(tokeniser));
if (!e.get()) return 0;
- return new UnaryBooleanExpression<Expression>(&notOp, e.release());
+ return new UnaryBooleanExpression(&notOp, e.release());
}
tokeniser.returnTokens();
- std::auto_ptr<Expression> e1(parseAddExpression(tokeniser));
+ std::auto_ptr<Expression> e1(addExpression(tokeniser));
if (!e1.get()) return 0;
switch (tokeniser.nextToken().type) {
@@ -822,23 +834,24 @@ Expression* parseComparisonExpression(Tokeniser& tokeniser)
// The rest must be T_NULL or T_NOT, T_NULL
switch (tokeniser.nextToken().type) {
case T_NULL:
- return new UnaryBooleanExpression<Expression>(&isNullOp, e1.release());
+ return new UnaryBooleanExpression(&isNullOp, e1.release());
case T_NOT:
if ( tokeniser.nextToken().type == T_NULL)
- return new UnaryBooleanExpression<Expression>(&isNonNullOp, e1.release());
+ return new UnaryBooleanExpression(&isNonNullOp, e1.release());
default:
+ error = "expected NULL or NOT NULL after IS";
return 0;
}
case T_NOT: {
- std::auto_ptr<BoolExpression> e(parseSpecialComparisons(tokeniser, e1));
+ std::auto_ptr<BoolExpression> e(specialComparisons(tokeniser, e1));
if (!e.get()) return 0;
- return new UnaryBooleanExpression<Expression>(&notOp, e.release());
+ return new UnaryBooleanExpression(&notOp, e.release());
}
case T_BETWEEN:
case T_LIKE:
case T_IN: {
tokeniser.returnTokens();
- return parseSpecialComparisons(tokeniser, e1);
+ return specialComparisons(tokeniser, e1);
}
default:
break;
@@ -858,15 +871,15 @@ Expression* parseComparisonExpression(Tokeniser& tokeniser)
return e1.release();
}
- std::auto_ptr<Expression> e2(parseAddExpression(tokeniser));
+ std::auto_ptr<Expression> e2(addExpression(tokeniser));
if (!e2.get()) return 0;
return new ComparisonExpression(op, e1.release(), e2.release());
}
-Expression* parseAddExpression(Tokeniser& tokeniser)
+Expression* addExpression(Tokeniser& tokeniser)
{
- std::auto_ptr<Expression> e(parseMultiplyExpression(tokeniser));
+ std::auto_ptr<Expression> e(multiplyExpression(tokeniser));
if (!e.get()) return 0;
Token t = tokeniser.nextToken();
@@ -876,10 +889,11 @@ Expression* parseAddExpression(Tokeniser& tokeniser)
case T_PLUS: op = &add; break;
case T_MINUS: op = &sub; break;
default:
+ error = "internal error processing binary + or -";
return 0;
}
std::auto_ptr<Expression> e1(e);
- std::auto_ptr<Expression> e2(parseMultiplyExpression(tokeniser));
+ std::auto_ptr<Expression> e2(multiplyExpression(tokeniser));
if (!e2.get()) return 0;
e.reset(new ArithmeticExpression(op, e1.release(), e2.release()));
t = tokeniser.nextToken();
@@ -889,9 +903,9 @@ Expression* parseAddExpression(Tokeniser& tokeniser)
return e.release();
}
-Expression* parseMultiplyExpression(Tokeniser& tokeniser)
+Expression* multiplyExpression(Tokeniser& tokeniser)
{
- std::auto_ptr<Expression> e(parseUnaryArithExpression(tokeniser));
+ std::auto_ptr<Expression> e(unaryArithExpression(tokeniser));
if (!e.get()) return 0;
Token t = tokeniser.nextToken();
@@ -901,10 +915,11 @@ Expression* parseMultiplyExpression(Tokeniser& tokeniser)
case T_MULT: op = &mult; break;
case T_DIV: op = &div; break;
default:
+ error = "internal error processing * or /";
return 0;
}
std::auto_ptr<Expression> e1(e);
- std::auto_ptr<Expression> e2(parseMultiplyExpression(tokeniser));
+ std::auto_ptr<Expression> e2(unaryArithExpression(tokeniser));
if (!e2.get()) return 0;
e.reset(new ArithmeticExpression(op, e1.release(), e2.release()));
t = tokeniser.nextToken();
@@ -914,20 +929,23 @@ Expression* parseMultiplyExpression(Tokeniser& tokeniser)
return e.release();
}
-Expression* parseUnaryArithExpression(Tokeniser& tokeniser)
+Expression* unaryArithExpression(Tokeniser& tokeniser)
{
const Token t = tokeniser.nextToken();
switch (t.type) {
case T_LPAREN: {
- std::auto_ptr<Expression> e(parseOrExpression(tokeniser));
+ std::auto_ptr<Expression> e(orExpression(tokeniser));
if (!e.get()) return 0;
- if ( tokeniser.nextToken().type!=T_RPAREN ) return 0;
+ if ( tokeniser.nextToken().type!=T_RPAREN ) {
+ error = "missing ')' after '('";
+ return 0;
+ }
return e.release();
}
case T_PLUS:
break; // Unary + is no op
case T_MINUS: {
- std::auto_ptr<Expression> e(parseUnaryArithExpression(tokeniser));
+ std::auto_ptr<Expression> e(unaryArithExpression(tokeniser));
if (!e.get()) return 0;
return new UnaryArithExpression(&negate, e.release());
}
@@ -936,11 +954,11 @@ Expression* parseUnaryArithExpression(Tokeniser& tokeniser)
}
tokeniser.returnTokens();
- std::auto_ptr<Expression> e(parsePrimaryExpression(tokeniser));
+ std::auto_ptr<Expression> e(primaryExpression(tokeniser));
return e.release();
}
-Expression* parsePrimaryExpression(Tokeniser& tokeniser)
+Expression* primaryExpression(Tokeniser& tokeniser)
{
const Token& t = tokeniser.nextToken();
switch (t.type) {
@@ -957,8 +975,27 @@ Expression* parsePrimaryExpression(Tokeniser& tokeniser)
case T_NUMERIC_APPROX:
return new Literal(boost::lexical_cast<double>(t.val));
default:
+ error = "expected literal or identifier";
return 0;
}
}
+};
+
+TopExpression* TopExpression::parse(const string& exp)
+{
+ string::const_iterator s = exp.begin();
+ string::const_iterator e = exp.end();
+ Tokeniser tokeniser(s,e);
+ Parse parse;
+ std::auto_ptr<Expression> b(parse.orExpression(tokeniser));
+ if (!b.get()) {
+ throwParseError(tokeniser, parse.error);
+ }
+ if (tokeniser.nextToken().type != T_EOS) {
+ throwParseError(tokeniser, "extra input");
+ }
+ return new TopBoolExpression(b.release());
+}
+
}}
diff --git a/qpid/cpp/src/qpid/broker/SelectorToken.cpp b/qpid/cpp/src/qpid/broker/SelectorToken.cpp
index 1e84834e18..e745bc3889 100644
--- a/qpid/cpp/src/qpid/broker/SelectorToken.cpp
+++ b/qpid/cpp/src/qpid/broker/SelectorToken.cpp
@@ -132,8 +132,8 @@ bool processString(std::string::const_iterator& s, std::string::const_iterator&
++q;
}
+ tok = Token(T_STRING, s, content);
s = q;
- tok = Token(T_STRING, content);
return true;
}
@@ -171,7 +171,7 @@ bool tokenise(std::string::const_iterator& s, std::string::const_iterator& e, To
while (true)
switch (state) {
case START:
- if (t==e) {tok = Token(T_EOS, ""); return true;}
+ if (t==e) {tok = Token(T_EOS, s, "<END>"); return true;}
else switch (*t) {
case '(': tokType = T_LPAREN; state = ACCEPT_INC; continue;
case ')': tokType = T_RPAREN; state = ACCEPT_INC; continue;
@@ -259,6 +259,7 @@ bool tokenise(std::string::const_iterator& s, std::string::const_iterator& e, To
Tokeniser::Tokeniser(const std::string::const_iterator& s, const std::string::const_iterator& e) :
tokp(0),
+ inStart(s),
inp(s),
inEnd(e)
{
@@ -294,5 +295,11 @@ void Tokeniser::returnTokens(unsigned int n)
tokp-=n;
}
+std::string Tokeniser::remaining()
+{
+ Token& currentTok = tokens[tokp];
+ return std::string(currentTok.tokenStart, inEnd);
+}
+
}}
diff --git a/qpid/cpp/src/qpid/broker/SelectorToken.h b/qpid/cpp/src/qpid/broker/SelectorToken.h
index 91fb1d5c36..bd60b69dce 100644
--- a/qpid/cpp/src/qpid/broker/SelectorToken.h
+++ b/qpid/cpp/src/qpid/broker/SelectorToken.h
@@ -67,6 +67,7 @@ typedef enum {
struct Token {
TokenType type;
std::string val;
+ std::string::const_iterator tokenStart;
Token()
{}
@@ -76,14 +77,23 @@ struct Token {
val(v)
{}
+ Token(TokenType t, const std::string::const_iterator& s, const std::string& v) :
+ type(t),
+ val(v),
+ tokenStart(s)
+ {}
+
Token(TokenType t, const std::string::const_iterator& s, const std::string::const_iterator& e) :
type(t),
- val(std::string(s,e))
+ val(std::string(s,e)),
+ tokenStart(s)
{}
bool operator==(const Token& r) const
{
- return type == r.type && val == r.val;
+ return
+ (type == T_EOS && r.type == T_EOS) ||
+ (type == r.type && val == r.val);
}
};
@@ -100,6 +110,7 @@ class Tokeniser {
std::vector<Token> tokens;
unsigned int tokp;
+ std::string::const_iterator inStart;
std::string::const_iterator inp;
std::string::const_iterator inEnd;
@@ -107,6 +118,7 @@ public:
QPID_BROKER_EXTERN Tokeniser(const std::string::const_iterator& s, const std::string::const_iterator& e);
QPID_BROKER_EXTERN void returnTokens(unsigned int n = 1);
QPID_BROKER_EXTERN const Token& nextToken();
+ QPID_BROKER_EXTERN std::string remaining();
};
}}
diff --git a/qpid/cpp/src/qpid/broker/SelectorValue.cpp b/qpid/cpp/src/qpid/broker/SelectorValue.cpp
index de097b8969..0855fa91d0 100644
--- a/qpid/cpp/src/qpid/broker/SelectorValue.cpp
+++ b/qpid/cpp/src/qpid/broker/SelectorValue.cpp
@@ -100,6 +100,8 @@ NumericPairBase* promoteNumeric(const Value& v1, const Value& v2)
assert(false);
}
}
+ // Can never get here - but this stops a warning
+ return 0;
}
bool operator==(const Value& v1, const Value& v2)
diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp
index 60c2d6e555..275886c6e3 100644
--- a/qpid/cpp/src/qpid/broker/SemanticState.cpp
+++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp
@@ -286,7 +286,7 @@ void SemanticState::record(const DeliveryRecord& delivery)
}
const std::string QPID_SYNC_FREQUENCY("qpid.sync_frequency");
-const std::string QPID_SELECTOR("qpid.selector");
+const std::string APACHE_SELECTOR("x-apache-selector");
SemanticStateConsumerImpl::SemanticStateConsumerImpl(SemanticState* _parent,
const string& _name,
@@ -309,7 +309,7 @@ Consumer(_name, type),
exclusive(_exclusive),
resumeId(_resumeId),
tag(_tag),
- selector(returnSelector(_arguments.getAsString(QPID_SELECTOR))),
+ selector(returnSelector(_arguments.getAsString(APACHE_SELECTOR))),
resumeTtl(_resumeTtl),
arguments(_arguments),
notifyEnabled(true),
diff --git a/qpid/cpp/src/qpid/broker/amqp/Connection.cpp b/qpid/cpp/src/qpid/broker/amqp/Connection.cpp
index a83034eb6e..be98c048b6 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/Connection.cpp
@@ -37,11 +37,11 @@ namespace qpid {
namespace broker {
namespace amqp {
-Connection::Connection(qpid::sys::OutputControl& o, const std::string& i, qpid::broker::Broker& b, Interconnects& interconnects_, bool saslInUse)
+Connection::Connection(qpid::sys::OutputControl& o, const std::string& i, qpid::broker::Broker& b, Interconnects& interconnects_, bool saslInUse, const std::string& d)
: ManagedConnection(b, i),
connection(pn_connection()),
transport(pn_transport()),
- out(o), id(i), broker(b), haveOutput(true), interconnects(interconnects_)
+ out(o), id(i), broker(b), haveOutput(true), interconnects(interconnects_), domain(d)
{
if (pn_transport_bind(transport, connection)) {
//error
@@ -265,4 +265,8 @@ std::string Connection::getError()
return text.str();
}
+std::string Connection::getDomain() const
+{
+ return domain;
+}
}}} // namespace qpid::broker::amqp
diff --git a/qpid/cpp/src/qpid/broker/amqp/Connection.h b/qpid/cpp/src/qpid/broker/amqp/Connection.h
index 28cf86f123..d61db82e60 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Connection.h
+++ b/qpid/cpp/src/qpid/broker/amqp/Connection.h
@@ -45,7 +45,7 @@ class Session;
class Connection : public sys::ConnectionCodec, public ManagedConnection
{
public:
- Connection(qpid::sys::OutputControl& out, const std::string& id, qpid::broker::Broker& broker, Interconnects&, bool saslInUse);
+ Connection(qpid::sys::OutputControl& out, const std::string& id, qpid::broker::Broker& broker, Interconnects&, bool saslInUse, const std::string& domain);
virtual ~Connection();
size_t decode(const char* buffer, size_t size);
virtual size_t encode(char* buffer, size_t size);
@@ -57,6 +57,7 @@ class Connection : public sys::ConnectionCodec, public ManagedConnection
framing::ProtocolVersion getVersion() const;
pn_transport_t* getTransport();
Interconnects& getInterconnects();
+ std::string getDomain() const;
protected:
typedef std::map<pn_session_t*, boost::shared_ptr<Session> > Sessions;
pn_connection_t* connection;
@@ -67,6 +68,7 @@ class Connection : public sys::ConnectionCodec, public ManagedConnection
bool haveOutput;
Sessions sessions;
Interconnects& interconnects;
+ std::string domain;
virtual void process();
std::string getError();
diff --git a/qpid/cpp/src/qpid/broker/amqp/Filter.cpp b/qpid/cpp/src/qpid/broker/amqp/Filter.cpp
index 2984c2923a..bbe3330939 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Filter.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/Filter.cpp
@@ -61,7 +61,7 @@ void Filter::onStringValue(const qpid::amqp::CharSequence& key, const qpid::amqp
if (descriptor->match(qpid::amqp::filters::LEGACY_TOPIC_FILTER_SYMBOL, qpid::amqp::filters::LEGACY_TOPIC_FILTER_CODE)
|| descriptor->match(qpid::amqp::filters::LEGACY_DIRECT_FILTER_SYMBOL, qpid::amqp::filters::LEGACY_DIRECT_FILTER_CODE)) {
setSubjectFilter(filter);
- } else if (descriptor->match(qpid::amqp::filters::QPID_SELECTOR_FILTER_SYMBOL, 0)) {
+ } else if (descriptor->match(qpid::amqp::filters::SELECTOR_FILTER_SYMBOL, qpid::amqp::filters::SELECTOR_FILTER_CODE)) {
setSelectorFilter(filter);
} else {
QPID_LOG(notice, "Skipping unrecognised string filter with key " << filter.key << " and descriptor " << filter.descriptor);
diff --git a/qpid/cpp/src/qpid/broker/amqp/Interconnect.cpp b/qpid/cpp/src/qpid/broker/amqp/Interconnect.cpp
index 082715b1b2..92a6f75f1e 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Interconnect.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/Interconnect.cpp
@@ -41,7 +41,7 @@ namespace amqp {
Interconnect::Interconnect(qpid::sys::OutputControl& out, const std::string& id, qpid::broker::Broker& broker, bool saslInUse,
bool i, const std::string& n, const std::string& s, const std::string& t, Domain& d, Interconnects& r)
- : Connection(out, id, broker, r, saslInUse), incoming(i), name(n), source(s), target(t), domain(d), registry(r), headerDiscarded(false),
+ : Connection(out, id, broker, r, saslInUse, std::string()), incoming(i), name(n), source(s), target(t), domain(d), registry(r), headerDiscarded(false),
closeRequested(false), isTransportDeleted(false)
{}
diff --git a/qpid/cpp/src/qpid/broker/amqp/ProtocolPlugin.cpp b/qpid/cpp/src/qpid/broker/amqp/ProtocolPlugin.cpp
index 0e622f8d20..16f0cdc39f 100644
--- a/qpid/cpp/src/qpid/broker/amqp/ProtocolPlugin.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/ProtocolPlugin.cpp
@@ -41,10 +41,19 @@ namespace qpid {
namespace broker {
namespace amqp {
+struct Options : public qpid::Options {
+ std::string domain;
+
+ Options() : qpid::Options("AMQP 1.0 Options") {
+ addOptions()
+ ("domain", optValue(domain, "DOMAIN"), "Domain of this broker");
+ }
+};
+
class ProtocolImpl : public Protocol
{
public:
- ProtocolImpl(Interconnects* i, Broker& b) : interconnects(i), broker(b)
+ ProtocolImpl(Interconnects* i, Broker& b, const std::string& d) : interconnects(i), broker(b), domain(d)
{
broker.getObjectFactoryRegistry().add(interconnects);//registry deletes on shutdown
}
@@ -54,16 +63,20 @@ class ProtocolImpl : public Protocol
private:
Interconnects* interconnects;
Broker& broker;
+ std::string domain;
};
struct ProtocolPlugin : public Plugin
{
+ Options options;
+ Options* getOptions() { return &options; }
+
void earlyInitialize(Plugin::Target& target)
{
//need to register protocol before recovery from store
broker::Broker* broker = dynamic_cast<qpid::broker::Broker*>(&target);
if (broker) {
- ProtocolImpl* impl = new ProtocolImpl(new Interconnects(), *broker);
+ ProtocolImpl* impl = new ProtocolImpl(new Interconnects(), *broker, options.domain);
broker->getProtocolRegistry().add("AMQP 1.0", impl);//registry deletes on shutdown
}
}
@@ -79,18 +92,20 @@ qpid::sys::ConnectionCodec* ProtocolImpl::create(const qpid::framing::ProtocolVe
if (v.getProtocol() == qpid::framing::ProtocolVersion::SASL) {
if (broker.getOptions().auth) {
QPID_LOG(info, "Using AMQP 1.0 (with SASL layer)");
- return new qpid::broker::amqp::Sasl(out, id, broker, *interconnects, qpid::SaslFactory::getInstance().createServer(broker.getOptions().realm, broker.getOptions().requireEncrypted, external));
+ return new qpid::broker::amqp::Sasl(out, id, broker, *interconnects,
+ qpid::SaslFactory::getInstance().createServer(broker.getOptions().realm,broker.getOptions().requireEncrypted, external),
+ domain);
} else {
std::auto_ptr<SaslServer> authenticator(new qpid::NullSaslServer(broker.getOptions().realm));
QPID_LOG(info, "Using AMQP 1.0 (with dummy SASL layer)");
- return new qpid::broker::amqp::Sasl(out, id, broker, *interconnects, authenticator);
+ return new qpid::broker::amqp::Sasl(out, id, broker, *interconnects, authenticator, domain);
}
} else {
if (broker.getOptions().auth) {
throw qpid::Exception("SASL layer required!");
} else {
QPID_LOG(info, "Using AMQP 1.0 (no SASL layer)");
- return new qpid::broker::amqp::Connection(out, id, broker, *interconnects, false);
+ return new qpid::broker::amqp::Connection(out, id, broker, *interconnects, false, domain);
}
}
}
diff --git a/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp b/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
index d8e12fcfdd..820aaf87d4 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
@@ -31,8 +31,8 @@ namespace qpid {
namespace broker {
namespace amqp {
-Sasl::Sasl(qpid::sys::OutputControl& o, const std::string& id, qpid::broker::Broker& broker, Interconnects& i, std::auto_ptr<qpid::SaslServer> auth)
- : qpid::amqp::SaslServer(id), out(o), connection(out, id, broker, i, true),
+Sasl::Sasl(qpid::sys::OutputControl& o, const std::string& id, qpid::broker::Broker& broker, Interconnects& i, std::auto_ptr<qpid::SaslServer> auth, const std::string& domain)
+ : qpid::amqp::SaslServer(id), out(o), connection(out, id, broker, i, true, domain),
authenticator(auth),
state(INCOMPLETE), writeHeader(true), haveOutput(true)
{
diff --git a/qpid/cpp/src/qpid/broker/amqp/Sasl.h b/qpid/cpp/src/qpid/broker/amqp/Sasl.h
index 7718b4c43a..194ab0a0d5 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Sasl.h
+++ b/qpid/cpp/src/qpid/broker/amqp/Sasl.h
@@ -39,7 +39,7 @@ namespace amqp {
class Sasl : public sys::ConnectionCodec, qpid::amqp::SaslServer
{
public:
- Sasl(qpid::sys::OutputControl& out, const std::string& id, qpid::broker::Broker& broker, Interconnects&, std::auto_ptr<qpid::SaslServer> authenticator);
+ Sasl(qpid::sys::OutputControl& out, const std::string& id, qpid::broker::Broker& broker, Interconnects&, std::auto_ptr<qpid::SaslServer> authenticator, const std::string& domain);
~Sasl();
size_t decode(const char* buffer, size_t size);
diff --git a/qpid/cpp/src/qpid/broker/amqp/Session.cpp b/qpid/cpp/src/qpid/broker/amqp/Session.cpp
index 544616b897..62011f6372 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Session.cpp
+++ b/qpid/cpp/src/qpid/broker/amqp/Session.cpp
@@ -53,6 +53,20 @@ namespace qpid {
namespace broker {
namespace amqp {
+namespace {
+bool is_capability_requested(const std::string& name, pn_data_t* capabilities)
+{
+ while (pn_data_next(capabilities)) {
+ pn_bytes_t c = pn_data_get_symbol(capabilities);
+ std::string s(c.start, c.size);
+ if (s == name) return true;
+ }
+ return false;
+}
+
+const std::string CREATE_ON_DEMAND("create-on-demand");
+}
+
class IncomingToQueue : public DecodingIncoming
{
public:
@@ -81,7 +95,7 @@ Session::ResolvedNode Session::resolve(const std::string name, pn_terminus_t* te
node.exchange = broker.getExchanges().find(name);
node.queue = broker.getQueues().find(name);
if (!node.queue && !node.exchange) {
- if (pn_terminus_is_dynamic(terminus)) {
+ if (pn_terminus_is_dynamic(terminus) || is_capability_requested(CREATE_ON_DEMAND, pn_terminus_capabilities(terminus))) {
//is it a queue or an exchange?
NodeProperties properties;
properties.read(pn_terminus_properties(terminus));
@@ -117,25 +131,43 @@ Session::ResolvedNode Session::resolve(const std::string name, pn_terminus_t* te
return node;
}
+std::string Session::generateName(pn_link_t* link)
+{
+ std::stringstream s;
+ s << qpid::types::Uuid(true) << "::" << pn_link_name(link);
+ if (!connection.getDomain().empty()) {
+ s << "@" << connection.getDomain();
+ }
+ return s.str();
+}
+
void Session::attach(pn_link_t* link)
{
if (pn_link_is_sender(link)) {
pn_terminus_t* source = pn_link_remote_source(link);
//i.e a subscription
+ std::string name;
if (pn_terminus_get_type(source) == PN_UNSPECIFIED) {
throw qpid::Exception("No source specified!");/*invalid-field?*/
+ } else if (pn_terminus_is_dynamic(source)) {
+ name = generateName(link);
+ } else {
+ name = pn_terminus_get_address(source);
}
- std::string name = pn_terminus_get_address(source);
QPID_LOG(debug, "Received attach request for outgoing link from " << name);
pn_terminus_set_address(pn_link_source(link), name.c_str());
setupOutgoing(link, source, name);
} else {
pn_terminus_t* target = pn_link_remote_target(link);
+ std::string name;
if (pn_terminus_get_type(target) == PN_UNSPECIFIED) {
throw qpid::Exception("No target specified!");/*invalid field?*/
+ } else if (pn_terminus_is_dynamic(target)) {
+ name = generateName(link);
+ } else {
+ name = pn_terminus_get_address(target);
}
- std::string name = pn_terminus_get_address(target);
QPID_LOG(debug, "Received attach request for incoming link to " << name);
pn_terminus_set_address(pn_link_target(link), name.c_str());
diff --git a/qpid/cpp/src/qpid/broker/amqp/Session.h b/qpid/cpp/src/qpid/broker/amqp/Session.h
index 74f50a9eda..b142224cfd 100644
--- a/qpid/cpp/src/qpid/broker/amqp/Session.h
+++ b/qpid/cpp/src/qpid/broker/amqp/Session.h
@@ -95,6 +95,7 @@ class Session : public ManagedSession, public boost::enable_shared_from_this<Ses
ResolvedNode resolve(const std::string name, pn_terminus_t* terminus, bool incoming);
void setupOutgoing(pn_link_t* link, pn_terminus_t* source, const std::string& name);
void setupIncoming(pn_link_t* link, pn_terminus_t* target, const std::string& name);
+ std::string generateName(pn_link_t*);
};
}}} // namespace qpid::broker::amqp
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
index de6ee0cd2d..a9f2758605 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -93,7 +93,8 @@ const std::string DURABLE("durable");
const std::string X_DECLARE("x-declare");
const std::string X_SUBSCRIBE("x-subscribe");
const std::string X_BINDINGS("x-bindings");
-const std::string QPID_SELECTOR("qpid.selector");
+const std::string SELECTOR("selector");
+const std::string APACHE_SELECTOR("x-apache-selector");
const std::string EXCHANGE("exchange");
const std::string QUEUE("queue");
const std::string KEY("key");
@@ -477,8 +478,8 @@ QueueSource::QueueSource(const Address& address) :
//options)
exclusive = Opt(address)/LINK/X_SUBSCRIBE/EXCLUSIVE;
(Opt(address)/LINK/X_SUBSCRIBE/ARGUMENTS).collect(options);
- std::string selector = Opt(address)/LINK/QPID_SELECTOR;
- if (!selector.empty()) options.setString(QPID_SELECTOR, selector);
+ std::string selector = Opt(address)/LINK/SELECTOR;
+ if (!selector.empty()) options.setString(APACHE_SELECTOR, selector);
}
void QueueSource::subscribe(qpid::client::AsyncSession& session, const std::string& destination)
@@ -990,7 +991,7 @@ Verifier::Verifier()
link[X_SUBSCRIBE] = true;
link[X_DECLARE] = true;
link[X_BINDINGS] = true;
- link[QPID_SELECTOR] = true;
+ link[SELECTOR] = true;
defined[LINK] = link;
}
void Verifier::verify(const Address& address) const
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
index 40b09b0fc0..11f9475cad 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
@@ -143,6 +143,11 @@ uint32_t ReceiverImpl::getUnsettled()
return parent->getUnsettledAcks(destination);
}
+qpid::messaging::Address ReceiverImpl::getAddress() const
+{
+ return address;
+}
+
ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name,
const qpid::messaging::Address& a) :
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
index 76da4f31a9..4dba76c8d9 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
@@ -66,6 +66,7 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl
void received(qpid::messaging::Message& message);
qpid::messaging::Session getSession() const;
bool isClosed() const;
+ qpid::messaging::Address getAddress() const;
private:
mutable sys::Mutex lock;
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
index b275db38d7..7001acaf99 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -34,6 +34,11 @@ SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name,
parent(&_parent), name(_name), address(_address), state(UNRESOLVED),
capacity(50), window(0), flushed(false), unreliable(AddressResolution::is_unreliable(address)) {}
+qpid::messaging::Address SenderImpl::getAddress() const
+{
+ return address;
+}
+
void SenderImpl::send(const qpid::messaging::Message& message, bool sync)
{
if (unreliable) { // immutable, don't need lock
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
index d75863c743..ee250af2d4 100644
--- a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
@@ -56,6 +56,7 @@ class SenderImpl : public qpid::messaging::SenderImpl
void init(qpid::client::AsyncSession, AddressResolution&);
const std::string& getName() const;
qpid::messaging::Session getSession() const;
+ qpid::messaging::Address getAddress() const;
private:
mutable sys::Mutex lock;
diff --git a/qpid/cpp/src/qpid/messaging/Address.cpp b/qpid/cpp/src/qpid/messaging/Address.cpp
index a516959edb..6fbaeef661 100644
--- a/qpid/cpp/src/qpid/messaging/Address.cpp
+++ b/qpid/cpp/src/qpid/messaging/Address.cpp
@@ -19,6 +19,8 @@
*
*/
#include "qpid/messaging/Address.h"
+#include "qpid/messaging/AddressImpl.h"
+#include "qpid/messaging/AddressParser.h"
#include "qpid/framing/Uuid.h"
#include <sstream>
#include <boost/format.hpp>
@@ -34,51 +36,9 @@ const std::string OPTIONS_DIVIDER = ";";
const std::string SPACE = " ";
const std::string TYPE = "type";
}
-class AddressImpl
-{
- public:
- std::string name;
- std::string subject;
- Variant::Map options;
-
- AddressImpl() {}
- AddressImpl(const std::string& n, const std::string& s, const Variant::Map& o) :
- name(n), subject(s), options(o) {}
-};
-
-class AddressParser
-{
- public:
- AddressParser(const std::string&);
- bool parse(Address& address);
- private:
- const std::string& input;
- std::string::size_type current;
- static const std::string RESERVED;
-
- bool readChar(char c);
- bool readQuotedString(std::string& s);
- bool readQuotedValue(Variant& value);
- bool readString(std::string& value, char delimiter);
- bool readWord(std::string& word, const std::string& delims = RESERVED);
- bool readSimpleValue(Variant& word);
- bool readKey(std::string& key);
- bool readValue(Variant& value);
- bool readKeyValuePair(Variant::Map& map);
- bool readMap(Variant& value);
- bool readList(Variant& value);
- bool readName(std::string& name);
- bool readSubject(std::string& subject);
- bool error(const std::string& message);
- bool eos();
- bool iswhitespace();
- bool in(const std::string& delims);
- bool isreserved();
-};
-
Address::Address() : impl(new AddressImpl()) {}
Address::Address(const std::string& address) : impl(new AddressImpl())
-{
+{
AddressParser parser(address);
parser.parse(*this);
}
@@ -86,7 +46,7 @@ Address::Address(const std::string& name, const std::string& subject, const Vari
const std::string& type)
: impl(new AddressImpl(name, subject, options)) { setType(type); }
Address::Address(const Address& a) :
- impl(new AddressImpl(a.impl->name, a.impl->subject, a.impl->options)) {}
+ impl(new AddressImpl(a.impl->name, a.impl->subject, a.impl->options)) { impl->temporary = a.impl->temporary; }
Address::~Address() { delete impl; }
Address& Address::operator=(const Address& a) { *impl = *a.impl; return *this; }
diff --git a/qpid/cpp/src/qpid/messaging/AddressImpl.h b/qpid/cpp/src/qpid/messaging/AddressImpl.h
new file mode 100644
index 0000000000..8d34bd73c4
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/AddressImpl.h
@@ -0,0 +1,45 @@
+#ifndef QPID_MESSAGING_ADDRESSIMPL_H
+#define QPID_MESSAGING_ADDRESSIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/types/Variant.h"
+namespace qpid {
+namespace messaging {
+
+class AddressImpl
+{
+ public:
+ std::string name;
+ std::string subject;
+ qpid::types::Variant::Map options;
+ bool temporary;
+
+ AddressImpl() : temporary(false) {}
+ AddressImpl(const std::string& n, const std::string& s, const qpid::types::Variant::Map& o) :
+ name(n), subject(s), options(o), temporary(false) {}
+ static void setTemporary(Address& a, bool value) { a.impl->temporary = value; }
+ static bool isTemporary(const Address& a) { return a.impl->temporary; }
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_ADDRESSIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/AddressParser.cpp b/qpid/cpp/src/qpid/messaging/AddressParser.cpp
index 67249e188e..882deba463 100644
--- a/qpid/cpp/src/qpid/messaging/AddressParser.cpp
+++ b/qpid/cpp/src/qpid/messaging/AddressParser.cpp
@@ -19,6 +19,7 @@
*
*/
#include "AddressParser.h"
+#include "AddressImpl.h"
#include "qpid/framing/Uuid.h"
#include <boost/format.hpp>
@@ -38,7 +39,10 @@ bool AddressParser::parse(Address& address)
{
std::string name;
if (readName(name)) {
- if (name.find('#') == 0) name = qpid::framing::Uuid(true).str() + name;
+ if (name.find('#') == 0) {
+ name = qpid::framing::Uuid(true).str() + name;
+ AddressImpl::setTemporary(address, true);
+ }
address.setName(name);
if (readChar('/')) {
std::string subject;
diff --git a/qpid/cpp/src/qpid/messaging/Receiver.cpp b/qpid/cpp/src/qpid/messaging/Receiver.cpp
index 78e0c5daa3..c45ebd6760 100644
--- a/qpid/cpp/src/qpid/messaging/Receiver.cpp
+++ b/qpid/cpp/src/qpid/messaging/Receiver.cpp
@@ -19,6 +19,7 @@
*
*/
#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Address.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/ReceiverImpl.h"
#include "qpid/messaging/Session.h"
@@ -45,4 +46,5 @@ void Receiver::close() { impl->close(); }
const std::string& Receiver::getName() const { return impl->getName(); }
Session Receiver::getSession() const { return impl->getSession(); }
bool Receiver::isClosed() const { return impl->isClosed(); }
+Address Receiver::getAddress() const { return impl->getAddress(); }
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
index e450693d2c..59ccc3214e 100644
--- a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
+++ b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
@@ -27,6 +27,7 @@
namespace qpid {
namespace messaging {
+class Address;
class Duration;
class Message;
class MessageListener;
@@ -48,6 +49,7 @@ class ReceiverImpl : public virtual qpid::RefCounted
virtual const std::string& getName() const = 0;
virtual Session getSession() const = 0;
virtual bool isClosed() const = 0;
+ virtual Address getAddress() const = 0;
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Sender.cpp b/qpid/cpp/src/qpid/messaging/Sender.cpp
index 53dbb69777..a60de3d606 100644
--- a/qpid/cpp/src/qpid/messaging/Sender.cpp
+++ b/qpid/cpp/src/qpid/messaging/Sender.cpp
@@ -19,6 +19,7 @@
*
*/
#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Address.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/SenderImpl.h"
#include "qpid/messaging/Session.h"
@@ -40,5 +41,5 @@ uint32_t Sender::getUnsettled() { return impl->getUnsettled(); }
uint32_t Sender::getAvailable() { return getCapacity() - getUnsettled(); }
const std::string& Sender::getName() const { return impl->getName(); }
Session Sender::getSession() const { return impl->getSession(); }
-
+Address Sender::getAddress() const { return impl->getAddress(); }
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/SenderImpl.h b/qpid/cpp/src/qpid/messaging/SenderImpl.h
index d978463fdb..91fd9b1536 100644
--- a/qpid/cpp/src/qpid/messaging/SenderImpl.h
+++ b/qpid/cpp/src/qpid/messaging/SenderImpl.h
@@ -27,6 +27,7 @@
namespace qpid {
namespace messaging {
+class Address;
class Message;
class Session;
@@ -41,6 +42,7 @@ class SenderImpl : public virtual qpid::RefCounted
virtual uint32_t getUnsettled() = 0;
virtual const std::string& getName() const = 0;
virtual Session getSession() const = 0;
+ virtual Address getAddress() const = 0;
private:
};
}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp
index 359660dce5..a46606a526 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp
@@ -20,6 +20,7 @@
*/
#include "qpid/messaging/amqp/AddressHelper.h"
#include "qpid/messaging/Address.h"
+#include "qpid/log/Statement.h"
#include <vector>
#include <boost/assign.hpp>
extern "C" {
@@ -56,7 +57,9 @@ const std::string MOVE("move");
const std::string COPY("copy");
const std::string SUPPORTED_DIST_MODES("supported-dist-modes");
+const std::string CREATE_ON_DEMAND("create-on-demand");
+const std::string DUMMY(".");
const std::vector<std::string> RECEIVER_MODES = boost::assign::list_of<std::string>(ALWAYS) (RECEIVER);
const std::vector<std::string> SENDER_MODES = boost::assign::list_of<std::string>(ALWAYS) (SENDER);
@@ -155,26 +158,33 @@ const qpid::types::Variant::Map& AddressHelper::getLinkProperties() const
return link;
}
-void AddressHelper::setNodeProperties(pn_terminus_t* terminus)
+void AddressHelper::setNodeProperties(pn_terminus_t* terminus, bool dynamic)
{
- pn_terminus_set_dynamic(terminus, true);
+ if (dynamic) {
+ pn_terminus_set_address(terminus, DUMMY.c_str());//Workaround for proton bug
+ pn_terminus_set_dynamic(terminus, true);
+ } else {
+ pn_data_t* capabilities = pn_terminus_capabilities(terminus);
+ if (!capabilities) {
+ QPID_LOG(error, "!!!No capabilities!!!");
+ }
+ pn_data_put_symbol(capabilities, convert(CREATE_ON_DEMAND));
+ }
//properties for dynamically created node:
- pn_data_t* data = pn_terminus_properties(terminus);
if (node.size()) {
+ pn_data_t* data = pn_terminus_properties(terminus);
pn_data_put_map(data);
pn_data_enter(data);
- }
- for (qpid::types::Variant::Map::const_iterator i = node.begin(); i != node.end(); ++i) {
- if (i->first == TYPE) {
- pn_data_put_symbol(data, convert(SUPPORTED_DIST_MODES));
- pn_data_put_string(data, convert(i->second == TOPIC ? COPY : MOVE));
- } else {
- pn_data_put_symbol(data, convert(i->first));
- pn_data_put_string(data, convert(i->second.asString()));
+ for (qpid::types::Variant::Map::const_iterator i = node.begin(); i != node.end(); ++i) {
+ if (i->first == TYPE) {
+ pn_data_put_symbol(data, convert(SUPPORTED_DIST_MODES));
+ pn_data_put_string(data, convert(i->second == TOPIC ? COPY : MOVE));
+ } else {
+ pn_data_put_symbol(data, convert(i->first));
+ pn_data_put_string(data, convert(i->second.asString()));
+ }
}
- }
- if (node.size()) {
pn_data_exit(data);
}
}
diff --git a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h
index cd0aa1be9e..2442619ed3 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h
+++ b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h
@@ -40,7 +40,7 @@ class AddressHelper
bool deleteEnabled(CheckMode mode) const;
bool assertEnabled(CheckMode mode) const;
- void setNodeProperties(pn_terminus_t*);
+ void setNodeProperties(pn_terminus_t*, bool dynamic);
const qpid::types::Variant::Map& getNodeProperties() const;
const qpid::types::Variant::Map& getLinkProperties() const;
private:
@@ -49,6 +49,7 @@ class AddressHelper
std::string deletePolicy;
qpid::types::Variant::Map node;
qpid::types::Variant::Map link;
+ std::string name;
bool enabled(const std::string& policy, CheckMode mode) const;
};
diff --git a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp
index c74ee01898..9febe66f7e 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp
@@ -26,6 +26,7 @@
#include "SessionContext.h"
#include "Transport.h"
#include "qpid/messaging/exceptions.h"
+#include "qpid/messaging/AddressImpl.h"
#include "qpid/messaging/Duration.h"
#include "qpid/messaging/Message.h"
#include "qpid/messaging/MessageImpl.h"
@@ -285,34 +286,45 @@ void ConnectionContext::attach(boost::shared_ptr<SessionContext> ssn, boost::sha
{
lnk->configure();
attach(ssn->session, (pn_link_t*) lnk->sender);
- if (!pn_link_remote_target((pn_link_t*) lnk->sender)) {
+ pn_terminus_t* t = pn_link_remote_target(lnk->sender);
+ if (!pn_terminus_get_address(t)) {
std::string msg("No such target : ");
msg += lnk->getTarget();
+ QPID_LOG(debug, msg);
throw qpid::messaging::NotFound(msg);
+ } else if (AddressImpl::isTemporary(lnk->address)) {
+ lnk->address.setName(pn_terminus_get_address(t));
+ QPID_LOG(debug, "Dynamic target name set to " << lnk->address.getName());
}
+ QPID_LOG(debug, "Attach succeeded to " << lnk->getTarget());
}
void ConnectionContext::attach(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk)
{
lnk->configure();
attach(ssn->session, lnk->receiver, lnk->capacity);
- if (!pn_link_remote_source(lnk->receiver)) {
+ pn_terminus_t* s = pn_link_remote_source(lnk->receiver);
+ if (!pn_terminus_get_address(s)) {
std::string msg("No such source : ");
msg += lnk->getSource();
+ QPID_LOG(debug, msg);
throw qpid::messaging::NotFound(msg);
+ } else if (AddressImpl::isTemporary(lnk->address)) {
+ lnk->address.setName(pn_terminus_get_address(s));
+ QPID_LOG(debug, "Dynamic source name set to " << lnk->address.getName());
}
+ QPID_LOG(debug, "Attach succeeded from " << lnk->getSource());
}
void ConnectionContext::attach(pn_session_t* /*session*/, pn_link_t* link, int credit)
{
qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock);
- QPID_LOG(debug, "Attaching link " << link << ", state=" << pn_link_state(link));
pn_link_open(link);
- QPID_LOG(debug, "Link attached " << link << ", state=" << pn_link_state(link));
+ QPID_LOG(debug, "Link attach sent for " << link << ", state=" << pn_link_state(link));
if (credit) pn_link_flow(link, credit);
wakeupDriver();
while (pn_link_state(link) & PN_REMOTE_UNINIT) {
- QPID_LOG(debug, "waiting for confirmation of link attach for " << link << ", state=" << pn_link_state(link));
+ QPID_LOG(debug, "Waiting for confirmation of link attach for " << link << ", state=" << pn_link_state(link) << "...");
wait();
}
}
diff --git a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp
index 54de3eae45..3370199067 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp
@@ -228,7 +228,7 @@ void EncodedMessage::InitialScan::onTtl(uint32_t i) { mi.setTtl(i); em.ttl = i;
void EncodedMessage::InitialScan::onFirstAcquirer(bool b) { em.firstAcquirer = b; }
void EncodedMessage::InitialScan::onDeliveryCount(uint32_t i)
{
- mi.setRedelivered(i);
+ mi.setRedelivered(i > 1);
em.deliveryCount = i;
}
diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp
index 638b1fc674..f7b06ddc05 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp
@@ -20,9 +20,11 @@
*/
#include "qpid/messaging/amqp/ReceiverContext.h"
#include "qpid/messaging/amqp/AddressHelper.h"
+#include "qpid/messaging/AddressImpl.h"
#include "qpid/messaging/Duration.h"
#include "qpid/messaging/Message.h"
#include "qpid/amqp/descriptors.h"
+#include "qpid/log/Statement.h"
extern "C" {
#include <proton/engine.h>
}
@@ -38,7 +40,7 @@ ReceiverContext::ReceiverContext(pn_session_t* session, const std::string& n, co
capacity(0) {}
ReceiverContext::~ReceiverContext()
{
- pn_link_free(receiver);
+ //pn_link_free(receiver);
}
void ReceiverContext::setCapacity(uint32_t c)
@@ -76,7 +78,7 @@ uint32_t ReceiverContext::getUnsettled()
void ReceiverContext::close()
{
-
+ pn_link_close(receiver);
}
const std::string& ReceiverContext::getName() const
@@ -113,23 +115,30 @@ void ReceiverContext::configure() const
}
void ReceiverContext::configure(pn_terminus_t* source) const
{
- pn_terminus_set_address(source, address.getName().c_str());
//dynamic create:
AddressHelper helper(address);
- if (helper.createEnabled(AddressHelper::FOR_RECEIVER)) {
- helper.setNodeProperties(source);
+ if (AddressImpl::isTemporary(address)) {
+ //application expects a name to be generated
+ QPID_LOG(debug, "source is dynamic");
+ helper.setNodeProperties(source, true);
+ } else {
+ pn_terminus_set_address(source, address.getName().c_str());
+ if (helper.createEnabled(AddressHelper::FOR_RECEIVER)) {
+ //application expects name of node to be as specified
+ helper.setNodeProperties(source, false);
+ }
}
// Look specifically for qpid.selector link property and add a filter for it
- qpid::types::Variant::Map::const_iterator i = helper.getLinkProperties().find("qpid.selector");
+ qpid::types::Variant::Map::const_iterator i = helper.getLinkProperties().find("selector");
if (i!=helper.getLinkProperties().end()) {
pn_data_t* filter = pn_terminus_filter(source);
pn_data_put_map(filter);
pn_data_enter(filter);
- pn_data_put_symbol(filter, convert("qpid.selector"));
+ pn_data_put_symbol(filter, convert("selector"));
pn_data_put_described(filter);
pn_data_enter(filter);
- pn_data_put_symbol(filter, convert(qpid::amqp::filters::QPID_SELECTOR_FILTER_SYMBOL));
+ pn_data_put_ulong(filter, qpid::amqp::filters::SELECTOR_FILTER_CODE);
pn_data_put_string(filter, convert(i->second));
pn_data_exit(filter);
pn_data_exit(filter);
@@ -149,6 +158,11 @@ void ReceiverContext::configure(pn_terminus_t* source) const
}
}
+Address ReceiverContext::getAddress() const
+{
+ return address;
+}
+
bool ReceiverContext::isClosed() const
{
return false;//TODO
diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h
index 34ecdda6be..9c5386157b 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h
+++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h
@@ -55,10 +55,11 @@ class ReceiverContext
const std::string& getSource() const;
bool isClosed() const;
void configure() const;
+ Address getAddress() const;
private:
friend class ConnectionContext;
const std::string name;
- const Address address;
+ Address address;
pn_link_t* receiver;
uint32_t capacity;
void configure(pn_terminus_t*) const;
diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp
index 9bf64ebb8d..c601d05ed0 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp
@@ -103,4 +103,9 @@ bool ReceiverHandle::isClosed() const
return receiver->isClosed();
}
+Address ReceiverHandle::getAddress() const
+{
+ return receiver->getAddress();
+}
+
}}} // namespace qpid::messaging::amqp
diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.h b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.h
index a1a6f26025..08a95fb585 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.h
+++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.h
@@ -53,6 +53,7 @@ class ReceiverHandle : public qpid::messaging::ReceiverImpl
const std::string& getName() const;
qpid::messaging::Session getSession() const;
bool isClosed() const;
+ Address getAddress() const;
private:
boost::shared_ptr<ConnectionContext> connection;
boost::shared_ptr<SessionContext> session;
diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp
index 96c4437b89..fe74a4bca8 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp
@@ -21,6 +21,7 @@
#include "qpid/messaging/amqp/SenderContext.h"
#include "qpid/messaging/amqp/EncodedMessage.h"
#include "qpid/messaging/amqp/AddressHelper.h"
+#include "qpid/messaging/AddressImpl.h"
#include "qpid/amqp/descriptors.h"
#include "qpid/amqp/MessageEncoder.h"
#include "qpid/messaging/exceptions.h"
@@ -44,12 +45,12 @@ SenderContext::SenderContext(pn_session_t* session, const std::string& n, const
SenderContext::~SenderContext()
{
- pn_link_free(sender);
+ //pn_link_free(sender);
}
void SenderContext::close()
{
-
+ pn_link_close(sender);
}
void SenderContext::setCapacity(uint32_t c)
@@ -347,11 +348,16 @@ void SenderContext::configure() const
}
void SenderContext::configure(pn_terminus_t* target) const
{
- pn_terminus_set_address(target, address.getName().c_str());
- //dynamic create:
AddressHelper helper(address);
- if (helper.createEnabled(AddressHelper::FOR_SENDER)) {
- helper.setNodeProperties(target);
+ if (AddressImpl::isTemporary(address)) {
+ //application expects a name to be generated
+ helper.setNodeProperties(target, true);
+ } else {
+ pn_terminus_set_address(target, address.getName().c_str());
+ if (helper.createEnabled(AddressHelper::FOR_SENDER)) {
+ //application expects name of node to be as specified
+ helper.setNodeProperties(target, false);
+ }
}
}
@@ -360,4 +366,9 @@ bool SenderContext::settled()
return processUnsettled() == 0;
}
+Address SenderContext::getAddress() const
+{
+ return address;
+}
+
}}} // namespace qpid::messaging::amqp
diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h
index 3595379e70..2969e75a16 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h
+++ b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h
@@ -71,12 +71,13 @@ class SenderContext
Delivery* send(const qpid::messaging::Message& message);
void configure() const;
bool settled();
+ Address getAddress() const;
private:
friend class ConnectionContext;
typedef std::deque<Delivery> Deliveries;
const std::string name;
- const qpid::messaging::Address address;
+ qpid::messaging::Address address;
pn_link_t* sender;
int32_t nextId;
Deliveries deliveries;
diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp
index b7168e5b31..4e258e7b38 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp
@@ -72,4 +72,9 @@ qpid::messaging::Session SenderHandle::getSession() const
return qpid::messaging::Session(new SessionHandle(connection, session));
}
+Address SenderHandle::getAddress() const
+{
+ return sender->getAddress();
+}
+
}}} // namespace qpid::messaging::amqp
diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.h b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.h
index 3c6b666582..fab158c1ef 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.h
+++ b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.h
@@ -48,6 +48,7 @@ class SenderHandle : public qpid::messaging::SenderImpl
uint32_t getUnsettled();
const std::string& getName() const;
Session getSession() const;
+ Address getAddress() const;
private:
boost::shared_ptr<ConnectionContext> connection;
boost::shared_ptr<SessionContext> session;
diff --git a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp
index 9bdc658bc7..bca40c6058 100644
--- a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp
+++ b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp
@@ -138,9 +138,13 @@ void SessionContext::acknowledge()
void SessionContext::acknowledge(const qpid::framing::SequenceNumber& id, bool cumulative)
{
+ QPID_LOG(debug, "acknowledging selected messages, id=" << id << ", cumulative=" << cumulative);
DeliveryMap::iterator i = unacked.find(id);
if (i != unacked.end()) {
- acknowledge(cumulative ? unacked.begin() : i, ++i);
+ DeliveryMap::iterator start = cumulative ? unacked.begin() : i;
+ acknowledge(start, ++i);
+ } else {
+ QPID_LOG(debug, "selective acknowledgement failed; message not found for id " << id);
}
}
diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
index fb6c326327..29c00d9c12 100644
--- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp
@@ -179,17 +179,24 @@ bool XmlExchange::bind(Queue::shared_ptr queue, const std::string& bindingKey, c
bool XmlExchange::unbind(Queue::shared_ptr queue, const std::string& bindingKey, const FieldTable* args)
{
+ RWlock::ScopedWlock l(lock);
+ return unbindLH(queue, bindingKey, args);
+}
+
+bool XmlExchange::unbindLH(Queue::shared_ptr queue, const std::string& bindingKey, const FieldTable* args)
+{
/*
* When called directly, no qpidFedOrigin argument will be
* present. When called from federation, it will be present.
*
* This is a bit of a hack - the binding needs the origin, but
* this interface, as originally defined, would not supply one.
+ *
+ * Note: caller must hold Wlock
*/
std::string fedOrigin;
if (args) fedOrigin = args->getAsString(qpidFedOrigin);
- RWlock::ScopedWlock l(lock);
if (bindingsMap[bindingKey].remove_if(MatchQueueAndOrigin(queue, fedOrigin))) {
if (mgmtExchange != 0) {
mgmtExchange->dec_bindingCount();
@@ -389,9 +396,9 @@ void XmlExchange::propagateFedOp(const std::string& bindingKey, const std::strin
bool XmlExchange::fedUnbind(const std::string& fedOrigin, const std::string& fedTags, Queue::shared_ptr queue, const std::string& bindingKey, const FieldTable* args)
{
- RWlock::ScopedRlock l(lock);
+ RWlock::ScopedWlock l(lock);
- if (unbind(queue, bindingKey, args)) {
+ if (unbindLH(queue, bindingKey, args)) {
propagateFedOp(bindingKey, fedTags, fedOpUnbind, fedOrigin);
return true;
}
diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.h b/qpid/cpp/src/qpid/xml/XmlExchange.h
index 7b04781ad5..fd3f8d0278 100644
--- a/qpid/cpp/src/qpid/xml/XmlExchange.h
+++ b/qpid/cpp/src/qpid/xml/XmlExchange.h
@@ -107,6 +107,8 @@ class XmlExchange : public virtual Exchange {
bool operator()(XmlBinding::shared_ptr b);
};
+ private:
+ bool unbindLH(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
};
diff --git a/qpid/cpp/src/tests/CMakeLists.txt b/qpid/cpp/src/tests/CMakeLists.txt
index f77863a146..001b5d2d69 100644
--- a/qpid/cpp/src/tests/CMakeLists.txt
+++ b/qpid/cpp/src/tests/CMakeLists.txt
@@ -293,6 +293,8 @@ install (TARGETS
qpid-receive qpid-send qpid-topic-listener qpid-topic-publisher receiver sender
qpid-txtest
RUNTIME DESTINATION ${QPID_INSTALL_TESTDIR})
+install (PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/qpidt
+ DESTINATION ${QPID_INSTALL_TESTDIR})
# This should ideally be done as part of the test run, but I don't know a way
# to get these arguments and the working directory set like Makefile.am does,
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index 2e55b24c3e..3943e21b7f 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -146,8 +146,8 @@ endif
# Test programs that are installed and therefore built as part of make, not make check
-qpidexectest_SCRIPTS += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh
-EXTRA_DIST += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh
+qpidexectest_SCRIPTS += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh qpidt
+EXTRA_DIST += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh qpidt
qpidexectest_PROGRAMS += receiver
receiver_SOURCES = \
diff --git a/qpid/cpp/src/tests/Selector.cpp b/qpid/cpp/src/tests/Selector.cpp
index 1fc9a9b7bb..59bdd36b77 100644
--- a/qpid/cpp/src/tests/Selector.cpp
+++ b/qpid/cpp/src/tests/Selector.cpp
@@ -251,6 +251,8 @@ QPID_AUTO_TEST_CASE(tokenString)
QPID_AUTO_TEST_CASE(parseStringFail)
{
+ BOOST_CHECK_THROW(qb::Selector e("hello world"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("hello ^ world"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A is null not"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A is null or not"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A is null or and"), std::range_error);
@@ -262,6 +264,10 @@ QPID_AUTO_TEST_CASE(parseStringFail)
BOOST_CHECK_THROW(qb::Selector e("A not like 'eclecti_' escape happy"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A BETWEEN AND 'true'"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A NOT BETWEEN 34 OR 3.9"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A IN ()"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A NOT IN ()"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A IN 'hello', 'there', 1, true, (1-17))"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A IN ('hello', 'there' 1, true, (1-17))"), std::range_error);
}
QPID_AUTO_TEST_CASE(parseString)
diff --git a/qpid/cpp/src/tests/ping_broker b/qpid/cpp/src/tests/ping_broker
index 6c391027a3..be99a6ef46 100755
--- a/qpid/cpp/src/tests/ping_broker
+++ b/qpid/cpp/src/tests/ping_broker
@@ -60,6 +60,9 @@ def OptionsAndArguments(argv):
help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD, DIGEST-MD5, GSSAPI). SASL automatically picks the most secure available mechanism - use this option to override.")
parser.add_option("--ssl-certificate", action="store", type="string", metavar="<cert>", help="Client SSL certificate (PEM Format)")
parser.add_option("--ssl-key", action="store", type="string", metavar="<key>", help="Client SSL private key (PEM Format)")
+ parser.add_option("--ssl-trustfile", action="store", type="string", metavar="<CA>", help="List of trusted CAs (PEM Format)")
+ parser.add_option("--ssl-skip-hostname-check", action="store_true",
+ help="Do not validate hostname in peer certificate")
parser.add_option("--ha-admin", action="store_true", help="Allow connection to a HA backup broker.")
opts, args = parser.parse_args(args=argv)
@@ -73,6 +76,10 @@ def OptionsAndArguments(argv):
conn_options['ssl_certfile'] = opts.ssl_certificate
if opts.ssl_key:
conn_options['ssl_key'] = opts.ssl_key
+ if opts.ssl_trustfile:
+ conn_options['ssl_trustfile'] = opts.ssl_trustfile
+ if opts.ssl_skip_hostname_check:
+ conn_options['ssl_skip_hostname_check'] = True
if opts.ha_admin:
conn_options['client_properties'] = {'qpid.ha-admin' : 1}
return args
diff --git a/qpid/cpp/src/tests/qpidt b/qpid/cpp/src/tests/qpidt
new file mode 100644
index 0000000000..5bdfb6eefd
--- /dev/null
+++ b/qpid/cpp/src/tests/qpidt
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import pdb
+
+import os
+from optparse import OptionParser
+import sys
+
+home = os.environ.get("QPID_TOOLS_HOME", os.path.normpath("/usr/share/qpid-tools"))
+sys.path.append(os.path.join(home, "python"))
+
+from qpid.messaging import Connection
+from qpidtoollibs import BrokerAgent, BrokerObject
+
+desc = """Experimental generic configuration tool for qpidd. Note: this may be
+modified or removed in subsequent releases.
+"""
+usage = """
+ %prog [OPTIONS] create <type> <name> [properties]
+ %prog [OPTIONS] delete <type> <name> [arguments]
+ %prog [OPTIONS] list <type>
+"""
+def add_nameval(m, s):
+ idx = s.find("=")
+ if idx >= 0:
+ name = s[0:idx]
+ value = s[idx+1:]
+ else:
+ name = s
+ value = None
+ m[name] = value
+
+class Manager:
+ def __init__(self):
+ self.parser = OptionParser(description=desc, usage=usage)
+ self.url = None
+ self.conn_options = {}
+ self.command = None
+ self.typename = None
+ self.name = None
+ self.extra = {}
+ self.parser.add_option("-b", "--broker", action="store", type="string", metavar="<address>", help="Address of qpidd broker with syntax: [username/password@] hostname | ip-address [:<port>]")
+ self.parser.add_option("--sasl-mechanism", action="store", type="string", metavar="<mech>", help="SASL mechanism for authentication")
+ self.parser.add_option("--ssl-certificate", action="store", type="string", metavar="<cert>", help="Client SSL certificate (PEM Format)")
+ self.parser.add_option("--ssl-key", action="store", type="string", metavar="<key>", help="Client SSL private key (PEM Format)")
+ self.parser.add_option("--ha-admin", action="store_true", help="Allow connection to a HA backup broker.")
+
+ def parse_args(self, argv):
+ opts, args = self.parser.parse_args(args=argv)
+ self.url = opts.broker or "localhost:5672"
+ self.get_connection_options(opts)
+
+ if len(args) == 0:
+ self.command = "list"
+ elif len(args) == 1:
+ self.command = args.pop()
+ elif len(args) == 2:
+ self.command, self.typename = args[:2]
+ else:
+ self.command, self.typename, self.name = args[:3]
+ if len(args) > 3:
+ other = args[3:]
+ while len(other):
+ add_nameval(self.extra, other.pop())
+ if self.command == "create" or self.command == "delete":
+ if not self.typename:
+ parser.error("%s requires a type to be named (e.g. queue, exchange)")
+ if not self.name:
+ parser.error("%s requires an object name to be specified")
+ elif self.command != "list":
+ parser.error("Invalid command: %s. You must specify one of 'create', 'delete' or 'list'" % command)
+
+ def get_connection_options(self, opts):
+ if opts.sasl_mechanism:
+ self.conn_options['sasl_mechanisms'] = opts.sasl_mechanism
+ if opts.ssl_certificate:
+ self.conn_options['ssl_certfile'] = opts.ssl_certificate
+ if opts.ssl_key:
+ if not opts.ssl_certificate:
+ self.parser.error("missing '--ssl-certificate' (required by '--ssl-key')")
+ conn_options['ssl_keyfile'] = opts.ssl_key
+ if opts.ha_admin:
+ self.conn_options['client_properties'] = {'qpid.ha-admin' : 1}
+
+ def connect(self):
+ self.connection = Connection.establish(self.url, **self.conn_options)
+ self.agent = BrokerAgent(self.connection)
+
+ def disconnect(self):
+ self.connection.close()
+
+ def execute(self):
+ if self.command == "list":
+ objects = [i["_values"] for i in self.agent._doClassQuery(self.typename.lower())]
+ for o in objects:
+ name = ""
+ details = ""
+ for k, v in o.items():
+ if k == "name":
+ name = v
+ elif v:
+ if isinstance(v, dict) and v["_object_name"]:
+ v = v["_object_name"]
+ details += "%s=%s " %(k,v)
+ print "%-25s %s" % (name, details)
+ elif self.command == "create":
+ self.agent.create(self.typename, self.name, self.extra)
+ elif self.command == "delete":
+ self.agent.delete(self.typename, self.name, self.extra)
+
+def main(argv=None):
+ manager = Manager()
+ try:
+ manager.parse_args(argv)
+ manager.connect()
+ manager.execute()
+ manager.disconnect()
+ except Exception,e:
+ print "Failed: %s - %s" % (e.__class__.__name__, e)
+
+if __name__ == "__main__":
+ sys.exit(main())
+
diff --git a/qpid/cpp/src/tests/ssl.mk b/qpid/cpp/src/tests/ssl.mk
index 435db0c55b..1544dc5e71 100644
--- a/qpid/cpp/src/tests/ssl.mk
+++ b/qpid/cpp/src/tests/ssl.mk
@@ -19,4 +19,4 @@
TESTS+=ssl_test
EXTRA_DIST+=ssl_test
-CLEAN_LOCAL += test_cert_db cert.password
+CLEAN_LOCAL += test_cert_dir cert.password
diff --git a/qpid/cpp/src/tests/ssl_test b/qpid/cpp/src/tests/ssl_test
index 89aaf44af0..cfbd253ab8 100755
--- a/qpid/cpp/src/tests/ssl_test
+++ b/qpid/cpp/src/tests/ssl_test
@@ -22,33 +22,77 @@
# Run a simple test over SSL
source ./test_env.sh
+#set -x
+
CONFIG=$(dirname $0)/config.null
-CERT_DIR=`pwd`/test_cert_db
+TEST_CERT_DIR=`pwd`/test_cert_dir
+CERT_DB=${TEST_CERT_DIR}/test_cert_db
CERT_PW_FILE=`pwd`/cert.password
TEST_HOSTNAME=127.0.0.1
TEST_CLIENT_CERT=rumplestiltskin
+CA_PEM_FILE=${TEST_CERT_DIR}/ca_cert.pem
+OTHER_CA_CERT_DB=${TEST_CERT_DIR}/x_ca_cert_db
+OTHER_CA_PEM_FILE=${TEST_CERT_DIR}/other_ca_cert.pem
+PY_PING_BROKER=$top_srcdir/src/tests/ping_broker
COUNT=10
trap cleanup EXIT
error() { echo $*; exit 1; }
+# create the test certificate database
+# $1 = string used as Subject in server's certificate
+# $2 = string used as SubjectAlternateName (SAN) in server's certificate
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_CLIENT_CERT} -s "CN=${TEST_CLIENT_CERT}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+
+ local CERT_SUBJECT=${1:-"CN=${TEST_HOSTNAME},O=MyCo,ST=Massachusetts,C=US"}
+ local CERT_SAN=${2:-"*.server.com"}
+
+ mkdir -p ${TEST_CERT_DIR}
+ rm -rf ${TEST_CERT_DIR}/*
+
+ # Set Up a CA with a self-signed Certificate
+ #
+ mkdir -p ${CERT_DB}
+ certutil -N -d ${CERT_DB} -f ${CERT_PW_FILE}
+ certutil -S -d ${CERT_DB} -n "Test-CA" -s "CN=Test-CA,O=MyCo,ST=Massachusetts,C=US" -t "CT,," -x -f ${CERT_PW_FILE} -z /bin/sh >/dev/null 2>&1
+ certutil -L -d ${CERT_DB} -n "Test-CA" -a -o ${CERT_DB}/rootca.crt -f ${CERT_PW_FILE}
+ #certutil -L -d ${CERT_DB} -f ${CERT_PW_FILE}
+
+ # create server certificate signed by Test-CA
+ #
+ certutil -R -d ${CERT_DB} -s "${CERT_SUBJECT}" -o server.req -f ${CERT_PW_FILE} -z /bin/sh > /dev/null 2>&1
+ certutil -C -d ${CERT_DB} -c "Test-CA" -8 "${CERT_SAN}" -i server.req -o server.crt -f ${CERT_PW_FILE} -m ${RANDOM}
+ certutil -A -d ${CERT_DB} -n ${TEST_HOSTNAME} -i server.crt -t "Pu,,"
+ rm server.req server.crt
+
+ # create a certificate to identify the client
+ #
+ certutil -R -d ${CERT_DB} -s "CN=${TEST_CLIENT_CERT}" -o client.req -f ${CERT_PW_FILE} -z /bin/sh > /dev/null 2>&1
+ certutil -C -d ${CERT_DB} -c "Test-CA" -8 "*.client.com" -i client.req -o client.crt -f ${CERT_PW_FILE} -m ${RANDOM}
+ certutil -A -d ${CERT_DB} -n ${TEST_CLIENT_CERT} -i client.crt -t "Pu,,"
+ ###
+ #certutil -N -d ${SERVER_CERT_DIR} -f ${CERT_PW_FILE}
+ #certutil -S -d ${SERVER_CERT_DIR} -n ${TEST_HOSTNAME} -s "CN=${TEST_HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+ #certutil -S -d ${SERVER_CERT_DIR} -n ${TEST_CLIENT_CERT} -s "CN=${TEST_CLIENT_CERT}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+
+ # Set up a separate DB with its own CA for testing failure to validate scenario
+ #
+ mkdir -p ${OTHER_CA_CERT_DB}
+ certutil -N -d ${OTHER_CA_CERT_DB} -f ${CERT_PW_FILE}
+ certutil -S -d ${OTHER_CA_CERT_DB} -n "Other-Test-CA" -s "CN=Another Test CA,O=MyCo,ST=Massachusetts,C=US" -t "CT,," -x -f ${CERT_PW_FILE} -z /bin/sh >/dev/null 2>&1
+ certutil -L -d ${OTHER_CA_CERT_DB} -n "Other-Test-CA" -a -o ${OTHER_CA_CERT_DB}/rootca.crt -f ${CERT_PW_FILE}
+ #certutil -L -d ${OTHER_CA_CERT_DB} -f ${CERT_PW_FILE}
}
delete_certs() {
- if [[ -e ${CERT_DIR} ]] ; then
- rm -rf ${CERT_DIR}
+ if [[ -e ${TEST_CERT_DIR} ]] ; then
+ rm -rf ${TEST_CERT_DIR}
fi
}
# Don't need --no-module-dir or --no-data-dir as they are set as env vars in test_env.sh
-COMMON_OPTS="--daemon --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME"
+COMMON_OPTS="--daemon --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DB --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME"
# Start new brokers:
# $1 must be integer
@@ -89,6 +133,7 @@ pick_port() {
cleanup() {
stop_brokers
delete_certs
+ rm -f ${CERT_PW_FILE}
}
start_ssl_broker() {
@@ -123,14 +168,14 @@ if [[ !(-e ${CERT_PW_FILE}) ]] ; then
echo password > ${CERT_PW_FILE}
fi
delete_certs
-create_certs || error "Could not create test certificate"
+create_certs || error "Could not create test certificate database"
start_ssl_broker
PORT=${PORTS[0]}
echo "Running SSL test on port $PORT"
export QPID_NO_MODULE_DIR=1
export QPID_LOAD_MODULE=$SSLCONNECTOR_LIB
-export QPID_SSL_CERT_DB=${CERT_DIR}
+export QPID_SSL_CERT_DB=${CERT_DB}
export QPID_SSL_CERT_PASSWORD_FILE=${CERT_PW_FILE}
## Test connection via connection settings
@@ -193,3 +238,81 @@ echo "Running SSL/TCP mux test on random port $PORT"
./qpid-perftest --count ${COUNT} --port ${PORT} -P tcp -b $TEST_HOSTNAME --summary || error "TCP connection failed!"
stop_brokers
+
+### Additional tests that require 'openssl' and 'pk12util' to be installed (optional)
+
+PK12UTIL=$(type -p pk12util)
+if [[ !(-x $PK12UTIL) ]] ; then
+ echo >&2 "'pk12util' command not available, skipping remaining tests"
+ exit 0
+fi
+
+OPENSSL=$(type -p openssl)
+if [[ !(-x $OPENSSL) ]] ; then
+ echo >&2 "'openssl' command not available, skipping remaining tests"
+ exit 0
+fi
+
+## verify python version > 2.5 (only 2.6+ does certificate checking)
+PY_VERSION=$(python -c "import sys; print hex(sys.hexversion)")
+if (( PY_VERSION < 0x02060000 )); then
+ echo >&2 "Detected python version < 2.6 - skipping certificate verification tests"
+ exit 0
+fi
+
+echo "Testing Certificate validation and Authentication with the Python Client..."
+
+# extract the CA's certificate as a PEM file
+get_ca_certs() {
+ $PK12UTIL -o ${TEST_CERT_DIR}/CA_pk12.out -d ${CERT_DB} -n "Test-CA" -w ${CERT_PW_FILE} -k ${CERT_PW_FILE} > /dev/null
+ $OPENSSL pkcs12 -in ${TEST_CERT_DIR}/CA_pk12.out -out ${CA_PEM_FILE} -nokeys -passin file:${CERT_PW_FILE} >/dev/null
+ $PK12UTIL -o ${TEST_CERT_DIR}/other_CA_pk12.out -d ${OTHER_CA_CERT_DB} -n "Other-Test-CA" -w ${CERT_PW_FILE} -k ${CERT_PW_FILE} > /dev/null
+ $OPENSSL pkcs12 -in ${TEST_CERT_DIR}/other_CA_pk12.out -out ${OTHER_CA_PEM_FILE} -nokeys -passin file:${CERT_PW_FILE} >/dev/null
+}
+
+get_ca_certs || error "Could not extract CA certificates as PEM files"
+start_ssl_broker
+PORT=${PORTS[0]}
+URL=amqps://$TEST_HOSTNAME:$PORT
+# verify the python client can authenticate the broker using the CA
+if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${CA_PEM_FILE}`; then echo " Passed"; else { echo " Failed"; exit 1; }; fi
+# verify the python client fails to authenticate the broker when using the other CA
+if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${OTHER_CA_PEM_FILE} > /dev/null 2>&1`; then { echo " Failed"; exit 1; }; else echo " Passed"; fi
+stop_brokers
+
+# create a certificate without matching TEST_HOSTNAME, should fail to verify
+
+create_certs "O=MyCo" "*.${TEST_HOSTNAME}.com" || error "Could not create server test certificate"
+get_ca_certs || error "Could not extract CA certificates as PEM files"
+start_ssl_broker
+PORT=${PORTS[0]}
+URL=amqps://$TEST_HOSTNAME:$PORT
+if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${CA_PEM_FILE} > /dev/null 2>&1`; then { echo " Failed"; exit 1; }; else echo " Passed"; fi
+# but disabling the check for the hostname should pass
+if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${CA_PEM_FILE} --ssl-skip-hostname-check`; then echo " Passed"; else { echo " Failed"; exit 1; }; fi
+stop_brokers
+
+# test SubjectAltName parsing
+
+if (( PY_VERSION >= 0x02070300 )); then
+ # python 2.7.3+ supports SubjectAltName extraction
+ # create a certificate with TEST_HOSTNAME only in SAN, should verify OK
+ create_certs "O=MyCo" "*.foo.com,${TEST_HOSTNAME},*xyz.com" || error "Could not create server test certificate"
+ get_ca_certs || error "Could not extract CA certificates as PEM files"
+ start_ssl_broker
+ PORT=${PORTS[0]}
+ URL=amqps://$TEST_HOSTNAME:$PORT
+ if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${CA_PEM_FILE}`; then echo " Passed"; else { echo " Failed"; exit 1; }; fi
+ stop_brokers
+
+ create_certs "O=MyCo" "*${TEST_HOSTNAME}" || error "Could not create server test certificate"
+ get_ca_certs || error "Could not extract CA certificates as PEM files"
+ start_ssl_broker
+ PORT=${PORTS[0]}
+ URL=amqps://$TEST_HOSTNAME:$PORT
+ if `${PY_PING_BROKER} -b $URL --ssl-trustfile=${CA_PEM_FILE}`; then echo " Passed"; else { echo " Failed"; exit 1; }; fi
+ stop_brokers
+fi
+
+
+
diff --git a/qpid/doc/book/src/java-broker/commonEntities.xml b/qpid/doc/book/src/java-broker/commonEntities.xml
index a53440a467..ed0031e567 100644
--- a/qpid/doc/book/src/java-broker/commonEntities.xml
+++ b/qpid/doc/book/src/java-broker/commonEntities.xml
@@ -23,7 +23,7 @@
<!ENTITY qpidProgrammingBook "../../Programming-In-Apache-Qpid/html/">
<!ENTITY qpidCppBook "../../AMQP-Messaging-Broker-CPP-Book/html/">
-<!ENTITY qpidCurrentRelease "0.21">
+<!ENTITY qpidCurrentRelease "0.23">
<!-- Oracle javadoc -->
<!ENTITY oracleJdkDocUrl "http://oracle.com/javase/6/docs/api/">
diff --git a/qpid/extras/qmf/setup.py b/qpid/extras/qmf/setup.py
index db62ddba99..ddfba19a49 100755
--- a/qpid/extras/qmf/setup.py
+++ b/qpid/extras/qmf/setup.py
@@ -20,7 +20,7 @@
from distutils.core import setup
setup(name="qpid-qmf",
- version="0.21",
+ version="0.23",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
packages=["qmf"],
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
index 8b74eb1dce..4f6f122876 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -341,6 +341,26 @@ public class RestServlet extends AbstractServlet
}
}
+ if (names.isEmpty())
+ {
+ if (_hierarchy.length == 0)
+ {
+ try
+ {
+ doUpdate(getBroker(), providedObject);
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ catch(RuntimeException e)
+ {
+ setResponseStatus(response, e);
+ }
+ return;
+ }
+ else
+ {
+ throw new ServletException("Cannot identify request target object");
+ }
+ }
providedObject.put("name", names.get(names.size()-1));
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
index b20169c94d..fea67d5942 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -18,8 +18,26 @@
* under the License.
*
*/
-define(["dojo/_base/xhr"],
- function (xhr) {
+
+define(["dojo/_base/xhr",
+ "dojo/_base/event",
+ "dojo/_base/json",
+ "dojo/_base/lang",
+ "dojo/dom-construct",
+ "dojo/dom-geometry",
+ "dojo/window",
+ "dijit/Dialog",
+ "dijit/form/Form",
+ "dijit/form/Button",
+ "dijit/form/RadioButton",
+ "dijit/form/CheckBox",
+ "dojox/layout/TableContainer",
+ "dojox/layout/ScrollPane",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "dojo/domReady!"
+ ],
+ function (xhr, event, json, lang, dom, geometry, win) {
var util = {};
if (Array.isArray) {
util.isArray = function (object) {
@@ -122,5 +140,125 @@ define(["dojo/_base/xhr"],
return (type === "PlainPasswordFile" || type === "Base64MD5PasswordFile");
};
+ util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle)
+ {
+ var layout = new dojox.layout.TableContainer({
+ cols: 1,
+ "labelWidth": "300",
+ showLabels: true,
+ orientation: "horiz",
+ customClass: "formLabel"
+ });
+ var submitButton = new dijit.form.Button({label: "Submit", type: "submit"});
+ var form = new dijit.form.Form();
+
+ var dialogContent = dom.create("div");
+ var dialogContentArea = dom.create("div", { "class": "dijitDialogPaneContentArea"});
+ var dialogActionBar = dom.create("div", { "class": "dijitDialogPaneActionBar"} );
+ dialogContent.appendChild(dialogContentArea);
+ dialogContent.appendChild(dialogActionBar);
+ dialogContentArea.appendChild(layout.domNode)
+ dialogActionBar.appendChild(submitButton.domNode);
+ form.domNode.appendChild(dialogContent);
+
+ var widgets = {};
+ var requiredFor ={};
+ for(var i in attributeWidgetFactories)
+ {
+ var attributeWidgetFactory = attributeWidgetFactories[i];
+ var widget = attributeWidgetFactory.createWidget(data);
+ var name = attributeWidgetFactory.name ? attributeWidgetFactory.name : widget.name;
+ widgets[name] = widget;
+ widget.initialValue = widget.value;
+ layout.addChild(widget);
+ if (attributeWidgetFactory.hasOwnProperty("requiredFor"))
+ {
+ requiredFor[attributeWidgetFactory.requiredFor] = widget;
+ }
+ }
+
+ // add onchange handler to set required property for dependent widget
+ for(var widgetName in requiredFor)
+ {
+ var dependent = requiredFor[widgetName];
+ var widget = widgets[widgetName];
+ if (widget)
+ {
+ widget.dependent = dependent;
+ widget.on("change", function(newValue){
+ this.dependent.set("required", newValue != "");
+ });
+ }
+ }
+ var setAttributesDialog = new dijit.Dialog({
+ title: dialogTitle,
+ content: form,
+ style: "width: 600px; max-height: 80%"
+ });
+ form.on("submit", function(e)
+ {
+ event.stop(e);
+ try
+ {
+ if(form.validate())
+ {
+ var values = {};
+ for(var i in widgets)
+ {
+ var widget = widgets[i];
+ var value = widget.value;
+ var propName = widget.name;
+ if ((widget instanceof dijit.form.CheckBox || widget instanceof dijit.form.RadioButton))
+ {
+ values[ propName ] = widget.checked;
+ }
+ else if (value != widget.initialValue)
+ {
+ values[ propName ] = value ? value: null;
+ }
+ }
+
+ var that = this;
+ xhr.put({url: putURL, sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(values),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+ if(this.success === true)
+ {
+ setAttributesDialog.destroy();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+ return false;
+ }
+ else
+ {
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+ }
+ catch(e)
+ {
+ alert("Unexpected exception:" + e.message);
+ return false;
+ }
+ });
+ form.connectChildren(true);
+ setAttributesDialog.startup();
+ setAttributesDialog.on("show", function(){
+ var data = geometry.position(layout.domNode);
+ var maxHeight = win.getBox().h * 0.6;
+ if (data.h > maxHeight)
+ {
+ dialogContentArea.style.height = maxHeight + "px";
+ dialogContentArea.style.overflow= "auto";
+ }
+ })
+ setAttributesDialog.show();
+ };
+
return util;
}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
index 98d442bf14..6c2065fe9d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
@@ -35,6 +35,11 @@ define(["dojo/_base/xhr",
"dojox/grid/enhanced/plugins/IndirectSelection",
"dijit/layout/AccordionContainer",
"dijit/layout/AccordionPane",
+ "dijit/form/FilteringSelect",
+ "dijit/form/NumberSpinner",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/CheckBox",
+ "dojo/store/Memory",
"dojo/domReady!"],
function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid, registry, addAuthenticationProvider, addVirtualHost, addPort) {
@@ -45,7 +50,301 @@ define(["dojo/_base/xhr",
if(parent) {
this.modelObj.parent = {};
this.modelObj.parent[ parent.type] = parent;
- }
+ }
+ this.attributeWidgetFactories = [{
+ name: "name",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: true,
+ value: brokerData.name,
+ disabled: true,
+ label: "Name*:",
+ name: "name"})
+ }
+ }, {
+ name: "defaultAuthenticationProvider",
+ createWidget: function(brokerData) {
+ var providers = brokerData.authenticationproviders;
+ var data = [];
+ if (providers) {
+ for (var i=0; i< providers.length; i++) {
+ data.push({id: providers[i].name, name: providers[i].name});
+ }
+ }
+ var providersStore = new dojo.store.Memory({ data: data });
+ return new dijit.form.FilteringSelect({
+ required: true,
+ store: providersStore,
+ value: brokerData.defaultAuthenticationProvider,
+ label: "Default Authentication Provider*:",
+ name: "defaultAuthenticationProvider"})
+ }
+ }, {
+ name: "defaultVirtualHost",
+ createWidget: function(brokerData) {
+ var hosts = brokerData.virtualhosts;
+ var data = [];
+ if (hosts) {
+ for (var i=0; i< hosts.length; i++) {
+ data.push({id: hosts[i].name, name: hosts[i].name});
+ }
+ }
+ var hostsStore = new dojo.store.Memory({ data: data });
+ return new dijit.form.FilteringSelect({
+ required: true, store: hostsStore,
+ value: brokerData.defaultVirtualHost,
+ label: "Default Virtual Host*:",
+ name: "defaultVirtualHost"})
+ }
+ }, {
+ name: "aclFile",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.aclFile,
+ label: "ACL file location:",
+ name: "aclFile"})
+ }
+ }, {
+ name: "groupFile",
+ createWidget: function(brokerData)
+ {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.groupFile,
+ label: "Group file location:",
+ name: "groupFile"});
+ }
+ }, {
+ name: "keyStorePath",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.keyStorePath,
+ label: "Path to keystore:",
+ name: "keyStorePath"});
+ }
+ }, {
+ name: "keyStoreCertAlias",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.keyStoreCertAlias,
+ label: "Keystore certificate alias:",
+ name: "keyStoreCertAlias"});
+ }
+ }, {
+ name: "keyStorePassword",
+ requiredFor: "keyStorePath",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ label: "Keystore password:",
+ invalidMessage: "Missed keystore password",
+ name: "keyStorePassword"});
+ }
+ }, {
+ name: "trustStorePath",
+ createWidget: function(brokerData)
+ {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.trustStorePath,
+ label: "Path to truststore:",
+ name: "trustStorePath"});
+ }
+ }, {
+ name: "trustStorePassword",
+ requiredFor: "trustStorePath",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ label: "Truststore password:",
+ invalidMessage: "Missed trustore password",
+ name: "trustStorePassword"});
+ }
+ }, {
+ name: "peerStorePath",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ value: brokerData.peerStorePath,
+ label: "Path to peerstore:",
+ name: "peerStorePath"});
+ }
+ }, {
+ name: "peerStorePassword",
+ requiredFor: "peerStorePath",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ label: "Peerstore password:",
+ invalidMessage: "Missed peerstore password",
+ name: "peerStorePassword"});
+ }
+ }, {
+ name: "alertThresholdQueueDepth",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.alertThresholdQueueDepth,
+ placeholder: "Count of messages",
+ label: "Queue depth alert threshold:",
+ name: "alertThresholdQueueDepth"
+ });
+ }
+ }, {
+ name: "alertThresholdMessageAge",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.alertThresholdMessageAge,
+ placeholder: "Time in ms",
+ label: "Queue message age alert threshold:",
+ name: "alertThresholdMessageAge"
+ });
+ }
+ }, {
+ name: "alertThresholdMessageSize",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.alertThresholdMessageSize,
+ placeholder: "Size in bytes",
+ label: "Queue message size alert threshold:",
+ name: "alertThresholdMessageSize"
+ });
+ }
+ }, {
+ name: "alertRepeatGap",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.alertThresholdMessageSize,
+ value: brokerData.alertRepeatGap,
+ placeholder: "Time in ms",
+ label: "Queue alert repeat gap:",
+ name: "alertRepeatGap"
+ });
+ }
+ }, {
+ name: "maximumDeliveryAttempts",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.maximumDeliveryAttempts,
+ placeholder: "Count of messages",
+ label: "Queue maximum delivery retries:",
+ name: "maximumDeliveryAttempts"
+ });
+ }
+ }, {
+ name: "deadLetterQueueEnabled",
+ createWidget: function(brokerData) {
+ return new dijit.form.CheckBox({
+ required: false,
+ checked: brokerData.deadLetterQueueEnabled,
+ value: "true",
+ label: "Dead letter queue enabled:",
+ name: "deadLetterQueueEnabled",
+ });
+ }
+ }, {
+ name: "queueFlowControlSizeBytes",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.queueFlowControlSizeBytes,
+ placeholder: "Size in bytes",
+ label: "Queue flow capacity:",
+ name: "queueFlowControlSizeBytes",
+ });
+ }
+ }, {
+ name: "queueFlowResumeSizeBytes",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.queueFlowResumeSizeBytes,
+ placeholder: "Size in bytes",
+ label: "Queue flow resume capacity:",
+ name: "queueFlowResumeSizeBytes",
+ });
+ }
+ }, {
+ name: "sessionCountLimit",
+ createWidget: function(brokerData)
+ {
+ return new dijit.form.NumberSpinner({
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.sessionCountLimit,
+ smallDelta: 1,
+ constraints: {min:1,max:65535,places:0, pattern: "#####"},
+ label: "Connection session limit:",
+ name: "sessionCountLimit"
+ });
+ }
+ }, {
+ name: "heartBeatDelay",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.heartBeatDelay,
+ placeholder: "Time in ms",
+ label: "Heart beat delay:",
+ name: "heartBeatDelay"
+ });
+ }
+ }, {
+ name: "statisticsReportingPeriod",
+ createWidget: function(brokerData) {
+ return new dijit.form.ValidationTextBox({
+ trim: "true",
+ regexp: "[0-9]+",
+ invalidMessage: "Invalid value",
+ required: false,
+ value: brokerData.statisticsReportingPeriod,
+ placeholder: "Time in ms",
+ label: "Statistics reporting period:",
+ name: "statisticsReportingPeriod"
+ });
+ }
+ }, {
+ name: "statisticsReportingResetEnabled",
+ createWidget: function(brokerData)
+ {
+ return new dijit.form.CheckBox({
+ required: false, checked: brokerData.statisticsReportingResetEnabled, value: "true",
+ label: "Statistics reporting period enabled:",
+ name: "statisticsReportingResetEnabled"
+ });
+ }
+ } ];
}
Broker.prototype.getTitle = function()
@@ -62,7 +361,7 @@ define(["dojo/_base/xhr",
contentPane.containerNode.innerHTML = data;
parser.parse(contentPane.containerNode);
- that.brokerUpdater = new BrokerUpdater(contentPane.containerNode, that.modelObj, that.controller);
+ that.brokerUpdater = new BrokerUpdater(contentPane.containerNode, that.modelObj, that.controller, that.attributeWidgetFactories);
updater.add( that.brokerUpdater );
@@ -109,6 +408,18 @@ define(["dojo/_base/xhr",
"Are you sure you want to delete port");
}
);
+
+ var editButton = query(".editBroker", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(editButton), "onClick",
+ function(evt){
+ util.showSetAttributesDialog(
+ that.attributeWidgetFactories,
+ that.brokerUpdater.brokerData,
+ "rest/broker",
+ "Set broker attributes");
+ }
+ );
+
}});
};
@@ -116,16 +427,11 @@ define(["dojo/_base/xhr",
updater.remove( this.brokerUpdater );
};
- function BrokerUpdater(node, brokerObj, controller)
+ function BrokerUpdater(node, brokerObj, controller, attributes)
{
this.controller = controller;
- this.name = query(".broker-name", node)[0];
- /*this.state = dom.byId("state");
- this.durable = dom.byId("durable");
- this.lifetimePolicy = dom.byId("lifetimePolicy");
- */
this.query = "rest/broker";
-
+ this.attributes = attributes;
var that = this;
xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
@@ -135,6 +441,7 @@ define(["dojo/_base/xhr",
util.flattenStatistics( that.brokerData);
+ that.showReadOnlyAttributes();
that.updateHeader();
var gridProperties = {
@@ -259,11 +566,28 @@ define(["dojo/_base/xhr",
BrokerUpdater.prototype.updateHeader = function()
{
- this.name.innerHTML = this.brokerData[ "name" ];
- /* this.state.innerHTML = this.brokerData[ "state" ];
- this.durable.innerHTML = this.brokerData[ "durable" ];
- this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ];
-*/
+ var brokerData = this.brokerData;
+ for(var i in this.attributes)
+ {
+ var propertyName = this.attributes[i].name;
+ var element = dojo.byId("brokerAttribute." + propertyName);
+ if (element)
+ {
+ if (brokerData.hasOwnProperty(propertyName))
+ {
+ var container = dojo.byId("brokerAttribute." + propertyName + ".container");
+ if (container)
+ {
+ container.style.display = "block";
+ }
+ element.innerHTML = brokerData [propertyName];
+ }
+ else
+ {
+ element.innerHTML = "";
+ }
+ }
+ }
};
BrokerUpdater.prototype.update = function()
@@ -295,7 +619,18 @@ define(["dojo/_base/xhr",
};
-
+ BrokerUpdater.prototype.showReadOnlyAttributes = function()
+ {
+ var brokerData = this.brokerData;
+ dojo.byId("brokerAttribute.name").innerHTML = brokerData.name;
+ dojo.byId("brokerAttribute.operatingSystem").innerHTML = brokerData.operatingSystem;
+ dojo.byId("brokerAttribute.platform").innerHTML = brokerData.platform;
+ dojo.byId("brokerAttribute.productVersion").innerHTML = brokerData.productVersion;
+ dojo.byId("brokerAttribute.managementVersion").innerHTML = brokerData.managementVersion;
+ dojo.byId("brokerAttribute.storeType").innerHTML = brokerData.storeType;
+ dojo.byId("brokerAttribute.storeVersion").innerHTML = brokerData.storeVersion;
+ dojo.byId("brokerAttribute.storePath").innerHTML = brokerData.storePath;
+ }
return Broker;
});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
index 60c514e262..bdcff2b7e9 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -19,14 +19,131 @@
-
-->
<div class="broker">
- <span>Name:</span><span class="broker-name" style="position:absolute; left:6em"></span>
- <br/>
-<!-- <span>State:</span><span class="broker-state" style="position:absolute; left:6em"></span>
- <br/>
- <span>Durable:</span><span class="broker-durable" style="position:absolute; left:6em"></span>
- <br/>
- <span>Lifespan:</span><span class="broker-lifetimePolicy" style="position:absolute; left:6em" ></span>
- <br/> -->
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Broker Attributes', open: false">
+ <div id="brokerAttributes" style="clear:both">
+ <div id="brokerAttribute.name.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker name:</div>
+ <div id="brokerAttribute.name" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.operatingSystem.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Operation system:</div>
+ <div id="brokerAttribute.operatingSystem" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.platform.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Platform:</div>
+ <div id="brokerAttribute.platform" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.productVersion.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker version:</div>
+ <div id="brokerAttribute.productVersion" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.managementVersion.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker management version:</div>
+ <div id="brokerAttribute.managementVersion" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.storeType.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker store type:</div>
+ <div id="brokerAttribute.storeType" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.storeVersion.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker store version:</div>
+ <div id="brokerAttribute.storeVersion" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.storePath.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker store location:</div>
+ <div id="brokerAttribute.storePath" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.defaultAuthenticationProvider.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Default authentication provider:</div>
+ <div id="brokerAttribute.defaultAuthenticationProvider" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.defaultVirtualHost.container" style="display: none; clear:both; clear:both;">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Default virtual host:</div>
+ <div id="brokerAttribute.defaultVirtualHost" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.aclFile.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">ACL file location:</div>
+ <div id="brokerAttribute.aclFile" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.groupFile.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Group file location:</div>
+ <div id="brokerAttribute.groupFile" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.keyStorePath.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to keystore:</div>
+ <div id="brokerAttribute.keyStorePath" style="float:left;"></div><br/>
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Keystore alias:</div>
+ <div id="brokerAttribute.keyStoreCertAlias" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.trustStorePath.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to truststore:</div>
+ <div id="brokerAttribute.trustStorePath" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.peerStorePath.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to peerstore:</div>
+ <div id="brokerAttribute.peerStorePath" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.statisticsReportingPeriod.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Statistics reporting period:</div>
+ <div id="brokerAttribute.statisticsReportingPeriod" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.statisticsReportingResetEnabled.container" style="display: none; clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Statistics reporting period enabled:</div>
+ <div id="brokerAttribute.statisticsReportingResetEnabled" style="float:left;"></div>
+ </div>
+ <div style="clear:both"></div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Queue Attributes', open: true">
+ <div id="brokerAttribute.alertThresholdQueueDepth.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue depth alert threshold:</div>
+ <div id="brokerAttribute.alertThresholdQueueDepth" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.alertThresholdMessageAge.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue message age alert threshold:</div>
+ <div id="brokerAttribute.alertThresholdMessageAge" style="float:left;"></div> ms
+ </div>
+ <div id="brokerAttribute.alertThresholdMessageSize.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue message size alert threshold:</div>
+ <div id="brokerAttribute.alertThresholdMessageSize" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.alertRepeatGap.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue alert repeat gap:</div>
+ <div id="brokerAttribute.alertRepeatGap" style="float:left;"></div> ms
+ </div>
+ <div id="brokerAttribute.maximumDeliveryAttempts.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue maximum delivery retries:</div>
+ <div id="brokerAttribute.maximumDeliveryAttempts" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.deadLetterQueueEnabled.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Dead letter queue enabled:</div>
+ <div id="brokerAttribute.deadLetterQueueEnabled" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.queueFlowControlSizeBytes.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue flow capacity:</div>
+ <div id="brokerAttribute.queueFlowControlSizeBytes" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.queueFlowResumeSizeBytes.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue flow resume capacity:</div>
+ <div id="brokerAttribute.queueFlowResumeSizeBytes" style="float:left;"></div>
+ </div>
+ <div style="clear:both"></div>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Connection attributes', open: true">
+ <div id="brokerAttribute.sessionCountLimit.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Connection session limit:</div>
+ <div id="brokerAttribute.sessionCountLimit" style="float:left;"></div>
+ </div>
+ <div id="brokerAttribute.heartBeatDelay.container" style="clear:both">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Heart beat delay:</div>
+ <div id="brokerAttribute.heartBeatDelay" style="float:left;"></div> ms
+ </div>
+ <div style="clear:both"></div>
+ </div>
+ </div>
+ <br/>
+ <button data-dojo-type="dijit.form.Button" class="editBroker">Edit</button>
+ </div>
<br/>
<div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Virtual Hosts'">
<div class="broker-virtualhosts"></div>
diff --git a/qpid/java/broker/src/main/java/broker.bnd b/qpid/java/broker/src/main/java/broker.bnd
index bf338543f7..2edbab79a5 100755
--- a/qpid/java/broker/src/main/java/broker.bnd
+++ b/qpid/java/broker/src/main/java/broker.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.21.0
+ver: 0.23.0
Bundle-SymbolicName: qpid-broker
Bundle-Version: ${ver}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationEntryStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationEntryStore.java
index d514bf25ce..5f3589c7ef 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationEntryStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigurationEntryStore.java
@@ -62,12 +62,26 @@ public interface ConfigurationEntryStore
* @param target location to copy store into
* @throws IllegalConfigurationException if store cannot be copied into given location
*/
- public void copyTo(String copyLocation);
+ void copyTo(String copyLocation);
/**
* Return the store location for the opened store or null if store has not been opened.
*
* @return store location for the opened store or null if store has not been opened
*/
- public String getStoreLocation();
+ String getStoreLocation();
+
+ /**
+ * Returns the version of the store
+ *
+ * @return store version
+ */
+ int getVersion();
+
+ /**
+ * Returns the type of the store
+ *
+ * @return store type
+ */
+ String getType();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/AuthenticationProviderRecoverer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/AuthenticationProviderRecoverer.java
index 9b06a2b499..3290c827c9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/AuthenticationProviderRecoverer.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/AuthenticationProviderRecoverer.java
@@ -47,7 +47,7 @@ public class AuthenticationProviderRecoverer implements ConfiguredObjectRecovere
AuthenticationProvider authenticationProvider = _authenticationProviderFactory.create(
configurationEntry.getId(),
broker,
- attributes, null);
+ attributes);
return authenticationProvider;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
index 3d19e781e2..0d7be75a0b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
@@ -18,7 +18,6 @@ import org.apache.qpid.server.model.adapter.BrokerAdapter;
import org.apache.qpid.server.model.adapter.PortFactory;
import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
import org.apache.qpid.server.configuration.updater.TaskExecutor;
-import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
@@ -50,7 +49,7 @@ public class BrokerRecoverer implements ConfiguredObjectRecoverer<Broker>
{
StoreConfigurationChangeListener storeChangeListener = new StoreConfigurationChangeListener(entry.getStore());
BrokerAdapter broker = new BrokerAdapter(entry.getId(), entry.getAttributes(), _statisticsGatherer, _virtualHostRegistry,
- _logRecorder, _rootMessageLogger, _authenticationProviderFactory, _portFactory, _taskExecutor);
+ _logRecorder, _rootMessageLogger, _authenticationProviderFactory, _portFactory, _taskExecutor, entry.getStore());
broker.addChangeListener(storeChangeListener);
Map<String, Collection<ConfigurationEntry>> childEntries = entry.getChildren();
@@ -103,12 +102,6 @@ public class BrokerRecoverer implements ConfiguredObjectRecoverer<Broker>
}
broker.setDefaultAuthenticationProvider(defaultAuthenticationProvider);
- GroupPrincipalAccessor groupPrincipalAccessor = new GroupPrincipalAccessor(broker.getGroupProviders());
- for (AuthenticationProvider authenticationProvider : authenticationProviders)
- {
- authenticationProvider.setGroupAccessor(groupPrincipalAccessor);
- }
-
Collection<Port> ports = broker.getPorts();
for (Port port : ports)
{
@@ -128,7 +121,7 @@ public class BrokerRecoverer implements ConfiguredObjectRecoverer<Broker>
private AuthenticationProvider getAuthenticationProviderByName(BrokerAdapter broker, String authenticationProviderName)
{
- AuthenticationProvider provider = broker.getAuthenticationProviderByName(authenticationProviderName);
+ AuthenticationProvider provider = broker.findAuthenticationProviderByName(authenticationProviderName);
if (provider == null)
{
throw new IllegalConfigurationException("Cannot find the authentication provider with name: "
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java
index 2ee072e5ff..413e9d2563 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java
@@ -57,6 +57,12 @@ public class JsonConfigurationEntryStore extends MemoryConfigurationEntryStore
}
@Override
+ public String getType()
+ {
+ return STORE_TYPE;
+ }
+
+ @Override
public String toString()
{
return "JsonConfigurationEntryStore [_storeFile=" + _storeFile + ", _rootId=" + getRootEntry().getId() + "]";
@@ -81,7 +87,7 @@ public class JsonConfigurationEntryStore extends MemoryConfigurationEntryStore
ConfigurationEntry rootEntry = initialStore.getRootEntry();
Map<UUID, ConfigurationEntry> entries = new HashMap<UUID, ConfigurationEntry>();
copyEntry(rootEntry.getId(), initialStore, entries);
- saveAsTree(rootEntry.getId(), entries, getObjectMapper(), storeFile);
+ saveAsTree(rootEntry.getId(), entries, getObjectMapper(), storeFile, getVersion());
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java
index 59247df25a..385d2f7327 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java
@@ -149,6 +149,18 @@ public class ManagementModeStoreHandler implements ConfigurationEntryStore
return _store.getStoreLocation();
}
+ @Override
+ public int getVersion()
+ {
+ return _store.getVersion();
+ }
+
+ @Override
+ public String getType()
+ {
+ return _store.getType();
+ }
+
private Map<UUID, ConfigurationEntry> createPortsFromCommadLineOptions(BrokerOptions options)
{
int managementModeRmiPort = options.getManagementModeRmiPort();
@@ -312,4 +324,5 @@ public class ManagementModeStoreHandler implements ConfigurationEntryStore
}
return new ConfigurationEntry(entry.getId(), entry.getType(), attributes, children, entry.getStore());
}
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java
index 48ca01c312..5944adaa99 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java
@@ -66,6 +66,8 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore
private static final String ID = "id";
private static final String TYPE = "@type";
+ private static final int STORE_VERSION = 1;
+
private final ObjectMapper _objectMapper;
private final Map<UUID, ConfigurationEntry> _entries;
private final Map<String, Class<? extends ConfiguredObject>> _relationshipClasses;
@@ -189,6 +191,18 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore
}
@Override
+ public int getVersion()
+ {
+ return STORE_VERSION;
+ }
+
+ @Override
+ public String getType()
+ {
+ return STORE_TYPE;
+ }
+
+ @Override
public String toString()
{
return "MemoryConfigurationEntryStore [_rootId=" + _rootId + "]";
@@ -215,12 +229,13 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore
protected void saveAsTree(File file)
{
- saveAsTree(_rootId, _entries, _objectMapper, file);
+ saveAsTree(_rootId, _entries, _objectMapper, file, STORE_VERSION);
}
- protected void saveAsTree(UUID rootId, Map<UUID, ConfigurationEntry> entries, ObjectMapper mapper, File file)
+ protected void saveAsTree(UUID rootId, Map<UUID, ConfigurationEntry> entries, ObjectMapper mapper, File file, int version)
{
Map<String, Object> tree = toTree(rootId, entries);
+ tree.put(Broker.STORE_VERSION, version);
try
{
mapper.writeValue(file, tree);
@@ -317,8 +332,11 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore
throw new IllegalConfigurationException("Duplicate id is found: " + entryId
+ "! The following configuration entries have the same id: " + entries.get(entryId) + ", " + entry);
}
- entries.put(entryId, entry);
+
Set<UUID> children = entry.getChildrenIds();
+ Set<UUID> childrenCopy = children == null? null : new HashSet<UUID>(children);
+ ConfigurationEntry copy = new ConfigurationEntry(entryId, entry.getType(), new HashMap<String, Object>(entry.getAttributes()), childrenCopy, this);
+ entries.put(entryId, copy);
if (children != null)
{
for (UUID uuid : children)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/updater/ChangeAttributesTask.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/updater/ChangeAttributesTask.java
new file mode 100644
index 0000000000..4ba4057fee
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/updater/ChangeAttributesTask.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration.updater;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+
+public class ChangeAttributesTask implements Callable<Void>
+{
+ private final Map<String, Object> _attributes;
+ private final ConfiguredObject _object;
+
+ public ChangeAttributesTask(ConfiguredObject target, Map<String, Object> attributes)
+ {
+ super();
+ _object = target;
+ _attributes = attributes;
+ }
+
+ @Override
+ public Void call() throws Exception
+ {
+ _object.setAttributes(_attributes);
+ return null;
+ }
+
+ public Map<String, Object> getAttributes()
+ {
+ return _attributes;
+ }
+
+ public ConfiguredObject getObject()
+ {
+ return _object;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ChangeAttributesTask [object=" + _object + ", attributes=" + _attributes + "]";
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
index 2e5c3a0cc7..61ceae9cf0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
@@ -25,7 +25,6 @@ import java.util.Collection;
import java.util.Collections;
import org.apache.qpid.server.security.SubjectCreator;
-import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
public interface AuthenticationProvider extends ConfiguredObject
{
@@ -67,5 +66,4 @@ public interface AuthenticationProvider extends ConfiguredObject
*/
SubjectCreator getSubjectCreator();
- void setGroupAccessor(GroupPrincipalAccessor groupPrincipalAccessor);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
index 1d2fdd0452..21a22d032d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
@@ -71,6 +71,10 @@ public interface Broker extends ConfiguredObject
String HEART_BEAT_DELAY = "heartBeatDelay";
String STATISTICS_REPORTING_PERIOD = "statisticsReportingPeriod";
String STATISTICS_REPORTING_RESET_ENABLED = "statisticsReportingResetEnabled";
+ String STORE_TYPE = "storeType";
+ String STORE_VERSION = "storeVersion";
+ String STORE_PATH = "storePath";
+ String MANAGEMENT_VERSION = "managementVersion";
/*
* A temporary attribute to pass the path to ACL file.
@@ -131,6 +135,10 @@ public interface Broker extends ConfiguredObject
HEART_BEAT_DELAY,
STATISTICS_REPORTING_PERIOD,
STATISTICS_REPORTING_RESET_ENABLED,
+ STORE_TYPE,
+ STORE_VERSION,
+ STORE_PATH,
+ MANAGEMENT_VERSION,
ACL_FILE,
KEY_STORE_PATH,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
index 2c05dce9cb..3244d55fe2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
@@ -29,6 +29,12 @@ import java.util.Map;
public class Model
{
+ /*
+ * API version for the broker management interfaces
+ */
+ public static final int MANAGEMENT_API_MAJOR_VERSION = 1;
+ public static final int MANAGEMENT_API_MINOR_VERSION = 0;
+
private static final Model MODEL_INSTANCE = new Model();
private final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
index 6b6cce3ffa..ce8e06bf4f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
@@ -27,12 +27,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.concurrent.Callable;
import org.apache.qpid.server.model.ConfigurationChangeListener;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.IllegalStateTransitionException;
import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.configuration.updater.ChangeAttributesTask;
import org.apache.qpid.server.configuration.updater.ChangeStateTask;
import org.apache.qpid.server.configuration.updater.CreateChildTask;
import org.apache.qpid.server.configuration.updater.SetAttributeTask;
@@ -56,7 +56,14 @@ abstract class AbstractAdapter implements ConfiguredObject
_id = id;
if (attributes != null)
{
- _attributes.putAll(attributes);
+ Collection<String> names = getAttributeNames();
+ for (String name : names)
+ {
+ if (attributes.containsKey(name))
+ {
+ _attributes.put(name, attributes.get(name));
+ }
+ }
}
if (defaults != null)
{
@@ -88,13 +95,17 @@ abstract class AbstractAdapter implements ConfiguredObject
if (setState(currentState, desiredState))
{
notifyStateChanged(currentState, desiredState);
+ return desiredState;
+ }
+ else
+ {
+ return getActualState();
}
}
else
{
- _taskExecutor.submitAndWait(new ChangeStateTask(this, currentState, desiredState));
+ return (State)_taskExecutor.submitAndWait(new ChangeStateTask(this, currentState, desiredState));
}
- return getActualState();
}
/**
@@ -218,13 +229,17 @@ abstract class AbstractAdapter implements ConfiguredObject
if (changeAttribute(name, expected, desired))
{
attributeSet(name, expected, desired);
+ return desired;
+ }
+ else
+ {
+ return getAttribute(name);
}
}
else
{
- _taskExecutor.submitAndWait(new SetAttributeTask(this, name, expected, desired));
+ return _taskExecutor.submitAndWait(new SetAttributeTask(this, name, expected, desired));
}
- return getAttribute(name);
}
protected boolean changeAttribute(final String name, final Object expected, final Object desired)
@@ -322,30 +337,23 @@ abstract class AbstractAdapter implements ConfiguredObject
}
else
{
- getTaskExecutor().submitAndWait(new Callable<Void>()
- {
-
- @Override
- public Void call() throws Exception
- {
- AbstractAdapter.this.setAttributes(attributes);
- return null;
- }
- });
+ getTaskExecutor().submitAndWait(new ChangeAttributesTask(this, attributes));
}
-
}
protected void changeAttributes(final Map<String, Object> attributes)
{
- for (Map.Entry<String, Object> attributeEntry : attributes.entrySet())
+ Collection<String> names = getAttributeNames();
+ for (String name : names)
{
- String name = attributeEntry.getKey();
- Object desired = attributeEntry.getValue();
- Object expected = getAttribute(name);
- if (changeAttribute(name, expected, desired))
+ if (attributes.containsKey(name))
{
- attributeSet(name, expected, desired);
+ Object desired = attributes.get(name);
+ Object expected = getAttribute(name);
+ if (changeAttribute(name, expected, desired))
+ {
+ attributeSet(name, expected, desired);
+ }
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
index 16c6cb7e5e..0c17637e2f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
@@ -67,19 +67,29 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
protected T _authManager;
protected final Broker _broker;
- private GroupPrincipalAccessor _groupAccessor;
-
protected Collection<String> _supportedAttributes;
- Map<String, AuthenticationManagerFactory> _factories;
+ protected Map<String, AuthenticationManagerFactory> _factories;
private AuthenticationProviderAdapter(UUID id, Broker broker, final T authManager, Map<String, Object> attributes, Collection<String> attributeNames)
{
- super(id, null, attributes, broker.getTaskExecutor());
+ super(id, null, null, broker.getTaskExecutor());
_authManager = authManager;
_broker = broker;
_supportedAttributes = createSupportedAttributes(attributeNames);
_factories = getAuthenticationManagerFactories();
addParent(Broker.class, broker);
+
+ // set attributes now after all attribute names are known
+ if (attributes != null)
+ {
+ for (String name : _supportedAttributes)
+ {
+ if (attributes.containsKey(name))
+ {
+ changeAttribute(name, null, attributes.get(name));
+ }
+ }
+ }
}
T getAuthManager()
@@ -198,7 +208,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
@Override
public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz)
{
- return null;
+ return Collections.emptySet();
}
@Override
@@ -222,14 +232,12 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
throw new IntegrityViolationException("Authentication provider '" + providerName + "' is set on port " + port.getName());
}
}
+ _authManager.close();
+ _authManager.onDelete();
return true;
}
else if(desiredState == State.ACTIVE)
{
- if (_groupAccessor == null)
- {
- throw new IllegalStateTransitionException("Cannot transit into ACTIVE state with null group accessor!");
- }
_authManager.initialise();
return true;
}
@@ -244,12 +252,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
@Override
public SubjectCreator getSubjectCreator()
{
- return new SubjectCreator(_authManager, _groupAccessor);
- }
-
- public void setGroupAccessor(GroupPrincipalAccessor groupAccessor)
- {
- _groupAccessor = groupAccessor;
+ return new SubjectCreator(_authManager, new GroupPrincipalAccessor(_broker.getGroupProviders()));
}
@Override
@@ -331,7 +334,6 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
}
-
}
public static class PrincipalDatabaseAuthenticationManagerAdapter
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactory.java
index 721282fb9c..353e9f83bf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactory.java
@@ -27,13 +27,14 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
import org.apache.qpid.server.plugin.AuthenticationManagerFactory;
import org.apache.qpid.server.plugin.QpidServiceLoader;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
-import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.apache.qpid.server.model.adapter.AuthenticationProviderAdapter.PrincipalDatabaseAuthenticationManagerAdapter;
import org.apache.qpid.server.model.adapter.AuthenticationProviderAdapter.SimpleAuthenticationProviderAdapter;
@@ -58,9 +59,8 @@ public class AuthenticationProviderFactory
* <p>
* The configured {@link AuthenticationManagerFactory}'s are used to try to create the {@link AuthenticationProvider}.
* The first non-null instance is returned. The factories are used in non-deterministic order.
- * @param groupPrincipalAccessor TODO
*/
- public AuthenticationProvider create(UUID id, Broker broker, Map<String, Object> attributes, GroupPrincipalAccessor groupPrincipalAccessor)
+ public AuthenticationProvider create(UUID id, Broker broker, Map<String, Object> attributes)
{
for (AuthenticationManagerFactory factory : _factories)
{
@@ -70,14 +70,30 @@ public class AuthenticationProviderFactory
AuthenticationProviderAdapter<?> authenticationProvider;
if (manager instanceof PrincipalDatabaseAuthenticationManager)
{
+ // a temporary restriction to prevent creation of several instances
+ // of PlainPasswordFileAuthenticationProvider/Base64MD5PasswordFileAuthenticationProvider
+ // due to current limitation of JMX management which cannot cope
+ // with several user management MBeans as MBean type is used as a name.
+
+ // TODO: Remove this check after fixing of JMX management
+ for (AuthenticationProvider provider : broker.getAuthenticationProviders())
+ {
+ if (provider instanceof PasswordCredentialManagingAuthenticationProvider)
+ {
+ throw new IllegalConfigurationException("An authentication provider which can manage users alredy exists ["
+ + provider.getName() + "]. Only one instance is allowed.");
+ }
+ }
+
+ manager.onCreate();
authenticationProvider = new PrincipalDatabaseAuthenticationManagerAdapter(id, broker,
(PrincipalDatabaseAuthenticationManager) manager, attributes, factory.getAttributeNames());
}
else
{
+ manager.onCreate();
authenticationProvider = new SimpleAuthenticationProviderAdapter(id, broker, manager, attributes, factory.getAttributeNames());
}
- authenticationProvider.setGroupAccessor(groupPrincipalAccessor);
return authenticationProvider;
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
index 1492982708..73706904e5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.AccessControlException;
+import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -32,9 +33,11 @@ import java.util.Map;
import java.util.UUID;
import javax.net.ssl.KeyManagerFactory;
+import java.security.cert.Certificate;
import org.apache.log4j.Logger;
import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.configuration.ConfigurationEntryStore;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.LogRecorder;
import org.apache.qpid.server.logging.RootMessageLogger;
@@ -47,6 +50,7 @@ import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.GroupProvider;
import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Model;
import org.apache.qpid.server.model.Plugin;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.State;
@@ -59,13 +63,13 @@ import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordFileAuthent
import org.apache.qpid.server.security.auth.manager.PlainPasswordFileAuthenticationManagerFactory;
import org.apache.qpid.server.security.group.FileGroupManager;
import org.apache.qpid.server.security.group.GroupManager;
-import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.store.MessageStoreCreator;
import org.apache.qpid.server.util.MapValueConverter;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class BrokerAdapter extends AbstractAdapter implements Broker, ConfigurationChangeListener
{
@@ -124,6 +128,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private static final String DEFAULT_KEY_STORE_NAME = "defaultKeyStore";
private static final String DEFAULT_TRUST_STORE_NAME = "defaultTrustStore";
private static final String DEFAULT_GROUP_PROFIDER_NAME = "defaultGroupProvider";
+ private static final String DEFAULT_PEER_STORE_NAME = "defaultPeerStore";
private static final String DUMMY_PASSWORD_MASK = "********";
@@ -146,7 +151,10 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
put(Broker.NAME, DEFAULT_NAME);
}});
-
+ private String[] POSITIVE_NUMERIC_ATTRIBUTES = { ALERT_THRESHOLD_MESSAGE_AGE, ALERT_THRESHOLD_MESSAGE_COUNT,
+ ALERT_THRESHOLD_QUEUE_DEPTH, ALERT_THRESHOLD_MESSAGE_SIZE, ALERT_REPEAT_GAP, FLOW_CONTROL_SIZE_BYTES,
+ FLOW_CONTROL_RESUME_SIZE_BYTES, MAXIMUM_DELIVERY_ATTEMPTS, HOUSEKEEPING_CHECK_PERIOD, SESSION_COUNT_LIMIT,
+ HEART_BEAT_DELAY, STATISTICS_REPORTING_PERIOD };
private final StatisticsGatherer _statisticsGatherer;
@@ -171,11 +179,12 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private final UUID _defaultKeyStoreId;
private final UUID _defaultTrustStoreId;
- private Collection<String> _supportedStoreTypes;
+ private final Collection<String> _supportedStoreTypes;
+ private final ConfigurationEntryStore _brokerStore;
public BrokerAdapter(UUID id, Map<String, Object> attributes, StatisticsGatherer statisticsGatherer, VirtualHostRegistry virtualHostRegistry,
LogRecorder logRecorder, RootMessageLogger rootMessageLogger, AuthenticationProviderFactory authenticationProviderFactory,
- PortFactory portFactory, TaskExecutor taskExecutor)
+ PortFactory portFactory, TaskExecutor taskExecutor, ConfigurationEntryStore brokerStore)
{
super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), taskExecutor);
_statisticsGatherer = statisticsGatherer;
@@ -186,11 +195,12 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
_authenticationProviderFactory = authenticationProviderFactory;
_portFactory = portFactory;
_securityManager = new SecurityManager((String)getAttribute(ACL_FILE));
-
+ addChangeListener(_securityManager);
_defaultKeyStoreId = UUIDGenerator.generateBrokerChildUUID(KeyStore.class.getSimpleName(), DEFAULT_KEY_STORE_NAME);
_defaultTrustStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_TRUST_STORE_NAME);
createBrokerChildrenFromAttributes();
_supportedStoreTypes = new MessageStoreCreator().getStoreTypes();
+ _brokerStore = brokerStore;
}
/*
@@ -198,6 +208,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
*/
private void createBrokerChildrenFromAttributes()
{
+ createGroupProvider();
+ createKeyStore();
+ createTrustStore();
+ createPeerStore();
+ }
+
+ private void createGroupProvider()
+ {
String groupFile = (String) getAttribute(GROUP_FILE);
if (groupFile != null)
{
@@ -205,8 +223,16 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
UUID groupProviderId = UUIDGenerator.generateBrokerChildUUID(GroupProvider.class.getSimpleName(),
DEFAULT_GROUP_PROFIDER_NAME);
GroupProviderAdapter groupProviderAdapter = new GroupProviderAdapter(groupProviderId, groupManager, this);
- addGroupProvider(groupProviderAdapter);
+ _groupProviders.put(DEFAULT_GROUP_PROFIDER_NAME, groupProviderAdapter);
+ }
+ else
+ {
+ _groupProviders.remove(DEFAULT_GROUP_PROFIDER_NAME);
}
+ }
+
+ private void createKeyStore()
+ {
Map<String, Object> actualAttributes = getActualAttributes();
String keyStorePath = (String) getAttribute(KEY_STORE_PATH);
if (keyStorePath != null)
@@ -218,9 +244,18 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
keyStoreAttributes.put(KeyStore.TYPE, java.security.KeyStore.getDefaultType());
keyStoreAttributes.put(KeyStore.CERTIFICATE_ALIAS, getAttribute(KEY_STORE_CERT_ALIAS));
keyStoreAttributes.put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- KeyStoreAdapter KeyStoreAdapter = new KeyStoreAdapter(_defaultKeyStoreId, this, keyStoreAttributes);
- addKeyStore(KeyStoreAdapter);
+ KeyStoreAdapter keyStoreAdapter = new KeyStoreAdapter(_defaultKeyStoreId, this, keyStoreAttributes);
+ _keyStores.put(keyStoreAdapter.getId(), keyStoreAdapter);
+ }
+ else
+ {
+ _keyStores.remove(_defaultKeyStoreId);
}
+ }
+
+ private void createTrustStore()
+ {
+ Map<String, Object> actualAttributes = getActualAttributes();
String trustStorePath = (String) getAttribute(TRUST_STORE_PATH);
if (trustStorePath != null)
{
@@ -232,13 +267,22 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
trsustStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
trsustStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
TrustStoreAdapter trustStore = new TrustStoreAdapter(_defaultTrustStoreId, this, trsustStoreAttributes);
- addTrustStore(trustStore);
+ _trustStores.put(trustStore.getId(), trustStore);
+ }
+ else
+ {
+ _trustStores.remove(_defaultTrustStoreId);
}
+ }
+
+ private void createPeerStore()
+ {
+ Map<String, Object> actualAttributes = getActualAttributes();
String peerStorePath = (String) getAttribute(PEER_STORE_PATH);
+ UUID peerStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_PEER_STORE_NAME);
if (peerStorePath != null)
{
Map<String, Object> peerStoreAttributes = new HashMap<String, Object>();
- UUID peerStoreId = UUID.randomUUID();
peerStoreAttributes.put(TrustStore.NAME, peerStoreId.toString());
peerStoreAttributes.put(TrustStore.PATH, peerStorePath);
peerStoreAttributes.put(TrustStore.PEERS_ONLY, Boolean.TRUE);
@@ -246,7 +290,11 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
peerStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
peerStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
TrustStoreAdapter trustStore = new TrustStoreAdapter(peerStoreId, this, peerStoreAttributes);
- addTrustStore(trustStore);
+ _trustStores.put(trustStore.getId(), trustStore);
+ }
+ else
+ {
+ _trustStores.remove(peerStoreId);
}
}
@@ -276,7 +324,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
}
- public AuthenticationProvider getAuthenticationProviderByName(String authenticationProviderName)
+ public AuthenticationProvider findAuthenticationProviderByName(String authenticationProviderName)
{
Collection<AuthenticationProvider> providers = getAuthenticationProviders();
for (AuthenticationProvider authenticationProvider : providers)
@@ -483,40 +531,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
AuthenticationProvider authenticationProvider = null;
synchronized (_authenticationProviders)
{
- String type = (String)attributes.get(AuthenticationProvider.TYPE);
- if (type == null)
- {
- throw new IllegalConfigurationException("Authentication provider type is not specified");
- }
-
- // a temporary restriction to prevent creation of several instances
- // of PlainPasswordFileAuthenticationProvider/Base64MD5PasswordFileAuthenticationProvider
- // due to current limitation of JMX management which cannot cope
- // with several user management MBeans as MBean type is used as a name.
-
- // TODO: Remove this check after fixing of JMX management
- if (type.equals(PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE)
- || type.equals(Base64MD5PasswordFileAuthenticationManagerFactory.PROVIDER_TYPE))
- {
-
- for (AuthenticationProvider provider : _authenticationProviders.values())
- {
- String providerType = (String) provider.getAttribute(AuthenticationProvider.TYPE);
- if (providerType.equals(PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE)
- || providerType.equals(Base64MD5PasswordFileAuthenticationManagerFactory.PROVIDER_TYPE))
- {
- throw new IllegalConfigurationException("An authentication provider which can manage users alredy exists ["
- + provider.getName() + "]. Only one instance is allowed.");
- }
- }
-
- }
-
- // it's cheap to create the groupPrincipalAccessor on the fly
- GroupPrincipalAccessor groupPrincipalAccessor = new GroupPrincipalAccessor(_groupProviders.values());
-
- authenticationProvider = _authenticationProviderFactory.create(UUID.randomUUID(), this, attributes,
- groupPrincipalAccessor);
+ authenticationProvider = _authenticationProviderFactory.create(UUID.randomUUID(), this, attributes);
addAuthenticationProvider(authenticationProvider);
}
authenticationProvider.setDesiredState(State.INITIALISING, State.ACTIVE);
@@ -674,17 +689,29 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
return _authenticationProviderFactory.getSupportedAuthenticationProviders();
}
- else if (DEFAULT_AUTHENTICATION_PROVIDER.equals(name))
+ else if (KEY_STORE_PASSWORD.equals(name) || TRUST_STORE_PASSWORD.equals(name) || PEER_STORE_PASSWORD.equals(name))
+ {
+ if (getActualAttributes().get(name) != null)
+ {
+ return DUMMY_PASSWORD_MASK;
+ }
+ return null;
+ }
+ else if (MANAGEMENT_VERSION.equals(name))
+ {
+ return Model.MANAGEMENT_API_MAJOR_VERSION + "." + Model.MANAGEMENT_API_MINOR_VERSION;
+ }
+ else if (STORE_VERSION.equals(name))
{
- return _defaultAuthenticationProvider == null ? null : _defaultAuthenticationProvider.getName();
+ return _brokerStore.getVersion();
}
- else if (KEY_STORE_PASSWORD.equals(name))
+ else if (STORE_TYPE.equals(name))
{
- return DUMMY_PASSWORD_MASK;
+ return _brokerStore.getType();
}
- else if (TRUST_STORE_PASSWORD.equals(name))
+ else if (STORE_PATH.equals(name))
{
- return DUMMY_PASSWORD_MASK;
+ return _brokerStore.getStoreLocation();
}
return super.getAttribute(name);
}
@@ -990,6 +1017,173 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
@Override
protected void changeAttributes(Map<String, Object> attributes)
{
- super.changeAttributes(MapValueConverter.convert(attributes, ATTRIBUTE_TYPES));
+ //TODO: Add ACL check
+ //TODO: Add management mode check
+ Map<String, Object> convertedAttributes = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ validateAttributes(convertedAttributes);
+
+ boolean keyStoreChanged = false;
+ boolean trustStoreChanged = false;
+ boolean peerStoreChanged = false;
+ Collection<String> names = AVAILABLE_ATTRIBUTES;
+ for (String name : names)
+ {
+ if (attributes.containsKey(name))
+ {
+ Object desired = attributes.get(name);
+ Object expected = getAttribute(name);
+ if (changeAttribute(name, expected, desired))
+ {
+ if (GROUP_FILE.equals(name))
+ {
+ createGroupProvider();
+ }
+ else if (DEFAULT_AUTHENTICATION_PROVIDER.equals(name))
+ {
+ if (!_defaultAuthenticationProvider.getName().equals(desired))
+ {
+ _defaultAuthenticationProvider = findAuthenticationProviderByName((String)desired);
+ }
+ }
+ else if (KEY_STORE_PATH.equals(name) || KEY_STORE_PASSWORD.equals(name) || KEY_STORE_CERT_ALIAS.equals(name))
+ {
+ keyStoreChanged = true;
+ }
+ else if (TRUST_STORE_PATH.equals(name) || TRUST_STORE_PASSWORD.equals(name))
+ {
+ trustStoreChanged = true;
+ }
+ else if (PEER_STORE_PATH.equals(name) || PEER_STORE_PASSWORD.equals(name))
+ {
+ peerStoreChanged = true;
+ }
+ attributeSet(name, expected, desired);
+ }
+ }
+ }
+
+ // the calls below are not thread safe but they should be fine in a management mode
+ // as there will be no user connected
+ // The new keystore/trustore/peerstore will be only used with new ports
+ // At the moment we cannot restart ports with new keystore/trustore/peerstore
+
+ if (keyStoreChanged)
+ {
+ createKeyStore();
+ }
+ if (trustStoreChanged)
+ {
+ createTrustStore();
+ }
+ if (peerStoreChanged)
+ {
+ createPeerStore();
+ }
+ }
+
+ private void validateAttributes(Map<String, Object> convertedAttributes)
+ {
+ String aclFile = (String) convertedAttributes.get(ACL_FILE);
+ if (aclFile != null)
+ {
+ // create a security manager to validate the ACL specified in file
+ new SecurityManager(aclFile);
+ }
+ String groupFile = (String) convertedAttributes.get(GROUP_FILE);
+ if (groupFile != null)
+ {
+ // create a group manager to validate the groups specified in file
+ new FileGroupManager(groupFile);
+ }
+ validateKeyStoreAttributes(convertedAttributes, "key store", KEY_STORE_PATH, KEY_STORE_PASSWORD, KEY_STORE_CERT_ALIAS);
+ validateKeyStoreAttributes(convertedAttributes, "trust store", TRUST_STORE_PATH, TRUST_STORE_PASSWORD, null);
+ validateKeyStoreAttributes(convertedAttributes, "peer store", PEER_STORE_PATH, PEER_STORE_PASSWORD, null);
+ String defaultAuthenticationProvider = (String) convertedAttributes.get(DEFAULT_AUTHENTICATION_PROVIDER);
+ if (defaultAuthenticationProvider != null)
+ {
+ AuthenticationProvider provider = findAuthenticationProviderByName(defaultAuthenticationProvider);
+ if (provider == null)
+ {
+ throw new IllegalConfigurationException("Authentication provider with name " + defaultAuthenticationProvider
+ + " canot be set as a default as it does not exist");
+ }
+ }
+ String defaultVirtualHost = (String) convertedAttributes.get(DEFAULT_VIRTUAL_HOST);
+ if (defaultVirtualHost != null)
+ {
+ VirtualHost foundHost = findVirtualHostByName(defaultVirtualHost);
+ if (foundHost == null)
+ {
+ throw new IllegalConfigurationException("Virtual host with name " + defaultVirtualHost
+ + " cannot be set as a default as it does not exist");
+ }
+ }
+ Long queueFlowControlSize = (Long) convertedAttributes.get(FLOW_CONTROL_SIZE_BYTES);
+ if (queueFlowControlSize != null && queueFlowControlSize > 0)
+ {
+ Long queueFlowControlResumeSize = (Long) convertedAttributes.get(FLOW_CONTROL_RESUME_SIZE_BYTES);
+ if (queueFlowControlResumeSize == null)
+ {
+ throw new IllegalConfigurationException("Flow control resume size attribute is not specified with flow control size attribute");
+ }
+ if (queueFlowControlResumeSize >= queueFlowControlSize)
+ {
+ throw new IllegalConfigurationException("Flow control resume size should be less then flow control size");
+ }
+ }
+ for (String attributeName : POSITIVE_NUMERIC_ATTRIBUTES)
+ {
+ Number value = (Number) convertedAttributes.get(attributeName);
+ if (value != null && value.longValue() < 0)
+ {
+ throw new IllegalConfigurationException("Only positive integer value can be specified for the attribute "
+ + attributeName);
+ }
+ }
+ }
+
+ private void validateKeyStoreAttributes(Map<String, Object> convertedAttributes, String type, String pathAttribute,
+ String passwordAttribute, String aliasAttribute)
+ {
+ String keyStoreFile = (String) convertedAttributes.get(pathAttribute);
+ if (keyStoreFile != null)
+ {
+ String password = (String) convertedAttributes.get(passwordAttribute);
+ if (password == null)
+ {
+ password = (String) getActualAttributes().get(passwordAttribute);
+ }
+ java.security.KeyStore keyStore = null;
+ try
+ {
+ keyStore = SSLUtil.getInitializedKeyStore(keyStoreFile, password, java.security.KeyStore.getDefaultType());
+ }
+ catch (Exception e)
+ {
+ throw new IllegalConfigurationException("Cannot instantiate " + type + " at " + keyStoreFile, e);
+ }
+ if (aliasAttribute != null)
+ {
+ String alias = (String) convertedAttributes.get(aliasAttribute);
+ if (alias != null)
+ {
+ Certificate cert = null;
+ try
+ {
+ cert = keyStore.getCertificate(alias);
+ }
+ catch (KeyStoreException e)
+ {
+ // key store should be initialized above
+ throw new RuntimeException("Key store has not been initialized", e);
+ }
+ if (cert == null)
+ {
+ throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias + "in " + type
+ + " : " + keyStoreFile);
+ }
+ }
+ }
+ }
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
index d1b1373dcf..01eb41fd36 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
@@ -716,15 +716,18 @@ class Subscription_1_0 implements Subscription
getEndpoint().detach();
}
- public synchronized boolean wouldSuspend(final QueueEntry msg)
+ public boolean wouldSuspend(final QueueEntry msg)
{
- final boolean hasCredit = _link.isAttached() && getEndpoint().hasCreditToSend();
- if(!hasCredit && getState() == State.ACTIVE)
+ synchronized (_link.getLock())
{
- suspend();
- }
+ final boolean hasCredit = _link.isAttached() && getEndpoint().hasCreditToSend();
+ if(!hasCredit && getState() == State.ACTIVE)
+ {
+ suspend();
+ }
- return !hasCredit;
+ return !hasCredit;
+ }
}
public boolean trySendLock()
@@ -732,11 +735,14 @@ class Subscription_1_0 implements Subscription
return _stateChangeLock.tryLock();
}
- public synchronized void suspend()
+ public void suspend()
{
- if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ synchronized(_link.getLock())
{
- _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
}
}
@@ -807,26 +813,32 @@ class Subscription_1_0 implements Subscription
return false; //TODO
}
- public synchronized void queueEmpty()
+ public void queueEmpty()
{
- if(_link.drained())
+ synchronized(_link.getLock())
{
- if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ if(_link.drained())
{
- _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
}
}
}
- public synchronized void flowStateChanged()
+ public void flowStateChanged()
{
- if(isSuspended() && getEndpoint() != null)
+ synchronized(_link.getLock())
{
- if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
+ if(isSuspended() && getEndpoint() != null)
{
- _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE);
+ if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
+ {
+ _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE);
+ }
+ _transactionId = _link.getTransactionId();
}
- _transactionId = _link.getTransactionId();
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index 1a1cce171b..9ef1ae1a3a 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -23,6 +23,10 @@ import org.apache.log4j.Logger;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.State;
import org.apache.qpid.server.plugin.AccessControlFactory;
import org.apache.qpid.server.plugin.QpidServiceLoader;
import org.apache.qpid.server.queue.AMQQueue;
@@ -46,9 +50,11 @@ import static org.apache.qpid.server.security.access.Operation.UNBIND;
import javax.security.auth.Subject;
import java.net.SocketAddress;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
@@ -60,7 +66,7 @@ import java.util.concurrent.ConcurrentHashMap;
*
* @see AccessControl
*/
-public class SecurityManager
+public class SecurityManager implements ConfigurationChangeListener
{
private static final Logger _logger = Logger.getLogger(SecurityManager.class);
@@ -69,8 +75,9 @@ public class SecurityManager
public static final ThreadLocal<Boolean> _accessChecksDisabled = new ClearingThreadLocal(false);
- private Map<String, AccessControl> _globalPlugins = new HashMap<String, AccessControl>();
- private Map<String, AccessControl> _hostPlugins = new HashMap<String, AccessControl>();
+ private Map<String, AccessControl> _globalPlugins = new ConcurrentHashMap<String, AccessControl>();
+ private Map<String, AccessControl> _hostPlugins = new ConcurrentHashMap<String, AccessControl>();
+ private Map<String, List<String>> _aclConfigurationToPluginNamesMapping = new ConcurrentHashMap<String, List<String>>();
/**
* A special ThreadLocal, which calls remove() on itself whenever the value is
@@ -130,14 +137,22 @@ public class SecurityManager
public SecurityManager(String aclFile)
{
+ configureACLPlugin(aclFile);
+ }
+
+ private void configureACLPlugin(String aclFile)
+ {
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("aclFile", aclFile);
+
for (AccessControlFactory provider : (new QpidServiceLoader<AccessControlFactory>()).instancesOf(AccessControlFactory.class))
{
AccessControl accessControl = provider.createInstance(attributes);
if(accessControl != null)
{
addHostPlugin(accessControl);
+
+ mapAclConfigurationToPluginName(aclFile, accessControl.getClass().getName());
}
}
@@ -147,6 +162,17 @@ public class SecurityManager
}
}
+ private void mapAclConfigurationToPluginName(String aclFile, String pluginName)
+ {
+ List<String> pluginNames = _aclConfigurationToPluginNamesMapping.get(aclFile);
+ if (pluginNames == null)
+ {
+ pluginNames = new ArrayList<String>();
+ _aclConfigurationToPluginNamesMapping.put(aclFile, pluginNames);
+ }
+ pluginNames.add(pluginName);
+ }
+
public static Subject getThreadSubject()
{
return _subject.get();
@@ -477,4 +503,50 @@ public class SecurityManager
_hostPlugins.put(plugin.getClass().getName(), plugin);
}
+ @Override
+ public void stateChanged(ConfiguredObject object, State oldState, State newState)
+ {
+ // no op
+ }
+
+ @Override
+ public void childAdded(ConfiguredObject object, ConfiguredObject child)
+ {
+ // no op
+ }
+
+ @Override
+ public void childRemoved(ConfiguredObject object, ConfiguredObject child)
+ {
+ // no op
+ }
+
+ @Override
+ public void attributeSet(ConfiguredObject object, String attributeName, Object oldAttributeValue, Object newAttributeValue)
+ {
+ if (object instanceof Broker && Broker.ACL_FILE.equals(attributeName))
+ {
+ // the code below is not thread safe, however, it should be fine in a management mode
+ // as there will be no user connected
+
+ if (oldAttributeValue != null)
+ {
+ List<String> pluginNames = _aclConfigurationToPluginNamesMapping.remove(oldAttributeValue);
+ if (pluginNames != null)
+ {
+ for (String name : pluginNames)
+ {
+ _hostPlugins.remove(name);
+ }
+ }
+ }
+ if (newAttributeValue != null)
+ {
+ configureACLPlugin((String)newAttributeValue);
+ }
+ _immediatePublishPropsCache.clear();
+ _publishPropsCache.clear();
+ }
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
index 578bb96efa..81f26a3e2f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
@@ -65,19 +65,17 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr
}
}
- public final void setPasswordFile(String passwordFile) throws IOException
+ public final void open(File passwordFile) throws IOException
{
- File f = new File(passwordFile);
- getLogger().info("PasswordFile using file " + f.getAbsolutePath());
- _passwordFile = f;
- if (!f.exists())
+ getLogger().info("PasswordFile using file " + passwordFile.getAbsolutePath());
+ _passwordFile = passwordFile;
+ if (!passwordFile.exists())
{
- throw new FileNotFoundException("Cannot find password file " + f);
+ throw new FileNotFoundException("Cannot find password file " + passwordFile);
}
- if (!f.canRead())
+ if (!passwordFile.canRead())
{
- throw new FileNotFoundException("Cannot read password file " + f +
- ". Check permissions.");
+ throw new FileNotFoundException("Cannot read password file " + passwordFile + ". Check permissions.");
}
loadPasswordFile();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
index 605d2d019d..df770e84f8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
@@ -24,6 +24,8 @@ import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialis
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
+
+import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.List;
@@ -32,7 +34,7 @@ import java.util.Map;
/** Represents a "user database" which is really a way of storing principals (i.e. usernames) and passwords. */
public interface PrincipalDatabase
{
- void setPasswordFile(String passwordFile) throws IOException;
+ void open(File passwordFile) throws IOException;
/**
* Set the password for a given principal in the specified callback. This is used for certain SASL providers. The
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractPrincipalDatabaseAuthManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractPrincipalDatabaseAuthManagerFactory.java
index 2cf8c4619a..5d427c4afb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractPrincipalDatabaseAuthManagerFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractPrincipalDatabaseAuthManagerFactory.java
@@ -19,7 +19,6 @@
*/
package org.apache.qpid.server.security.auth.manager;
-import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -62,16 +61,7 @@ public abstract class AbstractPrincipalDatabaseAuthManagerFactory implements Aut
}
PrincipalDatabase principalDatabase = createPrincipalDatabase();
- try
- {
- principalDatabase.setPasswordFile(passwordFile);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e.getMessage(), e);
- }
-
- return new PrincipalDatabaseAuthenticationManager(principalDatabase);
+ return new PrincipalDatabaseAuthenticationManager(principalDatabase, passwordFile);
}
abstract PrincipalDatabase createPrincipalDatabase();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
index dd4c2e717a..ae3bc5131f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
@@ -113,4 +113,16 @@ public class AnonymousAuthenticationManager implements AuthenticationManager
public void close()
{
}
+
+ @Override
+ public void onCreate()
+ {
+ // nothing to do, no external resource is required
+ }
+
+ @Override
+ public void onDelete()
+ {
+ // nothing to do, no external resource is used
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
index c1a694f148..1576a73a82 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
@@ -88,4 +88,14 @@ public interface AuthenticationManager extends Closeable
* @return authentication result
*/
AuthenticationResult authenticate(String username, String password);
+
+ /**
+ * Called after manager creation to create the required resources, for example, user databases etc.
+ */
+ void onCreate();
+
+ /**
+ * Called before manager deletion to release and clean the resources created in {@link #onCreate()}.
+ */
+ void onDelete();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
index 9ed8cf7fed..43e0a9f64f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
@@ -96,4 +96,16 @@ public class ExternalAuthenticationManager implements AuthenticationManager
public void close()
{
}
+
+ @Override
+ public void onCreate()
+ {
+ // nothing to do, no external resource is required
+ }
+
+ @Override
+ public void onDelete()
+ {
+ // nothing to do, no external resource is used
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
index 3c1b709648..6bbf3ca6f5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
@@ -109,6 +109,18 @@ public class KerberosAuthenticationManager implements AuthenticationManager
{
}
+ @Override
+ public void onCreate()
+ {
+ // nothing to do, no external resource is required
+ }
+
+ @Override
+ public void onDelete()
+ {
+ // nothing to do, no external resource is used
+ }
+
private static class GssApiCallbackHandler implements CallbackHandler
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
index f4c834810d..9647499783 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
@@ -20,9 +20,12 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import java.io.File;
+import java.io.IOException;
import java.security.Principal;
import org.apache.log4j.Logger;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
@@ -66,10 +69,12 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
private final Map<String, Map<String, ?>> _serverCreationProperties = new HashMap<String, Map<String, ?>>();
private final PrincipalDatabase _principalDatabase;
+ private final String _passwordFile;
- public PrincipalDatabaseAuthenticationManager(PrincipalDatabase pd)
+ public PrincipalDatabaseAuthenticationManager(PrincipalDatabase pd, String passwordFile)
{
_principalDatabase = pd;
+ _passwordFile = passwordFile;
}
public void initialise()
@@ -204,4 +209,37 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
{
return _principalDatabase;
}
+
+ @Override
+ public void onCreate()
+ {
+ try
+ {
+ File passwordFile = new File(_passwordFile);
+ if (!passwordFile.exists())
+ {
+ passwordFile.createNewFile();
+ }
+ else if (!passwordFile.canRead())
+ {
+ throw new IllegalConfigurationException("Cannot read password file" + _passwordFile + ". Check permissions.");
+ }
+
+ _principalDatabase.open(passwordFile);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalConfigurationException("Cannot use password database at :" + _passwordFile, e);
+ }
+ }
+
+ @Override
+ public void onDelete()
+ {
+ File file = new File(_passwordFile);
+ if (file.exists() && file.isFile())
+ {
+ file.delete();
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
index 7891ef8cf5..ee00e9850d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
@@ -306,4 +306,16 @@ public class SimpleLDAPAuthenticationManager implements AuthenticationManager
}
}
+
+ @Override
+ public void onCreate()
+ {
+ // nothing to do, no external resource is required
+ }
+
+ @Override
+ public void onDelete()
+ {
+ // nothing to do, no external resource is used
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java
index 4e12ac0750..8467dad60a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java
@@ -27,6 +27,8 @@ import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.sasl.SaslServerFactory;
+
+import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.List;
@@ -141,7 +143,7 @@ public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser
}
@Override
- public void setPasswordFile(String passwordFile) throws IOException
+ public void open(File passwordFile) throws IOException
{
throw new UnsupportedOperationException();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java
index d549b76aab..1b8cdc91bc 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java
@@ -25,8 +25,6 @@ import java.util.HashSet;
import java.util.Set;
import org.apache.qpid.server.model.GroupProvider;
-import org.apache.qpid.server.model.adapter.GroupProviderAdapter;
-
public class GroupPrincipalAccessor
{
diff --git a/qpid/java/broker/src/main/resources/initial-store.json b/qpid/java/broker/src/main/resources/initial-store.json
index 9fe72b3601..7e73772d6d 100644
--- a/qpid/java/broker/src/main/resources/initial-store.json
+++ b/qpid/java/broker/src/main/resources/initial-store.json
@@ -20,6 +20,7 @@
*/
{
"name": "QpidBroker",
+ "storeVersion": 1,
"defaultAuthenticationProvider" : "passwordFile",
"defaultVirtualHost" : "default",
"authenticationproviders" : [ {
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java
index 8e0bfdaeb7..79dcf0cac4 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java
@@ -53,7 +53,6 @@ import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.model.adapter.AuthenticationProviderFactory;
import org.apache.qpid.server.model.adapter.PortFactory;
import org.apache.qpid.server.configuration.updater.TaskExecutor;
-import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
@@ -300,9 +299,6 @@ public class BrokerRecovererTest extends TestCase
assertNotNull(broker);
assertEquals("Unexpected number of authentication providers", 2, broker.getAuthenticationProviders().size());
- //verify that a GroupAcessor was added to the AuthenticationProviders
- verify(_authenticationProvider1).setGroupAccessor(any(GroupPrincipalAccessor.class));
- verify(authenticationProvider2).setGroupAccessor(any(GroupPrincipalAccessor.class));
}
public void testCreateBrokerWithGroupProvider()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
index b357c0b8e9..9d7f6a9cc1 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
@@ -110,7 +110,10 @@ public abstract class ConfigurationEntryStoreTestCase extends QpidTestCase
assertEquals("Unexpected type ", Broker.class.getSimpleName(), brokerConfigEntry.getType());
Map<String, Object> attributes = brokerConfigEntry.getAttributes();
assertNotNull("Attributes cannot be null", attributes);
- assertEquals("Unexpected attributes", _brokerAttributes, attributes);
+ for (Map.Entry<String, Object> attribute : _brokerAttributes.entrySet())
+ {
+ assertEquals("Unexpected attribute " + attribute.getKey(), attribute.getValue(), attributes.get(attribute.getKey()));
+ }
}
public void testGetEntry()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java
index 92e304ab86..1cb760f611 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java
@@ -52,6 +52,7 @@ public class JsonConfigurationEntryStoreTest extends ConfigurationEntryStoreTest
Map<String, Object> brokerObjectMap = new HashMap<String, Object>();
brokerObjectMap.put(Broker.ID, brokerId);
brokerObjectMap.put("@type", Broker.class.getSimpleName());
+ brokerObjectMap.put("storeVersion", 1);
brokerObjectMap.putAll(brokerAttributes);
StringWriter sw = new StringWriter();
@@ -114,8 +115,9 @@ public class JsonConfigurationEntryStoreTest extends ConfigurationEntryStoreTest
assertEquals("Unexpected root entry", brokerId, root.getId());
Map<String, Object> attributes = root.getAttributes();
assertNotNull("Attributes not found", attributes);
- assertEquals("Unexpected number of attriburtes", 1, attributes.size());
+ assertEquals("Unexpected number of attriburtes", 2, attributes.size());
assertEquals("Unexpected name attribute", getTestName(), attributes.get(Broker.NAME));
+ assertEquals("Unexpected version attribute", 1, attributes.get(Broker.STORE_VERSION));
}
public void testCreateFromInitialStore() throws Exception
@@ -135,8 +137,18 @@ public class JsonConfigurationEntryStoreTest extends ConfigurationEntryStoreTest
assertEquals("Unexpected root entry", brokerId, root.getId());
Map<String, Object> attributes = root.getAttributes();
assertNotNull("Attributes not found", attributes);
- assertEquals("Unexpected number of attriburtes", 1, attributes.size());
+ assertEquals("Unexpected number of attriburtes", 2, attributes.size());
assertEquals("Unexpected name attribute", getTestName(), attributes.get(Broker.NAME));
+ assertEquals("Unexpected version attribute", 1, attributes.get(Broker.STORE_VERSION));
}
+ public void testGetVersion()
+ {
+ assertEquals("Unexpected version", 1, getStore().getVersion());
+ }
+
+ public void testGetType()
+ {
+ assertEquals("Unexpected type", "json", getStore().getType());
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java
index 65ced69915..314e673c08 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java
@@ -94,4 +94,14 @@ public class MemoryConfigurationEntryStoreTest extends ConfigurationEntryStoreTe
assertEquals("Unexpected broker attributes", initialStoreRoot.getAttributes(), root.getAttributes());
assertEquals("Unexpected broker children", initialStoreRoot.getChildrenIds(), root.getChildrenIds());
}
+
+ public void testGetVersion()
+ {
+ assertEquals("Unexpected version", 1, getStore().getVersion());
+ }
+
+ public void testGetType()
+ {
+ assertEquals("Unexpected type", "memory", getStore().getType());
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactoryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactoryTest.java
index 585fecae83..eb721d93a0 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactoryTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/AuthenticationProviderFactoryTest.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.model.adapter;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
import java.util.Collections;
import java.util.HashMap;
@@ -30,7 +31,7 @@ import java.util.UUID;
import junit.framework.TestCase;
-import org.apache.qpid.server.configuration.ConfigurationEntry;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
@@ -64,9 +65,7 @@ public class AuthenticationProviderFactoryTest extends TestCase
QpidServiceLoader<AuthenticationManagerFactory> authManagerFactoryServiceLoader = mock(QpidServiceLoader.class);
AuthenticationManagerFactory authenticationManagerFactory = mock(AuthenticationManagerFactory.class);
- ConfigurationEntry configurationEntry = mock(ConfigurationEntry.class);
- when(configurationEntry.getId()).thenReturn(id);
Broker broker = mock(Broker.class);
when(authManagerFactoryServiceLoader.atLeastOneInstanceOf(AuthenticationManagerFactory.class)).thenReturn(
@@ -74,7 +73,7 @@ public class AuthenticationProviderFactoryTest extends TestCase
when(authenticationManagerFactory.createInstance(attributes)).thenReturn(authenticationManager);
AuthenticationProviderFactory providerFactory = new AuthenticationProviderFactory(authManagerFactoryServiceLoader);
- AuthenticationProvider provider = providerFactory.create(id, broker, attributes, null);
+ AuthenticationProvider provider = providerFactory.create(id, broker, attributes);
assertNotNull("Provider is not created", provider);
assertEquals("Unexpected ID", id, provider.getId());
@@ -82,4 +81,47 @@ public class AuthenticationProviderFactoryTest extends TestCase
return provider;
}
+ @SuppressWarnings("unchecked")
+ public void testCreatePasswordCredentialManagingAuthenticationProviderFailsWhenAnotherOneAlreadyExist()
+ {
+ Broker broker = mock(Broker.class);
+ PasswordCredentialManagingAuthenticationProvider anotherProvider = mock(PasswordCredentialManagingAuthenticationProvider.class);
+ when(broker.getAuthenticationProviders()).thenReturn(Collections.<AuthenticationProvider>singleton(anotherProvider));
+
+ QpidServiceLoader<AuthenticationManagerFactory> loader = mock(QpidServiceLoader.class);
+ AuthenticationManagerFactory managerFactory = mock(AuthenticationManagerFactory.class);
+ when(managerFactory.createInstance(any(Map.class))).thenReturn(mock(PrincipalDatabaseAuthenticationManager.class));
+ when(loader.atLeastOneInstanceOf(AuthenticationManagerFactory.class)).thenReturn(Collections.singleton(managerFactory));
+
+ AuthenticationProviderFactory providerFactory = new AuthenticationProviderFactory(loader);
+ try
+ {
+ providerFactory.create(UUID.randomUUID(), broker, new HashMap<String, Object>());
+ fail("Creation of anaother PasswordCredentialManagingAuthenticationProvider should fail");
+ }
+ catch (IllegalConfigurationException e)
+ {
+ // pass
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testCreateNonPasswordCredentialManagingAuthenticationProviderWhenAnotherOneAlreadyExist()
+ {
+ Broker broker = mock(Broker.class);
+ AuthenticationProvider anotherProvider = mock(AuthenticationProvider.class);
+ when(broker.getAuthenticationProviders()).thenReturn(Collections.singleton(anotherProvider));
+
+ QpidServiceLoader<AuthenticationManagerFactory> loader = mock(QpidServiceLoader.class);
+ AuthenticationManagerFactory managerFactory = mock(AuthenticationManagerFactory.class);
+ when(managerFactory.createInstance(any(Map.class))).thenReturn(mock(AuthenticationManager.class));
+ when(loader.atLeastOneInstanceOf(AuthenticationManagerFactory.class)).thenReturn(Collections.singleton(managerFactory));
+
+ AuthenticationProviderFactory providerFactory = new AuthenticationProviderFactory(loader);
+ UUID id = UUID.randomUUID();
+ AuthenticationProvider provider = providerFactory.create(id, broker, new HashMap<String, Object>());
+
+ assertNotNull("Provider is not created", provider);
+ assertEquals("Unexpected ID", id, provider.getId());
+ }
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
index 7b244e219e..4102a1fc68 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
@@ -84,7 +84,7 @@ public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
_database = new Base64MD5PasswordFilePrincipalDatabase();
_pwdFile = File.createTempFile(this.getClass().getName(), "pwd");
_pwdFile.deleteOnExit();
- _database.setPasswordFile(_pwdFile.getAbsolutePath());
+ _database.open(_pwdFile);
_testPwdFiles.clear();
}
@@ -153,7 +153,7 @@ public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
{
try
{
- _database.setPasswordFile(file.toString());
+ _database.open(file);
}
catch (IOException e)
{
@@ -392,7 +392,7 @@ public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
{
try
{
- _database.setPasswordFile("DoesntExist");
+ _database.open(new File("DoesntExist"));
}
catch (FileNotFoundException fnfe)
{
@@ -414,7 +414,7 @@ public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
try
{
- _database.setPasswordFile(testFile.toString());
+ _database.open(testFile);
}
catch (FileNotFoundException fnfe)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
index 8e62324f7d..eecbcdf38d 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
@@ -284,7 +284,7 @@ public class PlainPasswordFilePrincipalDatabaseTest extends TestCase
{
try
{
- _database.setPasswordFile("DoesntExist");
+ _database.open(new File("DoesntExist"));
}
catch (FileNotFoundException fnfe)
{
@@ -306,7 +306,7 @@ public class PlainPasswordFilePrincipalDatabaseTest extends TestCase
try
{
- _database.setPasswordFile(testFile.toString());
+ _database.open(testFile);
}
catch (FileNotFoundException fnfe)
{
@@ -403,7 +403,7 @@ public class PlainPasswordFilePrincipalDatabaseTest extends TestCase
{
try
{
- _database.setPasswordFile(file.toString());
+ _database.open(file);
}
catch (IOException e)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
index f670d80ae8..c41b9bf081 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
@@ -27,6 +27,8 @@ import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
+
+import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
@@ -151,7 +153,7 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase
}
@Override
- public void setPasswordFile(String passwordFile)
+ public void open(File passwordFile)
{
throw new UnsupportedOperationException();
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
index 1ae667804a..8025907e41 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
@@ -24,6 +24,7 @@ import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHel
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.io.File;
import java.security.Provider;
import java.security.Security;
import java.util.Collections;
@@ -54,13 +55,29 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase
private AuthenticationManager _manager = null; // Class under test
private PrincipalDatabase _principalDatabase;
+ private String _passwordFileLocation;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _passwordFileLocation = TMP_FOLDER + File.separator + PrincipalDatabaseAuthenticationManagerTest.class.getSimpleName() + "-" + getName();
+ deletePasswordFileIfExists();
+ }
@Override
public void tearDown() throws Exception
{
- if (_manager != null)
+ try
+ {
+ if (_manager != null)
+ {
+ _manager.close();
+ }
+ }
+ finally
{
- _manager.close();
+ deletePasswordFileIfExists();
}
super.tearDown();
}
@@ -74,7 +91,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase
when(_principalDatabase.getMechanisms()).thenReturn(_initialisers);
- _manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase);
+ _manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase, _passwordFileLocation);
_manager.initialise();
}
@@ -104,7 +121,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase
usernamePasswordInitialiser.initialise(_principalDatabase);
- _manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase);
+ _manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase, null);
_manager.initialise();
}
@@ -232,6 +249,34 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase
_manager = null;
}
+ public void testOnCreate() throws Exception
+ {
+ setupMocks();
+
+ _manager.onCreate();
+ assertTrue("Password file was not created", new File(_passwordFileLocation).exists());
+ }
+
+ public void testOnDelete() throws Exception
+ {
+ setupMocks();
+
+ _manager.onCreate();
+ assertTrue("Password file was not created", new File(_passwordFileLocation).exists());
+
+ _manager.onDelete();
+ assertFalse("Password file was not deleted", new File(_passwordFileLocation).exists());
+ }
+
+ private void deletePasswordFileIfExists()
+ {
+ File passwordFile = new File(_passwordFileLocation);
+ if (passwordFile.exists())
+ {
+ passwordFile.delete();
+ }
+ }
+
/**
* Test SASL implementation used to test the authenticate() method.
*/
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexServerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexServerTest.java
index 51c2a0a5b8..629e1b4cf5 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexServerTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexServerTest.java
@@ -186,7 +186,7 @@ public class CRAMMD5HexServerTest extends TestCase
Base64MD5PasswordFilePrincipalDatabase db = new Base64MD5PasswordFilePrincipalDatabase();
File file = File.createTempFile("passwd", "db");
file.deleteOnExit();
- db.setPasswordFile(file.getCanonicalPath());
+ db.open(file);
db.createPrincipal( createTestPrincipal("knownuser"), "guest".toCharArray());
db.createPrincipal( createTestPrincipal("qpid3158user"), "guest2".toCharArray());
return db;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
index f94d8ddfc3..5e66bc9336 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
@@ -25,6 +25,8 @@ import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
+
+import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.List;
@@ -87,7 +89,7 @@ public class TestPrincipalDatabase implements PrincipalDatabase
}
@Override
- public void setPasswordFile(String passwordFile) throws IOException
+ public void open(File passwordFile) throws IOException
{
// TODO Auto-generated method stub
}
diff --git a/qpid/java/client/src/main/java/client.bnd b/qpid/java/client/src/main/java/client.bnd
index 0a47b30c72..1d78bee554 100755
--- a/qpid/java/client/src/main/java/client.bnd
+++ b/qpid/java/client/src/main/java/client.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.21.0
+ver: 0.23.0
Bundle-SymbolicName: qpid-client
Bundle-Version: ${ver}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
index 6ca2988186..fc7762e77d 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -653,6 +653,17 @@ public abstract class AMQDestination implements Destination, Referenceable
{
return false;
}
+ if (_subject == null)
+ {
+ if (that.getSubject() != null)
+ {
+ return false;
+ }
+ }
+ else if (!_subject.equals(that.getSubject()))
+ {
+ return false;
+ }
}
else
{
@@ -679,6 +690,10 @@ public abstract class AMQDestination implements Destination, Referenceable
if (_destSyntax == DestSyntax.ADDR)
{
result = 29 * _addressType + _name.hashCode();
+ if (_subject != null)
+ {
+ result = 29 * result + _subject.hashCode();
+ }
}
else
{
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
index 1a411c99bc..e034fa5b3f 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java
@@ -27,10 +27,10 @@ public class AMQDestinationTest extends TestCase
public void testEqaulsAndHashCodeForAddressBasedDestinations() throws Exception
{
AMQDestination dest = new AMQQueue("ADDR:Foo; {node :{type:queue}}");
- AMQDestination dest1 = new AMQQueue("ADDR:Foo; {node :{type:topic}}");
+ AMQDestination dest1 = new AMQTopic("ADDR:Foo; {node :{type:topic}}");
AMQDestination dest2 = new AMQQueue(
"ADDR:Foo; {create:always,node :{type:queue}}");
- String bUrl = "direct://amq.direct/test-route/Foo?routingkey='Foo'";
+ String bUrl = "BURL:direct://amq.direct/test-route/Foo?routingkey='Foo'";
AMQDestination dest3 = new AMQQueue(bUrl);
assertTrue(dest.equals(dest));
@@ -42,5 +42,9 @@ public class AMQDestinationTest extends TestCase
assertTrue(dest.hashCode() != dest1.hashCode());
assertTrue(dest.hashCode() == dest2.hashCode());
assertTrue(dest.hashCode() != dest3.hashCode());
+
+ AMQDestination dest4 = new AMQQueue("ADDR:Foo/Bar; {node :{type:queue}}");
+ AMQDestination dest5 = new AMQQueue("ADDR:Foo/Bar2; {node :{type:queue}}");
+ assertTrue(dest4.hashCode() != dest5.hashCode());
}
}
diff --git a/qpid/java/common.xml b/qpid/java/common.xml
index ce5693fd28..85cc7fc30b 100644
--- a/qpid/java/common.xml
+++ b/qpid/java/common.xml
@@ -24,9 +24,9 @@
<property name="project.name" value="qpid"/>
<!-- Version used for standard build output -->
- <property name="project.version" value="0.21"/>
+ <property name="project.version" value="0.23"/>
<!-- The release version used for maven output. SNAPSHOT added via maven.version.suffix -->
- <property name="project.version.maven" value="0.22"/>
+ <property name="project.version.maven" value="0.24"/>
<property name="project.url" value="http://qpid.apache.org"/>
<property name="project.groupid" value="org.apache.qpid"/>
<property name="project.namever" value="${project.name}-${project.version}"/>
diff --git a/qpid/java/common/src/main/java/common.bnd b/qpid/java/common/src/main/java/common.bnd
index 84350fdc75..5635012faa 100755
--- a/qpid/java/common/src/main/java/common.bnd
+++ b/qpid/java/common/src/main/java/common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.21.0
+ver: 0.23.0
Bundle-SymbolicName: qpid-common
Bundle-Version: ${ver}
diff --git a/qpid/java/management/common/src/main/java/management-common.bnd b/qpid/java/management/common/src/main/java/management-common.bnd
index 5ae9791299..dad6055a13 100644
--- a/qpid/java/management/common/src/main/java/management-common.bnd
+++ b/qpid/java/management/common/src/main/java/management-common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.21.0
+ver: 0.23.0
Bundle-SymbolicName: qpid-management-common
Bundle-Version: ${ver}
diff --git a/qpid/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json b/qpid/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json
index c147866591..aefd51dde0 100644
--- a/qpid/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json
+++ b/qpid/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json
@@ -1,7 +1,7 @@
{
"_tests":[
{
- "_name": "Varying number of participants: 1 consumer - 1 producer - PERSISTENT",
+ "_name": "Latency of varying number of participants: 1 consumer - 1 producer - PERSISTENT",
"_queues":[
{
"_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
@@ -59,1849 +59,10 @@
}
]
},
- {
- "_name": "Varying number of participants: 2 consumers - 1 producer - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_deliveryMode": 2,
- "_messageSize": 1024,
- "_interval": 1000
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "Varying number of participants: 5 consumers - 1 producer - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection0",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session0",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
- {
- "_name": "Varying number of participants: 10 consumers - 1 producer - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection0",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session0",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection6",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session6",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer6",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection7",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session7",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer7",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection8",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session8",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer8",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection9",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session9",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer9",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection10",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session10",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer10",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
- {
- "_name": "Varying number of participants: 1 consumer - 2 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
- {
- "_name": "Varying number of participants: 2 consumers - 2 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
- {
- "_name": "Varying number of participants: 5 consumers - 2 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
- {
- "_name": "Varying number of participants: 10 consumers - 2 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 1500,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection6",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session6",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer6",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection7",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session7",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer7",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection8",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session8",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer8",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection9",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session9",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer9",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection10",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session10",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer10",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
- {
- "_name": "Varying number of participants: 1 consumer - 5 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
- {
- "_name": "Varying number of participants: 2 consumers - 5 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
-
- {
- "_name": "Varying number of participants: 5 consumers - 5 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
- {
- "_name": "Varying number of participants: 10 consumers - 5 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 2000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection6",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session6",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer6",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection7",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session7",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer7",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection8",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session8",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer8",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection9",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session9",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer9",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection10",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session10",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer10",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
{
- "_name": "Varying number of participants: 1 consumer - 10 producers - PERSISTENT",
+ "_name": "Latency of varying number of participants: 1 consumer - 10 producers - PERSISTENT",
"_queues":[
{
"_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
@@ -2140,588 +301,8 @@
]
},
-
-
-
- {
- "_name": "Varying number of participants: 2 consumers - 10 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection6",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session6",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer6",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection7",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session7",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer7",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection8",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session8",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer8",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection9",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session9",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer9",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection10",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session10",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer10",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
-
- {
- "_name": "Varying number of participants: 5 consumers - 10 producers - PERSISTENT",
- "_queues":[
- {
- "_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_durable": true
- }
- ],
- "_clients":[
- {
- "_name": "producingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection6",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session6",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer6",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection7",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session7",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer7",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection8",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session8",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer8",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection9",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session9",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer9",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- },
- {
- "_name": "connection10",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session10",
- "_acknowledgeMode": 1,
- "_producers": [
- {
- "_name": "Producer10",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_interval": 3000,
- "_deliveryMode": 2,
- "_messageSize": 1024
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "_name": "consumingClient",
- "_connections":[
- {
- "_name": "connection1",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session1",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer1",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection2",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session2",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer2",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection3",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session3",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer3",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection4",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session4",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer4",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- },
- {
- "_name": "connection5",
- "_factory": "connectionfactory",
- "_sessions": [
- {
- "_sessionName": "session5",
- "_acknowledgeMode": 1,
- "_consumers": [
- {
- "_name": "Consumer5",
- "_destinationName": "direct://amq.direct//latency-varying-consumers?durable='true'",
- "_maximumDuration": 60000,
- "_evaluateLatency": true
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
-
-
-
-
{
- "_name": "Varying number of participants: 10 consumers - 10 producers - PERSISTENT",
+ "_name": "Latency of varying number of participants: 10 consumers - 10 producers - PERSISTENT",
"_queues":[
{
"_name": "direct://amq.direct//latency-varying-consumers?durable='true'",
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
index 078a1bb483..4ba2069dfd 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
@@ -41,14 +41,21 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase
{
List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("/rest/authenticationprovider");
assertNotNull("Providers details cannot be null", providerDetails);
- assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ assertEquals("Unexpected number of providers", 2, providerDetails.size());
for (Map<String, Object> provider : providerDetails)
{
- assertProvider(true, PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE, provider);
+ boolean managesPrincipals = true;
+ String type = PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE;
+ if (ANONYMOUS_AUTHENTICATION_PROVIDER.equals(provider.get(AuthenticationProvider.NAME)))
+ {
+ type = AnonymousAuthenticationManagerFactory.PROVIDER_TYPE;
+ managesPrincipals = false;
+ }
+ assertProvider(managesPrincipals, type , provider);
Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/"
+ provider.get(AuthenticationProvider.NAME));
assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data);
- assertProvider(true, PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE, data);
+ assertProvider(managesPrincipals, type, data);
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
index 63691e9915..fe4115b4c0 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
@@ -20,8 +20,10 @@
*/
package org.apache.qpid.systest.rest;
+import java.io.File;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -32,7 +34,10 @@ import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.adapter.BrokerAdapter;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestSSLConstants;
public class BrokerRestTest extends QpidRestTestCase
{
@@ -86,6 +91,107 @@ public class BrokerRestTest extends QpidRestTestCase
new HashSet<String>(port2Protocols));
}
+ public void testPutToUpdateWithValidAttributeValues() throws Exception
+ {
+ Map<String, Object> brokerAttributes = getValidBrokerAttributes();
+
+ int response = getRestTestHelper().submitRequest("/rest/broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response", 200, response);
+
+ restartBroker();
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("/rest/broker");
+ assertBrokerAttributes(brokerAttributes, brokerDetails);
+ }
+
+ public void testPutToUpdateWithInvalidAttributeValues() throws Exception
+ {
+ Map<String, Object> invalidAttributes = new HashMap<String, Object>();
+ invalidAttributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "non-existing-provider");
+ invalidAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, "non-existing-host");
+ invalidAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_AGE, -1000);
+ invalidAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_COUNT, -2000);
+ invalidAttributes.put(Broker.ALERT_THRESHOLD_QUEUE_DEPTH, -3000);
+ invalidAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_SIZE, -4000);
+ invalidAttributes.put(Broker.ALERT_REPEAT_GAP, -5000);
+ invalidAttributes.put(Broker.FLOW_CONTROL_SIZE_BYTES, -7000);
+ invalidAttributes.put(Broker.FLOW_CONTROL_RESUME_SIZE_BYTES, -16000);
+ invalidAttributes.put(Broker.MAXIMUM_DELIVERY_ATTEMPTS, -8);
+ invalidAttributes.put(Broker.HOUSEKEEPING_CHECK_PERIOD, -90000);
+ invalidAttributes.put(Broker.SESSION_COUNT_LIMIT, -10);
+ invalidAttributes.put(Broker.HEART_BEAT_DELAY, -11000);
+ invalidAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, -12000);
+ invalidAttributes.put(Broker.ACL_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-acl.acl");
+ invalidAttributes.put(Broker.KEY_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-keystore.jks");
+ invalidAttributes.put(Broker.KEY_STORE_PASSWORD, "password1");
+ invalidAttributes.put(Broker.KEY_STORE_CERT_ALIAS, "java-broker1");
+ invalidAttributes.put(Broker.TRUST_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-truststore.jks");
+ invalidAttributes.put(Broker.TRUST_STORE_PASSWORD, "password2");
+ invalidAttributes.put(Broker.PEER_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-peerstore.jks");
+ invalidAttributes.put(Broker.PEER_STORE_PASSWORD, "password3");
+ invalidAttributes.put(Broker.GROUP_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "groups-non-existing");
+
+ for (Map.Entry<String, Object> entry : invalidAttributes.entrySet())
+ {
+ Map<String, Object> brokerAttributes = getValidBrokerAttributes();
+ brokerAttributes.put(entry.getKey(), entry.getValue());
+ int response = getRestTestHelper().submitRequest("/rest/broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response for invalid attribute " + entry.getKey() + "=" + entry.getValue(), 409, response);
+ }
+
+ // a special case when FLOW_CONTROL_RESUME_SIZE_BYTES > FLOW_CONTROL_SIZE_BYTES
+ Map<String, Object> brokerAttributes = getValidBrokerAttributes();
+ brokerAttributes.put(Broker.FLOW_CONTROL_SIZE_BYTES, 1000);
+ brokerAttributes.put(Broker.FLOW_CONTROL_RESUME_SIZE_BYTES, 2000);
+ int response = getRestTestHelper().submitRequest("/rest/broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response for flow resume size > flow size", 409, response);
+ }
+
+ private Map<String, Object> getValidBrokerAttributes()
+ {
+ Map<String, Object> brokerAttributes = new HashMap<String, Object>();
+ brokerAttributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST);
+ brokerAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_AGE, 1000);
+ brokerAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_COUNT, 2000);
+ brokerAttributes.put(Broker.ALERT_THRESHOLD_QUEUE_DEPTH, 3000);
+ brokerAttributes.put(Broker.ALERT_THRESHOLD_MESSAGE_SIZE, 4000);
+ brokerAttributes.put(Broker.ALERT_REPEAT_GAP, 5000);
+ brokerAttributes.put(Broker.FLOW_CONTROL_SIZE_BYTES, 7000);
+ brokerAttributes.put(Broker.FLOW_CONTROL_RESUME_SIZE_BYTES, 6000);
+ brokerAttributes.put(Broker.MAXIMUM_DELIVERY_ATTEMPTS, 8);
+ brokerAttributes.put(Broker.DEAD_LETTER_QUEUE_ENABLED, true);
+ brokerAttributes.put(Broker.HOUSEKEEPING_CHECK_PERIOD, 90000);
+ brokerAttributes.put(Broker.SESSION_COUNT_LIMIT, 10);
+ brokerAttributes.put(Broker.HEART_BEAT_DELAY, 11000);
+ brokerAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, 12000);
+ brokerAttributes.put(Broker.STATISTICS_REPORTING_RESET_ENABLED, true);
+ brokerAttributes.put(Broker.ACL_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "broker_example.acl");
+ brokerAttributes.put(Broker.KEY_STORE_PATH, TestSSLConstants.BROKER_KEYSTORE);
+ brokerAttributes.put(Broker.KEY_STORE_PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD);
+ brokerAttributes.put(Broker.KEY_STORE_CERT_ALIAS, "java-broker");
+ brokerAttributes.put(Broker.TRUST_STORE_PATH, TestSSLConstants.TRUSTSTORE);
+ brokerAttributes.put(Broker.TRUST_STORE_PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ brokerAttributes.put(Broker.PEER_STORE_PATH, TestSSLConstants.TRUSTSTORE);
+ brokerAttributes.put(Broker.PEER_STORE_PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ brokerAttributes.put(Broker.GROUP_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "groups");
+ return brokerAttributes;
+ }
+
+ private void assertBrokerAttributes(Map<String, Object> expectedAttributes, Map<String, Object> actualAttributes)
+ {
+ for (Map.Entry<String, Object> entry : expectedAttributes.entrySet())
+ {
+ String attributeName = entry.getKey();
+ Object attributeValue = entry.getValue();
+ if (attributeName.equals(Broker.KEY_STORE_PASSWORD) || attributeName.equals(Broker.TRUST_STORE_PASSWORD) || attributeName.equals(Broker.PEER_STORE_PASSWORD))
+ {
+ attributeValue = "********";
+ }
+ Object currentValue = actualAttributes.get(attributeName);
+ assertEquals("Unexpected attribute " + attributeName + " value:", attributeValue, currentValue);
+ }
+ }
+
protected void assertBrokerAttributes(Map<String, Object> brokerDetails)
{
Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES,
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java
index e2b73aa2b5..30d5b195f1 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java
@@ -21,14 +21,21 @@
package org.apache.qpid.systest.rest;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.plugin.AuthenticationManagerFactory;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManagerFactory;
+import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManagerFactory;
import org.apache.qpid.test.utils.TestBrokerConfiguration;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
public class QpidRestTestCase extends QpidBrokerTestCase
{
+ public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "testAnonymous";
public static final String TEST1_VIRTUALHOST = "test";
public static final String TEST2_VIRTUALHOST = "test2";
public static final String TEST3_VIRTUALHOST = "test3";
@@ -77,6 +84,11 @@ public class QpidRestTestCase extends QpidBrokerTestCase
config.setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, _restTestHelper.getHttpPort());
config.removeObjectConfiguration(TestBrokerConfiguration.ENTRY_NAME_JMX_PORT);
config.removeObjectConfiguration(TestBrokerConfiguration.ENTRY_NAME_RMI_PORT);
+
+ Map<String, Object> anonymousProviderAttributes = new HashMap<String, Object>();
+ anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManagerFactory.PROVIDER_TYPE);
+ anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ config.addAuthenticationProviderConfiguration(anonymousProviderAttributes);
}
public RestTestHelper getRestTestHelper()
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java
index f5e326f90b..5593ad0b42 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java
@@ -45,7 +45,7 @@ public class StructureRestTest extends QpidRestTestCase
@SuppressWarnings("unchecked")
List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders");
- assertEquals("Unexpected number of authentication providers", 1, providers.size());
+ assertEquals("Unexpected number of authentication providers", 2, providers.size());
for (String hostName : EXPECTED_VIRTUALHOSTS)
{
diff --git a/qpid/packaging/windows/INSTALL_NOTES.html b/qpid/packaging/windows/INSTALL_NOTES.html
index 54f427ed79..66a24253a2 100644
--- a/qpid/packaging/windows/INSTALL_NOTES.html
+++ b/qpid/packaging/windows/INSTALL_NOTES.html
@@ -1,11 +1,11 @@
<html>
<head>
-<title>Apache Qpid C++ 0.21 Installation Notes</title>
+<title>Apache Qpid C++ 0.23 Installation Notes</title>
</head>
<body>
-<H1>Apache Qpid C++ 0.21 Installation Notes</H1>
+<H1>Apache Qpid C++ 0.23 Installation Notes</H1>
-<p>Thank you for installing Apache Qpid version 0.21 for Windows.
+<p>Thank you for installing Apache Qpid version 0.23 for Windows.
If the requisite features were installed, you can now run a broker,
use the example programs, and design your own messaging programs while
reading the Qpid C++ API reference documentation.</p>
@@ -83,7 +83,7 @@ default; therefore, to gain support for durable items the persistence plugin
must be loaded into the broker. This can be done using the
<code>--load-module</code> option to load the needed plugins. For example:
<pre>
-cd "C:\Program Files\Apache\qpidc-0.21"
+cd "C:\Program Files\Apache\qpidc-0.23"
qpidd.exe --load-module plugins\broker\store.dll --load-module plugins\broker\msclfs_store.dll
</pre>
The <code>--load-module</code> option can also take a full path. The option
diff --git a/qpid/packaging/windows/installer.proj b/qpid/packaging/windows/installer.proj
index b2d1d6fb2f..5402559a18 100644
--- a/qpid/packaging/windows/installer.proj
+++ b/qpid/packaging/windows/installer.proj
@@ -32,7 +32,7 @@
<source_root>$(MSBuildProjectDirectory)\..\..</source_root>
<staging_dir>$(MSBuildProjectDirectory)\stage</staging_dir>
<bits Condition="'$(bits)' == ''">32</bits>
- <qpid_version>0.21</qpid_version>
+ <qpid_version>0.23</qpid_version>
<OutputName>qpidc</OutputName>
<OutputType>Package</OutputType>
<WixToolPath>C:\Program Files (x86)\Windows Installer XML v3.5\bin</WixToolPath>
diff --git a/qpid/python/qpid/messaging/endpoints.py b/qpid/python/qpid/messaging/endpoints.py
index 95ff5516d0..143daf616a 100644
--- a/qpid/python/qpid/messaging/endpoints.py
+++ b/qpid/python/qpid/messaging/endpoints.py
@@ -122,6 +122,10 @@ class Connection(Endpoint):
@param ssl_certfile: file with client's public (eventually priv+pub) key (PEM format)
@type ssl_trustfile: str
@param ssl_trustfile: file trusted certificates to validate the server
+ @type ssl_skip_hostname_check: bool
+ @param ssl_skip_hostname_check: disable verification of hostname in
+ certificate. Use with caution - disabling hostname checking leaves you
+ vulnerable to Man-in-the-Middle attacks.
@rtype: Connection
@return: a disconnected Connection
@@ -170,6 +174,7 @@ class Connection(Endpoint):
self.ssl_keyfile = options.get("ssl_keyfile", None)
self.ssl_certfile = options.get("ssl_certfile", None)
self.ssl_trustfile = options.get("ssl_trustfile", None)
+ self.ssl_skip_hostname_check = options.get("ssl_skip_hostname_check", False)
self.client_properties = options.get("client_properties", {})
self.options = options
diff --git a/qpid/python/qpid/messaging/transports.py b/qpid/python/qpid/messaging/transports.py
index e901e98258..c76db1f395 100644
--- a/qpid/python/qpid/messaging/transports.py
+++ b/qpid/python/qpid/messaging/transports.py
@@ -53,7 +53,7 @@ TRANSPORTS["tcp"] = tcp
try:
from ssl import wrap_socket, SSLError, SSL_ERROR_WANT_READ, \
- SSL_ERROR_WANT_WRITE
+ SSL_ERROR_WANT_WRITE, CERT_REQUIRED, CERT_NONE
except ImportError:
## try the older python SSL api:
@@ -69,6 +69,15 @@ except ImportError:
ssl_certfile = conn.ssl_certfile
if ssl_certfile and not ssl_keyfile:
ssl_keyfile = ssl_certfile
+
+ # this version of SSL does NOT perform certificate validation. If the
+ # connection has been configured with CA certs (via ssl_trustfile), then
+ # the application expects the certificate to be validated against the
+ # supplied CA certs. Since this version cannot validate, the peer cannot
+ # be trusted.
+ if conn.ssl_trustfile:
+ raise SSLError("This version of Python does not support verification of the peer's certificate.")
+
self.ssl = ssl(self.socket, keyfile=ssl_keyfile, certfile=ssl_certfile)
self.socket.setblocking(1)
@@ -95,7 +104,39 @@ else:
def __init__(self, conn, host, port):
SocketTransport.__init__(self, conn, host, port)
- self.tls = wrap_socket(self.socket, keyfile=conn.ssl_keyfile, certfile=conn.ssl_certfile, ca_certs=conn.ssl_trustfile)
+ if conn.ssl_trustfile:
+ validate = CERT_REQUIRED
+ else:
+ validate = CERT_NONE
+
+ self.tls = wrap_socket(self.socket, keyfile=conn.ssl_keyfile,
+ certfile=conn.ssl_certfile,
+ ca_certs=conn.ssl_trustfile,
+ cert_reqs=validate)
+
+ if validate == CERT_REQUIRED and not conn.ssl_skip_hostname_check:
+ match_found = False
+ peer_cert = self.tls.getpeercert()
+ if peer_cert:
+ peer_names = []
+ if 'subjectAltName' in peer_cert:
+ for san in peer_cert['subjectAltName']:
+ if san[0] == 'DNS':
+ peer_names.append(san[1].lower())
+ if 'subject' in peer_cert:
+ for sub in peer_cert['subject']:
+ while isinstance(sub, tuple) and isinstance(sub[0],tuple):
+ sub = sub[0] # why the extra level of indirection???
+ if sub[0] == 'commonName':
+ peer_names.append(sub[1].lower())
+ for pattern in peer_names:
+ if _match_dns_pattern( host.lower(), pattern ):
+ #print "Match found %s" % pattern
+ match_found = True
+ break
+ if not match_found:
+ raise SSLError("Connection hostname '%s' does not match names from peer certificate: %s" % (host, peer_names))
+
self.socket.setblocking(0)
self.state = None
@@ -146,5 +187,31 @@ else:
# this closes the underlying socket
self.tls.close()
+ def _match_dns_pattern( hostname, pattern ):
+ """ For checking the hostnames provided by the peer's certificate
+ """
+ if pattern.find("*") == -1:
+ return hostname == pattern
+
+ # DNS wildcarded pattern - see RFC2818
+ h_labels = hostname.split(".")
+ p_labels = pattern.split(".")
+
+ while h_labels and p_labels:
+ if p_labels[0].find("*") == -1:
+ if p_labels[0] != h_labels[0]:
+ return False
+ else:
+ p = p_labels[0].split("*")
+ if not h_labels[0].startswith(p[0]):
+ return False
+ if not h_labels[0].endswith(p[1]):
+ return False
+ h_labels.pop(0)
+ p_labels.pop(0)
+
+ return not h_labels and not p_labels
+
+
TRANSPORTS["ssl"] = tls
TRANSPORTS["tcp+tls"] = tls
diff --git a/qpid/python/setup.py b/qpid/python/setup.py
index 56af530b43..5afa913183 100755
--- a/qpid/python/setup.py
+++ b/qpid/python/setup.py
@@ -298,7 +298,7 @@ class install_lib(_install_lib):
return outfiles + extra
setup(name="qpid-python",
- version="0.21",
+ version="0.23",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
packages=["mllib", "qpid", "qpid.messaging", "qpid.tests",
diff --git a/qpid/tests/setup.py b/qpid/tests/setup.py
index 67d2c87ad9..519c47c416 100755
--- a/qpid/tests/setup.py
+++ b/qpid/tests/setup.py
@@ -20,7 +20,7 @@
from distutils.core import setup
setup(name="qpid-tests",
- version="0.21",
+ version="0.23",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
packages=["qpid_tests", "qpid_tests.broker_0_10", "qpid_tests.broker_0_9",
diff --git a/qpid/tools/setup.py b/qpid/tools/setup.py
index 438a2af14f..87ae63c903 100755
--- a/qpid/tools/setup.py
+++ b/qpid/tools/setup.py
@@ -20,7 +20,7 @@
from distutils.core import setup
setup(name="qpid-tools",
- version="0.21",
+ version="0.23",
author="Apache Qpid",
author_email="dev@qpid.apache.org",
package_dir={'' : 'src/py'},
diff --git a/qpid/tools/src/ruby/qpid_management/.gitignore b/qpid/tools/src/ruby/qpid_management/.gitignore
new file mode 100644
index 0000000000..6a65a36504
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/.gitignore
@@ -0,0 +1,3 @@
+*.gem
+.bundle
+pkg/*
diff --git a/qpid/tools/src/ruby/qpid_management/.rspec b/qpid/tools/src/ruby/qpid_management/.rspec
new file mode 100644
index 0000000000..4e1e0d2f72
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/.rspec
@@ -0,0 +1 @@
+--color
diff --git a/qpid/tools/src/ruby/qpid_management/Gemfile b/qpid/tools/src/ruby/qpid_management/Gemfile
new file mode 100644
index 0000000000..1bd80c10c1
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/Gemfile
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in qpid_config.gemspec
+gemspec
+
+# development deps
+gem 'rspec'
+gem 'pry'
+gem 'pry-stack_explorer'
+gem 'pry-debugger'
+gem 'yard'
diff --git a/qpid/tools/src/ruby/qpid_management/Gemfile.lock b/qpid/tools/src/ruby/qpid_management/Gemfile.lock
new file mode 100644
index 0000000000..bf35564e90
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/Gemfile.lock
@@ -0,0 +1,55 @@
+PATH
+ remote: .
+ specs:
+ qpid_management (1.0)
+ qpid_messaging
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ binding_of_caller (0.7.1)
+ debug_inspector (>= 0.0.1)
+ coderay (1.0.9)
+ columnize (0.3.6)
+ debug_inspector (0.0.2)
+ debugger (1.4.0)
+ columnize (>= 0.3.1)
+ debugger-linecache (~> 1.1.1)
+ debugger-ruby_core_source (~> 1.2.0)
+ debugger-linecache (1.1.2)
+ debugger-ruby_core_source (>= 1.1.1)
+ debugger-ruby_core_source (1.2.0)
+ diff-lcs (1.2.1)
+ method_source (0.8.1)
+ pry (0.9.12)
+ coderay (~> 1.0.5)
+ method_source (~> 0.8)
+ slop (~> 3.4)
+ pry-debugger (0.2.2)
+ debugger (~> 1.3)
+ pry (~> 0.9.10)
+ pry-stack_explorer (0.4.9)
+ binding_of_caller (>= 0.7)
+ pry (~> 0.9.11)
+ qpid_messaging (0.20.2)
+ rspec (2.13.0)
+ rspec-core (~> 2.13.0)
+ rspec-expectations (~> 2.13.0)
+ rspec-mocks (~> 2.13.0)
+ rspec-core (2.13.0)
+ rspec-expectations (2.13.0)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rspec-mocks (2.13.0)
+ slop (3.4.3)
+ yard (0.8.5.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ pry
+ pry-debugger
+ pry-stack_explorer
+ qpid_management!
+ rspec
+ yard
diff --git a/qpid/tools/src/ruby/qpid_management/Rakefile b/qpid/tools/src/ruby/qpid_management/Rakefile
new file mode 100644
index 0000000000..7f295eda5c
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/Rakefile
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require "bundler/gem_tasks"
+require 'rspec/core/rake_task'
+
+require 'rake/clean'
+CLOBBER.include('pkg')
+
+RSpec::Core::RakeTask.new('spec')
+
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb
new file mode 100644
index 0000000000..0529710693
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb
@@ -0,0 +1,81 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 'qpid_management/broker_agent'
+require 'qpid_management/broker_object'
+require 'qpid_management/acl'
+require 'qpid_management/binding'
+require 'qpid_management/bridge'
+require 'qpid_management/broker'
+require 'qpid_management/cluster'
+require 'qpid_management/connection'
+require 'qpid_management/errors'
+require 'qpid_management/exchange'
+require 'qpid_management/ha_broker'
+require 'qpid_management/link'
+require 'qpid_management/memory'
+require 'qpid_management/queue'
+require 'qpid_management/session'
+require 'qpid_management/subscription'
+
+module Qpid
+ # The Qpid Management framework is a management framework for Qpid brokers
+ # that uses QMF2.
+ #
+ # ==== Example Usage
+ #
+ # Here is a simple example. It TODO.
+ #
+ # require 'rubygems'
+ # require 'qpid_messaging'
+ # require 'qpid_management'
+ #
+ # # create a connection and open it
+ # conn = Qpid::Messaging::Connection.new(:url => "broker.myqpiddomain.com")
+ # conn.open()
+ #
+ # # create a broker agent
+ # agent = Qpid::Management::BrokerAgent.new(conn)
+ #
+ # # get a reference to the broker
+ # broker = agent.broker
+ #
+ # # print out all exchange names
+ # puts broker.exchanges.map(&:name)
+ #
+ # # print out info about a single exchange
+ # amq_direct = broker.exchange('amq.direct')
+ # puts amq_direct
+ # puts amq_direct.msgDrops
+ #
+ # # create an exchange
+ # broker.add_exchange('topic', 'myexchange')
+ #
+ # # print out all queue names
+ # puts broker.queues.map(&:name)
+ #
+ # # create a queue
+ # broker.add_queue('myqueue')
+ #
+ # # print out info about a single queue
+ # myqueue = broker.queue('myqueue')
+ # puts myqueue.msgDepth
+ module Management
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb
new file mode 100644
index 0000000000..589b11fa59
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 Qpid
+ module Management
+ # Representation of the access control list (ACL) for the broker. Properties
+ # include:
+ # - aclDenyCount
+ # - brokerRef
+ # - connectionDenyCount
+ # - enforcingAcl
+ # - lastAclLoad
+ # - maxConnectionsPerIp
+ # - maxConnectionsPerUser
+ # - maxQueuesPerUser
+ # - policyFile
+ # - queueQuotaDenyCount
+ # - transferAcl
+ class Acl < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb
new file mode 100644
index 0000000000..cc46d84eeb
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+ module Management
+ # Representation of a binding in the broker. Properties include:
+ # - arguments
+ # - bindingKey
+ # - exchangeRef
+ # - msgMatched
+ # - queueRef
+ class Binding < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb
new file mode 100644
index 0000000000..cece0ba2ed
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 Qpid
+ module Management
+ # Representation of a bridge to another broker. Properties include:
+ # - channelId
+ # - dest
+ # - durable
+ # - dynamic
+ # - excludes
+ # - key
+ # - linkRef
+ # - name
+ # - src
+ # - srcIsLocal
+ # - srcIsQueue
+ # - sync
+ # - tag
+ class Bridge < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb
new file mode 100644
index 0000000000..31171bdf35
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb
@@ -0,0 +1,278 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 Qpid
+ module Management
+ # Representation of the broker. Properties include:
+ # - abandoned
+ # - abandonedViaAlt
+ # - acquires
+ # - byteDepth
+ # - byteFtdDepth
+ # - byteFtdDequeues
+ # - byteFtdEnqueues
+ # - bytePersistDequeues
+ # - bytePersistEnqueues
+ # - byteTotalDequeues
+ # - byteTotalEnqueues
+ # - byteTxnDequeues
+ # - byteTxnEnqueues
+ # - connBacklog
+ # - dataDir
+ # - discardsLvq
+ # - discardsNoRoute
+ # - discardsOverflow
+ # - discardsPurge
+ # - discardsRing
+ # - discardsSubscriber
+ # - discardsTtl
+ # - maxConns
+ # - mgmtPubInterval
+ # - mgmtPublish
+ # - msgDepth
+ # - msgFtdDepth
+ # - msgFtdDequeues
+ # - msgFtdEnqueues
+ # - msgPersistDequeues
+ # - msgPersistEnqueues
+ # - msgTotalDequeues
+ # - msgTotalEnqueues
+ # - msgTxnDequeues
+ # - msgTxnEnqueues
+ # - name
+ # - port
+ # - queueCount
+ # - releases
+ # - reroutes
+ # - stagingThreshold
+ # - systemRef
+ # - uptime
+ # - version
+ # - workerThreads
+ class Broker < BrokerObject
+ # Adds methods for the specified collections to be able to access all instances
+ # of a given collection, as well as a single instance by oid.
+ #
+ # == Example
+ # <tt>has_many :queues</tt> which will add:
+ # * <tt>#queues</tt> to retrieve all queues
+ # * <tt>#queue(oid)</tt> to retrieve a queue by oid (note, this is the short form of the object id, e.g. "myqueue" for a queue instead of "org.apache.qpid.broker:queue:myqueue"
+ #
+ # @param collections one or more symbols for the collections of objects a broker manages
+ def self.has_many(*collections)
+ [*collections].each do |collection|
+ singular_form = collection.to_s[0..-2]
+ capitalized_type = singular_form.gsub(/^\w/) { $&.upcase }
+
+ define_method(collection) do
+ @agent.find_all_by_class(Qpid::Management::const_get(capitalized_type))
+ end
+
+ define_method(singular_form) do |oid|
+ @agent.find_by_object_id(Qpid::Management::const_get(capitalized_type), "org.apache.qpid.broker:#{singular_form}:#{oid}")
+ end
+ end
+ end
+
+ # Adds method for the specified types to be able to access the singular
+ # instance of a given type.
+ #
+ # == Example
+ # <tt>has_one :acl</tt> which will add:
+ # * <tt>#acl</tt> to retrieve the Acl data for the Broker
+ #
+ # @param types one or more symbols for the singular objects a broker manages
+ def self.has_one(*types)
+ [*types].each do |type|
+ capitalized_type = type.to_s.gsub(/^\w/) { $&.upcase }
+
+ define_method("#{type}") do
+ @agent.find_first_by_class(Qpid::Management::const_get(capitalized_type))
+ end
+ end
+ end
+
+ has_many :connections, :sessions, :subscriptions, :exchanges, :queues, :bindings, :links, :bridges
+ has_one :acl, :memory
+
+ # Adds an exchange to the broker
+ # @param [String] type exchange type (fanout, direct, topic, headers, xml)
+ # @param [String] name exchange name
+ # @param [Hash] options exchange creation options
+ def add_exchange(type, name, options={})
+ create_broker_object('exchange', name, options.merge!({'exchange-type' => type}))
+ end
+
+ # Deletes an exchange from the broekr
+ # @param [String] name exchange name
+ def delete_exchange(name)
+ invoke_method('delete', {'type' => 'exchange', 'name' => name})
+ end
+
+ # Adds a queue to the broker
+ # @param [String] name queue name
+ # @param [Hash] options queue creation options
+ def add_queue(name, options={})
+ create_broker_object('queue', name, options)
+ end
+
+ # Deletes a queue from the broker
+ # @param [String] name queue name
+ def delete_queue(name)
+ invoke_method('delete', {'type' => 'queue', 'name' => name})
+ end
+
+ # Adds a binding from an exchange to a queue
+ # @param [String] exchange exchange name
+ # @param [String] queue queue name
+ # @param [String] key binding key
+ # @param [Hash] options binding creation options
+ def add_binding(exchange, queue, key="", options={})
+ create_broker_object('binding', "#{exchange}/#{queue}/#{key}", options)
+ end
+
+ # Deletes a binding from an exchange to a queue
+ # @param [String] exchange exchange name
+ # @param [String] queue queue name
+ # @param [String] key binding key
+ def delete_binding(exchange, queue, key="")
+ invoke_method('delete', {'type' => 'binding', 'name' => "#{exchange}/#{queue}/#{key}"})
+ end
+
+ # Adds a link to a remote broker
+ # @param [String] name link name
+ # @param [String] host remote broker host name or IP address
+ # @param [Fixnum] port remote broker port
+ # @param [String] transport transport mechanism used to connect to the remote broker
+ # @param [Boolean] durable should this link be persistent
+ # @param [String] auth_mechanism authentication mechanism to use
+ # @param [String] username user name to authenticate with the remote broker
+ # @param [String] password password for the user name
+ def add_link(name, host, port, transport='tcp', durable=false, auth_mechanism="", username="", password="")
+ options = {
+ 'host' => host,
+ 'port' => port,
+ 'transport' => transport,
+ 'durable' => durable,
+ 'authMechanism' => auth_mechanism,
+ 'username' => username,
+ 'password' => password
+ }
+
+ create_broker_object('link', name, options)
+ end
+
+ # Deletes a link to a remote broker
+ # @param [String] name link name
+ def delete_link(name)
+ invoke_method('delete', {'type' => 'link', 'name' => name})
+ end
+
+ # Adds a queue route
+ # @param [String] name the name of the bridge to create
+ # @param [Hash] options options for the queue route
+ # @option options [String] :link the name of the link to use (required)
+ # @option options [String] :queue the name of the source queue from which messages are pulled (required)
+ # @option options [String] :exchange the name of the destination exchange to which messages are sent (required)
+ # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required)
+ def add_queue_route(name, options={})
+ validate_options(options, [:link, :queue, :exchange, :sync])
+
+ properties = {
+ 'link' => options[:link],
+ 'src' => options[:queue],
+ 'dest' => options[:exchange],
+ 'srcIsQueue' => true,
+ 'sync' => options[:sync]
+ }
+
+ create_broker_object('bridge', name, properties)
+ end
+
+ # Adds an exchange route
+ # @param [String] name the name of the bridge to create
+ # @param [Hash] options options for the exchange route
+ # @option options [String] :link the name of the link to use (required)
+ # @option options [String] :exchange the name of the exchange to use (required)
+ # @option options [String] :key routing key to federate (required)
+ # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required)
+ # @option options [String] :bridge_queue name of the queue to use as a bridge queue (optional)
+ def add_exchange_route(name, options={})
+ validate_options(options, [:link, :exchange, :key, :sync])
+
+ properties = {
+ 'link' => options[:link],
+ 'src' => options[:exchange],
+ 'dest' => options[:exchange],
+ 'key' => options[:key],
+ 'sync' => options[:sync]
+ }
+
+ properties['queue'] = options[:bridge_queue] if options.has_key?(:bridge_queue)
+
+ create_broker_object('bridge', name, properties)
+ end
+
+ # Adds a dynamic route
+ # @param [String] name the name of the bridge to create
+ # @param [Hash] options options for the dynamic route
+ # @option options [String] :link the name of the link to use (required)
+ # @option options [String] :exchange the name of the exchange to use (required)
+ # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required)
+ # @option options [String] :bridge_queue name of the queue to use as a bridge queue (optional)
+ def add_dynamic_route(name, options={})
+ validate_options(options, [:link, :exchange, :sync])
+
+ properties = {
+ 'link' => options[:link],
+ 'src' => options[:exchange],
+ 'dest' => options[:exchange],
+ 'dynamic' => true,
+ 'sync' => options[:sync]
+ }
+
+ properties['queue'] = options[:bridge_queue] if options.has_key?(:bridge_queue)
+
+ create_broker_object('bridge', name, properties)
+ end
+
+ # Deletes a bridge (route)
+ # @param [String] name bridge name
+ def delete_bridge(name)
+ invoke_method('delete', {'type' => 'bridge', 'name' => name})
+ end
+
+ private
+
+ def create_broker_object(type, name, options)
+ invoke_method('create', {'type' => type,
+ 'name' => name,
+ 'properties' => options,
+ 'strict' => true})
+ end
+
+ def validate_options(options, required)
+ required.each do |req|
+ raise "Option :#{req.to_s} is required" unless options.has_key?(req)
+ end
+ end
+
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb
new file mode 100644
index 0000000000..800dcf26dc
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb
@@ -0,0 +1,173 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# for simplistic UUID - may want to consider something better in the future
+require 'securerandom'
+
+# Ruby 1.8 doesn't include SecureRandom#uuid, so let's add it if it's missing
+unless SecureRandom.respond_to? :uuid
+ module SecureRandom
+ def self.uuid
+ ary = self.random_bytes(16).unpack("NnnnnN")
+ ary[2] = (ary[2] & 0x0fff) | 0x4000
+ ary[3] = (ary[3] & 0x3fff) | 0x8000
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
+ end
+ end
+end
+
+module Qpid
+ module Management
+ # This is the primary class that interacts with a Qpid messaging broker for
+ # querying information from the broker and for configuring it.
+ class BrokerAgent
+ # Creates a new BrokerAgent instance. A new Qpid::Messaging::Session,
+ # Qpid::Messaging::Receiver, and Qpid::Messaging::Sender will be created
+ # so this instance of the BrokerAgent may send requests to the broker
+ # and receive replies back.
+ # @param [Qpid::Messaging::Connection] connection a valid, opened connection
+ def initialize(connection)
+ @connection = connection
+ @session = @connection.create_session()
+ @reply_to = "qmf.default.topic/direct.#{SecureRandom.uuid}; {node: {type:topic}, link:{x-declare:{auto-delete:True,exclusive:True}}}"
+ @reply_rx = @session.create_receiver(@reply_to)
+ @reply_rx.capacity = 10
+ @tx = @session.create_sender("qmf.default.direct/broker")
+ end
+
+ # Closes the Qpid::Messaging::Session for this BrokerAgent.
+ def close()
+ @session.close()
+ end
+
+ # Queries the broker for the Broker QMF object.
+ # @return [Broker] the broker QMF object
+ def broker()
+ find_first_by_class(Broker)
+ end
+
+ # Queries the broker for the Cluster QMF object.
+ # @return [Cluster] the cluster QMF object
+ def cluster
+ find_first_by_class(Cluster)
+ end
+
+ # Queries the broker for the HaBroker QMF object.
+ # @return [HaBroker] the HA broker QMF object
+ def ha_broker
+ find_first_by_class(HaBroker)
+ end
+
+ # Invokes a method on a target object.
+ # @param [String] method the name of the method to invoke
+ # @param [Hash] args the arguments to pass to the method
+ # @param [String] addr the full id of the target object
+ # @param [Fixnum] timeout the amount of time to wait for the broker to respond to the method invocation
+ def invoke_method(method, args, addr="org.apache.qpid.broker:broker:amqp-broker", timeout=10)
+ content = {'_object_id' => {'_object_name' => addr},
+ '_method_name' => method,
+ '_arguments' => args}
+
+ message = Qpid::Messaging::Message.new()
+ message.content = content
+ message.reply_to = @reply_to
+ message['method'] = 'request'
+ message['qmf.opcode'] = '_method_request'
+ message['x-amqp-0-10.app-id'] = 'qmf2'
+ message.subject = 'broker'
+
+ @tx.send(message)
+
+ response = @reply_rx.fetch(Qpid::Messaging::Duration.new(timeout * 1000))
+ @session.acknowledge()
+
+ raise "Exception from Agent: #{response.content['_values']}" if response.properties['qmf.opcode'] == '_exception'
+ raise "Bad response: #{response.properties}" if response.properties['qmf.opcode'] != '_method_response'
+
+ return response.content['_arguments']
+ end
+
+ def send_query(query)
+ message = Qpid::Messaging::Message.new()
+ message.content = query
+ message.reply_to = @reply_to
+ message['method'] = 'request'
+ message['qmf.opcode'] = '_query_request'
+ message['x-amqp-0-10.app-id'] = 'qmf2'
+ message.subject = 'broker'
+
+ @tx.send(message)
+
+ response = @reply_rx.fetch(Qpid::Messaging::Duration.new(10*1000))
+ @session.acknowledge()
+
+ raise 'Bad response' if response.properties['qmf.opcode'] != '_query_response'
+
+ items = response.content
+
+ while response.properties.has_key?('partial')
+ response = @reply_rx.fetch(Qpid::Messaging::Duration.new(10*1000))
+ items += response.content
+ @session.acknowledge()
+ end
+
+ return items
+ end
+
+ def find_all_by_class(clazz)
+ query = {
+ '_what' => 'OBJECT',
+ '_schema_id' => {
+ '_class_name' => BrokerObject.qmf_class(clazz)
+ }
+ }
+
+ items = send_query(query)
+
+ [].tap do |objs|
+ for item in items
+ objs << clazz.new(self, item)
+ end
+ end
+ end
+
+ def find_first_by_class(clazz)
+ objects = find_all_by_class(clazz)
+ return objects[0] if objects.size > 0
+ return nil
+ end
+
+ def find_by_object_id(clazz, oid)
+ query = {
+ '_what' => 'OBJECT',
+ '_object_id' => {
+ '_object_name' => oid
+ }
+ }
+
+ results = send_query(query)
+
+ return clazz.new(self, results[0]) if results.count == 1 and not results[0].nil?
+
+ # return nil if not found
+ return nil
+ end
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb
new file mode 100644
index 0000000000..fbbe5ff6e2
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb
@@ -0,0 +1,126 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 Qpid
+ module Management
+ # Representation of an object in the broker retrieved via QMF
+ class BrokerObject
+ attr_reader :content
+
+ # Creates a new BrokerObject
+ # @param [BrokerAgent] agent the agent used to query the data from the broker
+ # @param [Hash] content the raw QMF response data from the broker
+ def initialize(agent, content)
+ @agent = agent
+ @content = content
+ @values = content['_values']
+ end
+
+ # Refreshes the information associated with this instance by requerying the broker
+ # @raise [ObjectDeletedError] if the object has been deleted
+ def refresh!
+ refreshed = @agent.named_object(self.class, id)
+ if refreshed
+ @content = refreshed.content
+ @values = @content['_values']
+ else
+ raise ObjectDeletedError
+ end
+ end
+
+ # Returns the full object id
+ # @return [String] the full object id
+ def id
+ @content['_object_id']['_object_name']
+ end
+
+ # Helper method to convert a Class to its QMF name counterpart. For
+ # example, QpidConfig::Connection will be converted to connection.
+ # @param [Class] clazz the Class to convert
+ # @return [String] the converted QMF name counterpart for this Class
+ def self.qmf_class(clazz)
+ clazz.name.split(/::/).last.downcase
+ end
+
+ # Returns the short object id, i.e. without the leading org.apache.qpid.broker:<class name>:
+ # @return [String] the short object id
+ def short_id
+ clazz = BrokerObject.qmf_class(self.class)
+ if id =~ /org.apache.qpid.broker:#{clazz}:(.*)/
+ return $1;
+ end
+ return nil
+ end
+
+ # Returns the time at which this object was created
+ # @return [Time] the time at which this object was created
+ def created_at
+ Time.at(content['_create_ts'] / 1000000000.0)
+ end
+
+ # Returns the time at which this object was deleted. Only ever applies to
+ # BrokerObject instances created from a QMF event.
+ # @return [Time] the time at which this object was deleted
+ def deleted_at
+ Time.at(content['_delete_ts'] / 1000000000.0)
+ end
+
+ # Returns the time at which this object was last updated
+ # @return [Time] the time at which this object was last updated
+ def updated_at
+ Time.at(content['_update_ts'] / 1000000000.0)
+ end
+
+ # Exposes data from the QMF response
+ # @param [String] key the key to look up a value, e.g. msgDepth for a queue
+ # @return the value associated with the key, or nil if not found
+ def [](key)
+ return nil unless @values.has_key?(key)
+ value = @values[key]
+ if value.is_a?(Hash) and value.has_key?('_object_name')
+ full_name = value['_object_name']
+ colon = full_name.index(':')
+ unless colon.nil?
+ full_name = full_name[colon+1..-1]
+ colon = full_name.index(':')
+ return full_name[colon+1..-1] unless colon.nil?
+ end
+ end
+
+ return value
+ end
+
+ # Exposes data from the QMF response via methods, e.g. queue.msgDepth
+ def method_missing(method, *args, &block)
+ key = method.to_s
+ return self[key] if args.empty? and not self[key].nil?
+ super
+ end
+
+ def to_s
+ @values.to_s
+ end
+
+ # Invokes a QMF method
+ # @see BrokerAgent#invoke_method
+ def invoke_method(*args)
+ @agent.invoke_method(*args)
+ end
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb
new file mode 100644
index 0000000000..4fa7f146a7
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb
@@ -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.
+#
+
+module Qpid
+ module Management
+ # Representation of a cluster
+ class Cluster < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb
new file mode 100644
index 0000000000..153ccee684
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb
@@ -0,0 +1,51 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+ module Management
+ # Representation of a client connection. Properties include:
+ # - SystemConnection
+ # - address
+ # - authIdentity
+ # - bytesFromClient
+ # - bytesToClient
+ # - closing
+ # - federationLink
+ # - framesFromClient
+ # - framesToClient
+ # - incoming
+ # - msgsFromClient
+ # - msgsToClient
+ # - remoteParentPid
+ # - remotePid
+ # - remoteProcessName
+ # - remoteProperties
+ # - saslMechanism
+ # - saslSsf
+ # - shadow
+ # - userProxyAuth
+ # - vhostRef
+ class Connection < BrokerObject
+ # Closes this connection to the broker
+ def close
+ invoke_method('close', {}, "org.apache.qpid.broker:connection:#{address}")
+ end
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb
new file mode 100644
index 0000000000..b922cda680
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+ module Management
+ class ObjectNotFoundError < RuntimeError
+ end
+
+ class ObjectDeletedError < RuntimeError
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb
new file mode 100644
index 0000000000..5a3223aba6
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+ module Management
+ # Representation of an exchange. Properties include:
+ # - arguments
+ # - autoDelete
+ # - bindingCount
+ # - bindingCountHigh
+ # - bindingCountLow
+ # - byteDrops
+ # - byteReceives
+ # - byteRoutes
+ # - durable
+ # - msgDrops
+ # - msgReceives
+ # - msgRoutes
+ # - name
+ # - producerCount
+ # - producerCountHigh
+ # - producerCountLow
+ # - type
+ # - vhostRef
+ class Exchange < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb
new file mode 100644
index 0000000000..1ac9ea7a17
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb
@@ -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.
+#
+
+module Qpid
+ module Management
+ # Representation of an HA broker
+ class HaBroker < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb
new file mode 100644
index 0000000000..455b26a440
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb
@@ -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 Qpid
+ module Management
+ # Representation of a link to a remote broker. Properties include:
+ # - connectionRef
+ # - durable
+ # - host
+ # - lastError
+ # - name
+ # - port
+ # - state
+ # - transport
+ # - vhostRef
+ class Link < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb
new file mode 100644
index 0000000000..39dd803c9a
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+ module Management
+ # Representation of the broker's memory. Properties include:
+ # - malloc_arena
+ # - malloc_fordblks
+ # - malloc_hblkhd
+ # - malloc_hblks
+ # - malloc_keepcost
+ # - malloc_ordblks
+ # - malloc_uordblks
+ # - name
+ class Memory < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb
new file mode 100644
index 0000000000..c4fae3a53e
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb
@@ -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.
+#
+
+module Qpid
+ module Management
+ # Representation of a queue. Properties include:
+ # - acquires
+ # - arguments
+ # - autoDelete
+ # - bindingCount
+ # - bindingCountHigh
+ # - bindingCountLow
+ # - byteDepth
+ # - byteFtdDepth
+ # - byteFtdDequeues
+ # - byteFtdEnqueues
+ # - bytePersistDequeues
+ # - bytePersistEnqueues
+ # - byteTotalDequeues
+ # - byteTotalEnqueues
+ # - byteTxnDequeues
+ # - byteTxnEnqueues
+ # - consumerCount
+ # - consumerCountHigh
+ # - consumerCountLow
+ # - discardsLvq
+ # - discardsOverflow
+ # - discardsPurge
+ # - discardsRing
+ # - discardsSubscriber
+ # - discardsTtl
+ # - durable
+ # - exclusive
+ # - flowStopped
+ # - flowStoppedCount
+ # - messageLatencyAvg
+ # - messageLatencyCount
+ # - messageLatencyMax
+ # - messageLatencyMin
+ # - msgDepth
+ # - msgFtdDepth
+ # - msgFtdDequeues
+ # - msgFtdEnqueues
+ # - msgPersistDequeues
+ # - msgPersistEnqueues
+ # - msgTotalDequeues
+ # - msgTotalEnqueues
+ # - msgTxnDequeues
+ # - msgTxnEnqueues
+ # - name
+ # - releases
+ # - reroutes
+ # - unackedMessages
+ # - unackedMessagesHigh
+ # - unackedMessagesLow
+ # - vhostRef
+ class Queue < BrokerObject
+ # Purges (removes) messages from this queue
+ # @param [Fixnum] message_count number of messages to remove from the queue, or 0 for all messages
+ # @param [Hash] filter an optional filter to use when removing messages
+ def purge(message_count, filter={})
+ invoke_method('purge', {'request' => message_count, 'filter' => filter}, "org.apache.qpid.broker:queue:#{name}")
+ end
+
+ # Reroutes messages from this queue to an exchange, either the queue's
+ # alternate exchange, or the specified exchange
+ # @param [Fixnum] message_count number of messages to reroute from the queue, or 0 for all messages
+ # @param [Boolean] use_alternate_exchange whether to use the queue's alternate exchange as the destination
+ # @param [String] exchange name of destination exchange
+ # @param [Hash] filter an optional filter to use when rerouting messages
+ def reroute(message_count, use_alternate_exchange, exchange, filter)
+ args = {'request' => message_count,
+ 'useAltExchange' => use_alternate_exchange,
+ 'exchange' => exchange,
+ 'filter' => filter}
+
+ invoke_method('reroute', args, "org.apache.qpid.broker:queue:#{name}")
+ end
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb
new file mode 100644
index 0000000000..b4fcc7da59
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 Qpid
+ module Management
+ # Representation of a session to the broker. Properties include:
+ # - TxnCommits
+ # - TxnCount
+ # - TxnRejects
+ # - TxnStarts
+ # - attached
+ # - channelId
+ # - clientCredit
+ # - connectionRef
+ # - detachedLifespan
+ # - name
+ # - unackedMessages
+ # - vhostRef
+ class Session < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb
new file mode 100644
index 0000000000..fcff2831c0
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb
@@ -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 Qpid
+ module Management
+ # Representation of a subscription. Properties include:
+ # - acknowledged
+ # - arguments
+ # - browsing
+ # - creditMode
+ # - delivered
+ # - exclusive
+ # - name
+ # - queueRef
+ # - sessionRef
+ class Subscription < BrokerObject
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec b/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec
new file mode 100644
index 0000000000..a6cc1b828e
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec
@@ -0,0 +1,36 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+
+Gem::Specification.new do |s|
+ s.name = "qpid_management"
+ s.version = "1.0"
+ s.authors = ["Apache Qpid Project"]
+ s.email = ["dev@qpid.apache.org"]
+ s.homepage = "http://qpid.apache.org"
+ s.summary = %q{Qpid management library}
+ s.description = %q{Qpid management library}
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+ s.add_runtime_dependency 'qpid_messaging'
+end
diff --git a/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb b/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb
new file mode 100644
index 0000000000..7ffbf842e2
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 'spec_helper'
+
+describe Qpid::Management::BrokerAgent do
+ before(:each) do
+ @broker_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @connection = Qpid::Messaging::Connection.new(url:"localhost:#{@broker_port}")
+ @connection.open()
+ @agent = Qpid::Management::BrokerAgent.new(@connection)
+ end
+
+ after(:each) do
+ @agent.close()
+ @connection.close()
+ `qpidd -q --port #{@broker_port}`
+ end
+
+ describe '#broker' do
+ let(:broker) { @agent.broker }
+
+ it 'returns the broker' do
+ broker.class.should == Qpid::Management::Broker
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb b/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb
new file mode 100644
index 0000000000..6d6e1106a4
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb
@@ -0,0 +1,373 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 'spec_helper'
+
+describe Qpid::Management::Broker do
+ before(:each) do
+ @broker_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @connection = Qpid::Messaging::Connection.new(url:"localhost:#{@broker_port}")
+ @connection.open()
+ @agent = Qpid::Management::BrokerAgent.new(@connection)
+ @broker = @agent.broker
+ end
+
+ after(:each) do
+ @agent.close()
+ @connection.close()
+ `qpidd --quit --port #{@broker_port}`
+ end
+
+ def setup_queue_route
+ @other_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @broker.add_link('link1', 'localhost', @other_port)
+ @broker.add_queue('queue')
+ @broker.add_queue_route('qr1',
+ link: 'link1',
+ queue: 'queue',
+ exchange: 'amq.direct',
+ sync: 2)
+ end
+
+ %w(connection session subscription exchange queue binding link bridge).each do |type|
+ describe "##{type}s" do
+ before(:each) do
+ setup_queue_route if %w(link bridge).include?(type)
+ end
+
+ after(:each) do
+ if %w(link bridge).include?(type)
+ `qpidd --quit --port #{@other_port}`
+ end
+ end
+
+ let(:collection) { @broker.send("#{type}s") }
+
+ it "returns at least 1 #{type}" do
+ if type == 'subscription'
+ session = @connection.create_session
+ receiver = session.create_receiver("amq.direct/temp")
+ end
+ collection.count.should be > 0
+ end
+ end
+
+ describe "##{type}" do
+ before(:each) do
+ setup_queue_route if %w(link bridge).include?(type)
+ end
+
+ after(:each) do
+ if %w(link bridge).include?(type)
+ `qpidd --quit --port #{@other_port}`
+ end
+ end
+
+ let(:object) { @broker.send("#{type}s")[0] }
+
+ it "returns a #{type} by oid" do
+ if type == 'subscription'
+ session = @connection.create_session
+ receiver = session.create_receiver("amq.direct/temp")
+ end
+ @broker.send(type, object.short_id).id.should == object.id
+ end
+ end
+ end
+
+ describe '#add_exchange' do
+ %w(fanout direct topic headers).each do |type|
+ context "when adding a #{type} exchange" do
+ let(:exchange_name) { "#{type}1" }
+ before(:each) do
+ @before_creation = Time.now
+ @broker.add_exchange(type, exchange_name, {'qpid.replicate' => 'none'})
+ end
+
+ subject { @broker.exchange(exchange_name) }
+ its(:short_id) { should == exchange_name }
+ its(:type) { should == type }
+ its(:created_at) { should be > @before_creation }
+ it 'has the correct arguments' do
+ subject.arguments.should == {'qpid.replicate' => 'none'}
+ end
+ end
+ end
+ end
+
+ describe "#delete_exchange" do
+ before(:each) do
+ @before_creation = Time.now
+ @broker.add_exchange('fanout', 'fanout_to_delete')
+ end
+
+ let(:exchange) { @broker.exchange('fanout_to_delete') }
+
+ context "with a valid exchange name" do
+ it "deletes the exchange" do
+ @broker.delete_exchange(exchange.short_id)
+ expect { exchange.refresh! }.to raise_error
+ end
+ end
+
+ context "with an invalid exchange name" do
+ it "raises a not-found exception" do
+ expect { @broker.delete_exchange("badname") }.to raise_error(/not-found.*badname/)
+ end
+ end
+ end
+
+ describe "#add_queue" do
+ before(:each) do
+ @before_creation = Time.now
+ @queue_name = 'myqueue'
+ @broker.add_queue(@queue_name, {'qpid.replicate' => 'none'})
+ end
+
+ subject { @broker.queue(@queue_name) }
+ its(:short_id) { should == @queue_name }
+ its(:created_at) { should be > @before_creation }
+ it 'has the correct arguments' do
+ subject.arguments.should == {'qpid.replicate' => 'none'}
+ end
+ end
+
+ describe "#delete_queue" do
+ before(:each) do
+ @before_creation = Time.now
+ @broker.add_queue('queue_to_delete')
+ end
+
+ let(:queue) { @broker.queue('queue_to_delete') }
+
+ context "with a valid queue name" do
+ it "deletes the queue" do
+ @broker.delete_queue(queue.short_id)
+ expect { queue.refresh! }.to raise_error
+ end
+ end
+
+ context "with an invalid name" do
+ it "raises a not-found exception" do
+ expect { @broker.delete_queue("badname") }.to raise_error(/not-found.*badname/)
+ end
+ end
+ end
+
+ describe "#add_binding" do
+ before(:each) do
+ @broker.add_queue('queue')
+ end
+
+ it "creates a binding for a fanout exchange" do
+ @broker.add_exchange('fanout', 'fanout')
+ @broker.add_binding('fanout', 'queue')
+ expect { @broker.binding('org.apache.qpid.broker:exchange:fanout,org.apache.qpid.broker:queue:queue,') }.to_not raise_error
+ end
+
+ it "creates a binding for a direct exchange" do
+ @broker.add_exchange('direct', 'direct')
+ @broker.add_binding('direct', 'queue', 'mykey')
+ expect { @broker.binding('org.apache.qpid.broker:exchange:direct,org.apache.qpid.broker:queue:queue,mykey') }.to_not raise_error
+ end
+
+ it "creates a binding for a topic exchange" do
+ @broker.add_exchange('topic', 'topic')
+ @broker.add_binding('topic', 'queue', 'us.#')
+ expect { @broker.binding('org.apache.qpid.broker:exchange:topic,org.apache.qpid.broker:queue:queue,us.#') }.to_not raise_error
+ end
+ end
+
+ describe "#delete_binding" do
+ it "deletes an existing binding" do
+ @broker.add_queue('queue')
+ @broker.add_exchange('fanout', 'fanout')
+ @broker.add_binding('fanout', 'queue')
+ expect { @broker.delete_binding('fanout', 'queue') }.to_not raise_error
+ end
+ end
+
+ describe "#add_link" do
+ before(:each) do
+ @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ end
+
+ after(:each) do
+ `/usr/sbin/qpidd -q --port #{@other_port}`
+ end
+
+ it "adds a link" do
+ @broker.add_link('link1', 'localhost', @other_port)
+ @broker.links.count.should == 1
+ end
+ end
+
+ describe "#delete_link" do
+ before(:each) do
+ @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @broker.add_link('link1', 'localhost', @other_port)
+ end
+
+ after(:each) do
+ `/usr/sbin/qpidd -q --port #{@other_port}`
+ end
+
+ it "deletes a link" do
+ @broker.delete_link('link1')
+ @broker.links.count.should == 0
+ end
+ end
+
+ describe "#add_queue_route" do
+ context "with missing options" do
+ [:link, :queue, :exchange, :sync].each do |opt|
+ opts = {link: 'l', queue: 'q', exchange: 'e', sync:2}
+ opts.delete(opt)
+ it "raises an error when :#{opt} is missing" do
+ expect { @broker.add_queue_route('name', opts) }.to raise_error(/Option :#{opt} is required/)
+ end
+ end
+ end
+
+ context "with all required options" do
+ before(:each) do
+ @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @broker.add_link('link1', 'localhost', @other_port)
+ @broker.add_queue('queue')
+ @broker.add_queue_route('qr1',
+ link: 'link1',
+ queue: 'queue',
+ exchange: 'amq.direct',
+ sync: 2)
+ end
+
+ after(:each) do
+ `/usr/sbin/qpidd -q --port #{@other_port}`
+ end
+
+ it "adds a queue route" do
+ @broker.bridges.count.should == 1
+ end
+
+ subject { @broker.bridges[0] }
+ its(:dest) { should == 'amq.direct' }
+ its(:durable) { should == false }
+ its(:dynamic) { should == false }
+ its(:excludes) { should == "" }
+ its(:key) { should == "" }
+ its(:name) { should == "qr1" }
+ its(:src) { should == "queue" }
+ its(:srcIsLocal) { should == false }
+ its(:srcIsQueue) { should == true }
+ its(:sync) { should == 2 }
+ its(:tag) { should == "" }
+ end
+ end
+
+ describe "#add_exchange_route" do
+ context "with missing options" do
+ [:link, :exchange, :key, :sync].each do |opt|
+ opts = {link: 'l', exchange: 'e', key:'rk', sync:2}
+ opts.delete(opt)
+ it "raises an error when :#{opt} is missing" do
+ expect { @broker.add_exchange_route('name', opts) }.to raise_error(/Option :#{opt} is required/)
+ end
+ end
+ end
+
+ context "with all required options" do
+ before(:each) do
+ @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @broker.add_link('link1', 'localhost', @other_port)
+ @broker.add_queue('queue')
+ @broker.add_exchange_route('er1',
+ link: 'link1',
+ exchange: 'amq.direct',
+ key: 'foo',
+ sync: 2)
+ end
+
+ after(:each) do
+ `/usr/sbin/qpidd -q --port #{@other_port}`
+ end
+
+ it "adds an exchange route" do
+ @broker.bridges.count.should == 1
+ end
+
+ subject { @broker.bridges[0] }
+ its(:dest) { should == 'amq.direct' }
+ its(:durable) { should == false }
+ its(:dynamic) { should == false }
+ its(:excludes) { should == "" }
+ its(:key) { should == "foo" }
+ its(:name) { should == "er1" }
+ its(:src) { should == "amq.direct" }
+ its(:srcIsLocal) { should == false }
+ its(:srcIsQueue) { should == false }
+ its(:sync) { should == 2 }
+ its(:tag) { should == "" }
+ end
+ end
+
+ describe "#add_dynamic_route" do
+ context "with missing options" do
+ [:link, :exchange, :sync].each do |opt|
+ opts = {link: 'l', exchange: 'e', sync:2}
+ opts.delete(opt)
+ it "raises an error when :#{opt} is missing" do
+ expect { @broker.add_dynamic_route('name', opts) }.to raise_error(/Option :#{opt} is required/)
+ end
+ end
+ end
+
+ context "with all required options" do
+ before(:each) do
+ @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop
+ @broker.add_link('link1', 'localhost', @other_port)
+ @broker.add_queue('queue')
+ @broker.add_dynamic_route('dr1',
+ link: 'link1',
+ exchange: 'amq.direct',
+ sync: 2)
+ end
+
+ after(:each) do
+ `/usr/sbin/qpidd -q --port #{@other_port}`
+ end
+
+ it "adds an exchange route" do
+ @broker.bridges.count.should == 1
+ end
+
+ subject { @broker.bridges[0] }
+ its(:dest) { should == 'amq.direct' }
+ its(:durable) { should == false }
+ its(:dynamic) { should == true }
+ its(:excludes) { should == "" }
+ its(:key) { should == "" }
+ its(:name) { should == "dr1" }
+ its(:src) { should == "amq.direct" }
+ its(:srcIsLocal) { should == false }
+ its(:srcIsQueue) { should == false }
+ its(:sync) { should == 2 }
+ its(:tag) { should == "" }
+ end
+ end
+end
diff --git a/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb b/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb
new file mode 100644
index 0000000000..f552c55888
--- /dev/null
+++ b/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qpid_messaging'
+require 'qpid_management'