[qpid-cpp/f16] Rebased to sync with upstream's official 0.12 release
Nuno Santos
nsantos at fedoraproject.org
Tue Sep 20 21:30:06 UTC 2011
commit e691096e2187f1e4ebcb89adb41e3da98ba4fdeb
Author: Nuno Santos <nsantos at redhat.com>
Date: Tue Sep 20 17:29:39 2011 -0400
Rebased to sync with upstream's official 0.12 release
boost_filesystem_v2.patch | 11 -
boost_system.patch | 10 -
bootstrap.patch | 11 -
bz538355.patch | 239 -
db4.patch | 24 -
fedora.patch |18394 ++++-------------------------
mrg_1.3.x.patch |29603 ---------------------------------------------
mutable.patch | 13 -
qmf.patch | 121 -
qmf.rb.patch | 34 -
qpid-0.8-size_t.patch | 12 -
qpid-3159.patch | 29 -
qpid-cpp.spec | 84 +-
qpidd.patch | 10 -
qpidd.pp | Bin 23807 -> 0 bytes
so_number.patch | 11 -
sources | 4 +-
store-4411.patch | 118 -
store_1.3.x.patch | 1988 ---
swig.patch | 25 -
xqilla.patch | 67 -
21 files changed, 2194 insertions(+), 48614 deletions(-)
---
diff --git a/fedora.patch b/fedora.patch
index 80c8bf1..8172f66 100644
--- a/fedora.patch
+++ b/fedora.patch
@@ -1,367 +1,750 @@
-Index: cpp/src/qmf/Agent.cpp
-===================================================================
---- cpp/src/qmf/Agent.cpp (revision 1056407)
-+++ cpp/src/qmf/Agent.cpp (working copy)
-@@ -27,6 +27,7 @@
- #include "qmf/Query.h"
- #include "qmf/SchemaImpl.h"
- #include "qmf/agentCapability.h"
-+#include "qmf/constants.h"
- #include "qpid/messaging/Sender.h"
- #include "qpid/messaging/AddressParser.h"
- #include "qpid/management/Buffer.h"
-@@ -70,8 +71,8 @@
-
+From 00d9b16761b7f237c6b1418995cc9367aebac0f5 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Tue, 12 Jul 2011 11:49:32 +0000
+Subject: [PATCH 01/14] QPID-3275 - QMF Console asynchronous correlation-id
+ should be scoped to the session, not the specific
+ agent
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1145557 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/src/qmf/Agent.cpp | 29 ++++++-----------------------
+ qpid/cpp/src/qmf/AgentImpl.h | 1 -
+ qpid/cpp/src/qmf/ConsoleSession.cpp | 2 +-
+ qpid/cpp/src/qmf/ConsoleSessionImpl.h | 3 +++
+ 4 files changed, 10 insertions(+), 25 deletions(-)
+
+diff --git a/qpid/cpp/src/qmf/Agent.cpp b/qpid/cpp/src/qmf/Agent.cpp
+index 915f2a1..684f8e4 100644
+--- a/qpid/cpp/src/qmf/Agent.cpp
++++ b/qpid/cpp/src/qmf/Agent.cpp
+@@ -72,7 +72,7 @@ Schema Agent::getSchema(const SchemaId& s, Duration t) { return impl->getSchema(
AgentImpl::AgentImpl(const std::string& n, uint32_t e, ConsoleSessionImpl& s) :
-- name(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0),
-- nextCorrelator(1), schemaCache(s.schemaCache)
-+ name(n), directSubject(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0),
-+ sender(session.directSender), nextCorrelator(1), schemaCache(s.schemaCache)
+ name(n), directSubject(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0),
+- sender(session.directSender), nextCorrelator(1), schemaCache(s.schemaCache)
++ sender(session.directSender), schemaCache(s.schemaCache)
{
}
-@@ -82,6 +83,11 @@
- try {
- capability = v.asUint32();
- } catch (std::exception&) {}
-+ if (k == "_direct_subject")
-+ try {
-+ directSubject = v.asString();
-+ sender = session.topicSender;
-+ } catch (std::exception&) {}
- }
+@@ -102,12 +102,11 @@ const Variant& AgentImpl::getAttribute(const string& k) const
+ ConsoleEvent AgentImpl::query(const Query& query, Duration timeout)
+ {
+ boost::shared_ptr<SyncContext> context(new SyncContext());
+- uint32_t correlator;
++ uint32_t correlator(session.correlator());
+ ConsoleEvent result;
+
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+- correlator = nextCorrelator++;
+ contextMap[correlator] = context;
+ }
+ try {
+@@ -151,12 +150,7 @@ ConsoleEvent AgentImpl::query(const string& text, Duration timeout)
- const Variant& AgentImpl::getAttribute(const string& k) const
-@@ -113,7 +119,9 @@
- context->cond.wait(context->lock,
- qpid::sys::AbsTime(qpid::sys::now(),
- qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
-- if (context->response.isValid() && context->response.isFinal())
-+ if (context->response.isValid() &&
-+ ((context->response.getType() == CONSOLE_QUERY_RESPONSE && context->response.isFinal()) ||
-+ (context->response.getType() == CONSOLE_EXCEPTION)))
- result = context->response;
- else {
- auto_ptr<ConsoleEventImpl> impl(new ConsoleEventImpl(CONSOLE_EXCEPTION));
-@@ -331,7 +339,7 @@
- uint32_t correlator;
- boost::shared_ptr<SyncContext> context;
+ uint32_t AgentImpl::queryAsync(const Query& query)
+ {
+- uint32_t correlator;
+-
+- {
+- qpid::sys::Mutex::ScopedLock l(lock);
+- correlator = nextCorrelator++;
+- }
++ uint32_t correlator(session.correlator());
+
+ sendQuery(query, correlator);
+ return correlator;
+@@ -172,12 +166,11 @@ uint32_t AgentImpl::queryAsync(const string& text)
+ ConsoleEvent AgentImpl::callMethod(const string& method, const Variant::Map& args, const DataAddr& addr, Duration timeout)
+ {
+ boost::shared_ptr<SyncContext> context(new SyncContext());
+- uint32_t correlator;
++ uint32_t correlator(session.correlator());
+ ConsoleEvent result;
-- QPID_LOG(trace, "RCVD MethodResponse map=" << response);
-+ QPID_LOG(trace, "RCVD MethodResponse cid=" << cid << " map=" << response);
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+- correlator = nextCorrelator++;
+ contextMap[correlator] = context;
+ }
+ try {
+@@ -213,12 +206,7 @@ ConsoleEvent AgentImpl::callMethod(const string& method, const Variant::Map& arg
- aIter = response.find("_arguments");
- if (aIter != response.end())
-@@ -369,9 +377,43 @@
- }
+ uint32_t AgentImpl::callMethodAsync(const string& method, const Variant::Map& args, const DataAddr& addr)
+ {
+- uint32_t correlator;
+-
+- {
+- qpid::sys::Mutex::ScopedLock l(lock);
+- correlator = nextCorrelator++;
+- }
++ uint32_t correlator(session.correlator());
+ sendMethod(method, args, addr, correlator);
+ return correlator;
+@@ -596,12 +584,7 @@ void AgentImpl::sendMethod(const string& method, const Variant::Map& args, const
--void AgentImpl::handleDataIndication(const Variant::List&, const Message&)
-+void AgentImpl::handleDataIndication(const Variant::List& list, const Message& msg)
+ void AgentImpl::sendSchemaRequest(const SchemaId& id)
{
-- // TODO
-+ Variant::Map::const_iterator aIter;
-+ const Variant::Map& props(msg.getProperties());
-+ boost::shared_ptr<SyncContext> context;
-+
-+ aIter = props.find("qmf.content");
-+ if (aIter == props.end())
-+ return;
-+
-+ string content_type(aIter->second.asString());
-+ if (content_type != "_event")
-+ return;
+- uint32_t correlator;
+-
+- {
+- qpid::sys::Mutex::ScopedLock l(lock);
+- correlator = nextCorrelator++;
+- }
++ uint32_t correlator(session.correlator());
+
+ if (capability >= AGENT_CAPABILITY_V2_SCHEMA) {
+ Query query(QUERY_SCHEMA, id);
+diff --git a/qpid/cpp/src/qmf/AgentImpl.h b/qpid/cpp/src/qmf/AgentImpl.h
+index 7fa4f43..09754a3 100644
+--- a/qpid/cpp/src/qmf/AgentImpl.h
++++ b/qpid/cpp/src/qmf/AgentImpl.h
+@@ -99,7 +99,6 @@ namespace qmf {
+ uint32_t capability;
+ qpid::messaging::Sender sender;
+ qpid::types::Variant::Map attributes;
+- uint32_t nextCorrelator;
+ std::map<uint32_t, boost::shared_ptr<SyncContext> > contextMap;
+ boost::shared_ptr<SchemaCache> schemaCache;
+ mutable std::set<std::string> packageSet;
+diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
+index 5df0d83..7b51d80 100644
+--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
++++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
+@@ -68,7 +68,7 @@ Subscription ConsoleSession::subscribe(const string& q, const string& f, const s
+ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
+ connection(c), domain("default"), maxAgentAgeMinutes(5), listenOnDirect(true), strictSecurity(false),
+ opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
+- connectedBrokerInAgentList(false), schemaCache(new SchemaCache())
++ connectedBrokerInAgentList(false), schemaCache(new SchemaCache()), nextCorrelator(1)
+ {
+ if (!options.empty()) {
+ qpid::messaging::AddressParser parser(options);
+diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+index 411b3f0..429dfc4 100644
+--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
++++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+@@ -90,6 +90,8 @@ namespace qmf {
+ std::string directBase;
+ std::string topicBase;
+ boost::shared_ptr<SchemaCache> schemaCache;
++ qpid::sys::Mutex corrlock;
++ uint32_t nextCorrelator;
+
+ void enqueueEvent(const ConsoleEvent&);
+ void enqueueEventLH(const ConsoleEvent&);
+@@ -100,6 +102,7 @@ namespace qmf {
+ void handleV1SchemaResponse(qpid::management::Buffer&, uint32_t, const qpid::messaging::Message&);
+ void periodicProcessing(uint64_t);
+ void run();
++ uint32_t correlator() { qpid::sys::Mutex::ScopedLock l(corrlock); return nextCorrelator++; }
+
+ friend class AgentImpl;
+ };
+--
+1.7.4.4
+
+From 40738a2501f8bfe2f85e1d26790584ce034bd930 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Tue, 12 Jul 2011 16:11:34 +0000
+Subject: [PATCH 02/14] QPID-3344 - Comparisons of const DataAddr objects are
+ incorrect Applied patch from Zane Bitter
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1145644 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/include/qmf/DataAddr.h | 3 +++
+ qpid/cpp/src/qmf/DataAddr.cpp | 6 ++++--
+ qpid/cpp/src/qmf/DataAddrImpl.h | 4 ++--
+ qpid/cpp/src/qpid/store/StorageProvider.h | 2 +-
+ 4 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/qpid/cpp/include/qmf/DataAddr.h b/qpid/cpp/include/qmf/DataAddr.h
+index 63d309c..20c4690 100644
+--- a/qpid/cpp/include/qmf/DataAddr.h
++++ b/qpid/cpp/include/qmf/DataAddr.h
+@@ -51,6 +51,9 @@ namespace qmf {
+ QMF_EXTERN uint32_t getAgentEpoch() const;
+ QMF_EXTERN qpid::types::Variant::Map asMap() const;
+
++ QMF_EXTERN bool operator==(const DataAddr&) const;
++ QMF_EXTERN bool operator<(const DataAddr&) const;
+
-+ for (Variant::List::const_iterator lIter = list.begin(); lIter != list.end(); lIter++) {
-+ const Variant::Map& eventMap(lIter->asMap());
-+ Data data(new DataImpl(eventMap, this));
-+ int severity(SEV_NOTICE);
-+ uint64_t timestamp(0);
+ #ifndef SWIG
+ private:
+ friend class qmf::PrivateImplRef<DataAddr>;
+diff --git a/qpid/cpp/src/qmf/DataAddr.cpp b/qpid/cpp/src/qmf/DataAddr.cpp
+index fb51d57..d16e120 100644
+--- a/qpid/cpp/src/qmf/DataAddr.cpp
++++ b/qpid/cpp/src/qmf/DataAddr.cpp
+@@ -36,7 +36,9 @@ DataAddr::~DataAddr() { PI::dtor(*this); }
+ DataAddr& DataAddr::operator=(const DataAddr& s) { return PI::assign(*this, s); }
+
+ bool DataAddr::operator==(const DataAddr& o) { return *impl == *o.impl; }
++bool DataAddr::operator==(const DataAddr& o) const { return *impl == *o.impl; }
+ bool DataAddr::operator<(const DataAddr& o) { return *impl < *o.impl; }
++bool DataAddr::operator<(const DataAddr& o) const { return *impl < *o.impl; }
+
+ DataAddr::DataAddr(const qpid::types::Variant::Map& m) { PI::ctor(*this, new DataAddrImpl(m)); }
+ DataAddr::DataAddr(const string& n, const string& a, uint32_t e) { PI::ctor(*this, new DataAddrImpl(n, a, e)); }
+@@ -45,7 +47,7 @@ const string& DataAddr::getAgentName() const { return impl->getAgentName(); }
+ uint32_t DataAddr::getAgentEpoch() const { return impl->getAgentEpoch(); }
+ Variant::Map DataAddr::asMap() const { return impl->asMap(); }
+
+-bool DataAddrImpl::operator==(const DataAddrImpl& other)
++bool DataAddrImpl::operator==(const DataAddrImpl& other) const
+ {
+ return
+ agentName == other.agentName &&
+@@ -54,7 +56,7 @@ bool DataAddrImpl::operator==(const DataAddrImpl& other)
+ }
+
+
+-bool DataAddrImpl::operator<(const DataAddrImpl& other)
++bool DataAddrImpl::operator<(const DataAddrImpl& other) const
+ {
+ if (agentName < other.agentName) return true;
+ if (agentName > other.agentName) return false;
+diff --git a/qpid/cpp/src/qmf/DataAddrImpl.h b/qpid/cpp/src/qmf/DataAddrImpl.h
+index 3f9cae9..11d512f 100644
+--- a/qpid/cpp/src/qmf/DataAddrImpl.h
++++ b/qpid/cpp/src/qmf/DataAddrImpl.h
+@@ -38,8 +38,8 @@ namespace qmf {
+ //
+ // Methods from API handle
+ //
+- bool operator==(const DataAddrImpl&);
+- bool operator<(const DataAddrImpl&);
++ bool operator==(const DataAddrImpl&) const;
++ bool operator<(const DataAddrImpl&) const;
+ DataAddrImpl(const qpid::types::Variant::Map&);
+ DataAddrImpl(const std::string& _name, const std::string& _agentName, uint32_t _agentEpoch=0) :
+ agentName(_agentName), name(_name), agentEpoch(_agentEpoch) {}
+diff --git a/qpid/cpp/src/qpid/store/StorageProvider.h b/qpid/cpp/src/qpid/store/StorageProvider.h
+index bc8d187..d162cc5 100644
+--- a/qpid/cpp/src/qpid/store/StorageProvider.h
++++ b/qpid/cpp/src/qpid/store/StorageProvider.h
+@@ -54,7 +54,7 @@ struct QueueEntry {
+ QueueEntry(uint64_t id, TplStatus tpl = NONE, const std::string& x = "")
+ : queueId(id), tplStatus(tpl), xid(x) {}
+
+- bool operator==(const QueueEntry& rhs) {
++ bool operator==(const QueueEntry& rhs) const {
+ if (queueId != rhs.queueId) return false;
+ if (tplStatus == NONE && rhs.tplStatus == NONE) return true;
+ return xid == rhs.xid;
+--
+1.7.4.4
+
+From e2257aece703af5d775b087440958e19702b92a0 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Fri, 5 Aug 2011 15:24:16 +0000
+Subject: [PATCH 03/14] NO-JIRA - Added missing template file in distribution.
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1154264 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/managementgen/Makefile.am | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/qpid/cpp/managementgen/Makefile.am b/qpid/cpp/managementgen/Makefile.am
+index e10dd63..4fc5edc 100644
+--- a/qpid/cpp/managementgen/Makefile.am
++++ b/qpid/cpp/managementgen/Makefile.am
+@@ -32,6 +32,7 @@ pkgpyexec_qmfgentmpl_PYTHON = \
+ qmfgen/templates/Args.h \
+ qmfgen/templates/Class.cpp \
+ qmfgen/templates/Class.h \
++ qmfgen/templates/CMakeLists.cmake \
+ qmfgen/templates/Event.cpp \
+ qmfgen/templates/Event.h \
+ qmfgen/templates/Makefile.mk \
+--
+1.7.4.4
+
+From f654585bacf244e33cdb5a8a1ece6c15b18ecdc1 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Mon, 15 Aug 2011 16:47:56 +0000
+Subject: [PATCH 04/14] QPID-3423 - Timing and Performance Improvements in QMF
+ Libraries
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1157907 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/include/qmf/AgentSession.h | 5 +++
+ qpid/cpp/include/qmf/ConsoleSession.h | 4 ++
+ qpid/cpp/src/qmf/AgentSession.cpp | 41 ++++++++++++++++------
+ qpid/cpp/src/qmf/ConsoleSession.cpp | 43 ++++++++++++++++-------
+ qpid/cpp/src/qmf/ConsoleSessionImpl.h | 1 +
+ qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp | 19 ++++++++--
+ 6 files changed, 86 insertions(+), 27 deletions(-)
+
+diff --git a/qpid/cpp/include/qmf/AgentSession.h b/qpid/cpp/include/qmf/AgentSession.h
+index 1eeb252..5ecfb04 100644
+--- a/qpid/cpp/include/qmf/AgentSession.h
++++ b/qpid/cpp/include/qmf/AgentSession.h
+@@ -71,6 +71,11 @@ namespace qmf {
+ * If False: Listen only on the routable direct address
+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
++ * max-thread-wait-time:N - Time (in seconds) the session thread will wait for messages from the network between
++ * periodic background processing passes. [default: 5]
++ * Must not be greater than 'interval'. Larger numbers will cause fewer wake-ups but will
++ * increase the time it takes to shut down the process. This setting will not affect the
++ * agent's response time for queries or method invocation.
+ */
+ QMF_EXTERN AgentSession(qpid::messaging::Connection& conn, const std::string& options="");
+
+diff --git a/qpid/cpp/include/qmf/ConsoleSession.h b/qpid/cpp/include/qmf/ConsoleSession.h
+index 6008036..5e3a091 100644
+--- a/qpid/cpp/include/qmf/ConsoleSession.h
++++ b/qpid/cpp/include/qmf/ConsoleSession.h
+@@ -61,6 +61,10 @@ namespace qmf {
+ * If False: Listen only on the routable direct address
+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
++ * max-thread-wait-time:N - Time (in seconds) the session thread will wait for messages from the network between
++ * periodic background processing passes.
++ * Must not be greater than 60. Larger numbers will cause fewer wake-ups but will
++ * increase the time it takes to shut down the process. [default: 5]
+ */
+ QMF_EXTERN ConsoleSession(qpid::messaging::Connection& conn, const std::string& options="");
+
+diff --git a/qpid/cpp/src/qmf/AgentSession.cpp b/qpid/cpp/src/qmf/AgentSession.cpp
+index 71d3693..a88782d 100644
+--- a/qpid/cpp/src/qmf/AgentSession.cpp
++++ b/qpid/cpp/src/qmf/AgentSession.cpp
+@@ -120,6 +120,7 @@ namespace qmf {
+ bool publicEvents;
+ bool listenOnDirect;
+ bool strictSecurity;
++ uint32_t maxThreadWaitTime;
+ uint64_t schemaUpdateTime;
+ string directBase;
+ string topicBase;
+@@ -185,7 +186,7 @@ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) :
+ bootSequence(1), interval(60), lastHeartbeat(0), lastVisit(0), forceHeartbeat(false),
+ externalStorage(false), autoAllowQueries(true), autoAllowMethods(true),
+ maxSubscriptions(64), minSubInterval(3000), subLifetime(300), publicEvents(true),
+- listenOnDirect(true), strictSecurity(false),
++ listenOnDirect(true), strictSecurity(false), maxThreadWaitTime(5),
+ schemaUpdateTime(uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now())))
+ {
+ //
+@@ -246,7 +247,14 @@ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) :
+ iter = optMap.find("strict-security");
+ if (iter != optMap.end())
+ strictSecurity = iter->second.asBool();
+
-+ aIter = eventMap.find("_severity");
-+ if (aIter != eventMap.end())
-+ severity = int(aIter->second.asInt8());
++ iter = optMap.find("max-thread-wait-time");
++ if (iter != optMap.end())
++ maxThreadWaitTime = iter->second.asUint32();
+ }
+
-+ aIter = eventMap.find("_timestamp");
-+ if (aIter != eventMap.end())
-+ timestamp = aIter->second.asUint64();
++ if (maxThreadWaitTime > interval)
++ maxThreadWaitTime = interval;
+ }
+
+
+@@ -254,6 +262,11 @@ AgentSessionImpl::~AgentSessionImpl()
+ {
+ if (opened)
+ close();
+
-+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_EVENT));
-+ eventImpl->setAgent(this);
-+ eventImpl->addData(data);
-+ eventImpl->setSeverity(severity);
-+ eventImpl->setTimestamp(timestamp);
-+ if (data.hasSchema())
-+ learnSchemaId(data.getSchemaId());
-+ session.enqueueEvent(eventImpl.release());
++ if (thread) {
++ thread->join();
++ delete thread;
+ }
}
-@@ -507,17 +549,21 @@
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
+@@ -262,6 +275,12 @@ void AgentSessionImpl::open()
+ if (opened)
+ throw QmfException("The session is already open");
-- headers["method"] = "request";
-- headers["qmf.opcode"] = "_query_request";
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_REQUEST;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_QUERY_REQUEST;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
++ // If the thread exists, join and delete it before creating a new one.
++ if (thread) {
++ thread->join();
++ delete thread;
++ }
++
+ const string addrArgs(";{create:never,node:{type:topic}}");
+ const string routableAddr("direct-agent.route." + qpid::types::Uuid(true).str());
+ attributes["_direct_subject"] = routableAddr;
+@@ -304,13 +323,8 @@ void AgentSessionImpl::close()
+ if (!opened)
+ return;
- msg.setReplyTo(session.replyAddress);
- msg.setCorrelationId(boost::lexical_cast<string>(correlator));
-- msg.setSubject(name);
-+ msg.setSubject(directSubject);
-+ string userId(session.connection.getAuthenticatedUsername());
-+ if (!userId.empty())
-+ msg.setUserId(userId);
- encode(QueryImplAccess::get(query).asMap(), msg);
-- session.directSender.send(msg);
+- // Stop and join the receiver thread
++ // Stop the receiver thread. Don't join it until the destructor is called or open() is called.
+ threadCanceled = true;
+- thread->join();
+- delete thread;
-
-- QPID_LOG(trace, "SENT QueryRequest to=" << name);
-+ if (sender.isValid()) {
-+ sender.send(msg);
-+ QPID_LOG(trace, "SENT QueryRequest to=" << sender.getName() << "/" << directSubject << " cid=" << correlator);
-+ }
+- // Close the AMQP session
+- session.close();
+ opened = false;
}
+@@ -320,9 +334,13 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout)
+ uint64_t milliseconds = timeout.getMilliseconds();
+ qpid::sys::Mutex::ScopedLock l(lock);
-@@ -527,9 +573,9 @@
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
+- if (eventQueue.empty() && milliseconds > 0)
+- cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(),
+- qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
++ if (eventQueue.empty() && milliseconds > 0) {
++ int64_t nsecs(qpid::sys::TIME_INFINITE);
++ if ((uint64_t)(nsecs / 1000000) > milliseconds)
++ nsecs = (int64_t) milliseconds * 1000000;
++ qpid::sys::Duration then(nsecs);
++ cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), then));
++ }
-- headers["method"] = "request";
-- headers["qmf.opcode"] = "_method_request";
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_REQUEST;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_METHOD_REQUEST;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
+ if (!eventQueue.empty()) {
+ event = eventQueue.front();
+@@ -1050,7 +1068,7 @@ void AgentSessionImpl::run()
+ periodicProcessing((uint64_t) qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()) / qpid::sys::TIME_SEC);
+
+ Receiver rx;
+- bool valid = session.nextReceiver(rx, Duration::SECOND);
++ bool valid = session.nextReceiver(rx, Duration::SECOND * maxThreadWaitTime);
+ if (threadCanceled)
+ break;
+ if (valid) {
+@@ -1067,6 +1085,7 @@ void AgentSessionImpl::run()
+ enqueueEvent(AgentEvent(new AgentEventImpl(AGENT_THREAD_FAILED)));
+ }
- map["_method_name"] = method;
- map["_object_id"] = addr.asMap();
-@@ -537,11 +583,15 @@
++ session.close();
+ QPID_LOG(debug, "AgentSession thread exiting for agent " << agentName);
+ }
- msg.setReplyTo(session.replyAddress);
- msg.setCorrelationId(boost::lexical_cast<string>(correlator));
-- msg.setSubject(name);
-+ msg.setSubject(directSubject);
-+ string userId(session.connection.getAuthenticatedUsername());
-+ if (!userId.empty())
-+ msg.setUserId(userId);
- encode(map, msg);
-- session.directSender.send(msg);
--
-- QPID_LOG(trace, "SENT MethodRequest method=" << method << " to=" << name);
-+ if (sender.isValid()) {
-+ sender.send(msg);
-+ QPID_LOG(trace, "SENT MethodRequest method=" << method << " to=" << sender.getName() << "/" << directSubject << " content=" << map << " cid=" << correlator);
+diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
+index 7b51d80..af83595 100644
+--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
++++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
+@@ -66,7 +66,7 @@ Subscription ConsoleSession::subscribe(const string& q, const string& f, const s
+ //========================================================================================
+
+ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
+- connection(c), domain("default"), maxAgentAgeMinutes(5), listenOnDirect(true), strictSecurity(false),
++ connection(c), domain("default"), maxAgentAgeMinutes(5), listenOnDirect(true), strictSecurity(false), maxThreadWaitTime(5),
+ opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
+ connectedBrokerInAgentList(false), schemaCache(new SchemaCache()), nextCorrelator(1)
+ {
+@@ -92,7 +92,14 @@ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
+ iter = optMap.find("strict-security");
+ if (iter != optMap.end())
+ strictSecurity = iter->second.asBool();
++
++ iter = optMap.find("max-thread-wait-time");
++ if (iter != optMap.end())
++ maxThreadWaitTime = iter->second.asUint32();
+ }
++
++ if (maxThreadWaitTime > 60)
++ maxThreadWaitTime = 60;
+ }
+
+
+@@ -100,6 +107,11 @@ ConsoleSessionImpl::~ConsoleSessionImpl()
+ {
+ if (opened)
+ close();
++
++ if (thread) {
++ thread->join();
++ delete thread;
+ }
}
- void AgentImpl::sendSchemaRequest(const SchemaId& id)
-@@ -577,10 +627,14 @@
- Message msg;
- msg.setReplyTo(session.replyAddress);
- msg.setContent(content);
-- msg.setSubject(name);
-- session.directSender.send(msg);
--
-- QPID_LOG(trace, "SENT V1SchemaRequest to=" << name);
-+ msg.setSubject(directSubject);
-+ string userId(session.connection.getAuthenticatedUsername());
-+ if (!userId.empty())
-+ msg.setUserId(userId);
-+ if (sender.isValid()) {
-+ sender.send(msg);
-+ QPID_LOG(trace, "SENT V1SchemaRequest to=" << sender.getName() << "/" << directSubject);
+
+@@ -154,6 +166,12 @@ void ConsoleSessionImpl::open()
+ if (opened)
+ throw QmfException("The session is already open");
+
++ // If the thread exists, join and delete it before creating a new one.
++ if (thread) {
++ thread->join();
++ delete thread;
+ }
++
+ // Establish messaging addresses
+ directBase = "qmf." + domain + ".direct";
+ topicBase = "qmf." + domain + ".topic";
+@@ -182,14 +200,13 @@ void ConsoleSessionImpl::open()
+
+ // Start the receiver thread
+ threadCanceled = false;
++ opened = true;
+ thread = new qpid::sys::Thread(*this);
+
+ // Send an agent_locate to direct address 'broker' to identify the connected-broker-agent.
+ sendBrokerLocate();
+ if (agentQuery)
+ sendAgentLocate();
+-
+- opened = true;
}
-Index: cpp/src/qmf/Schema.cpp
-===================================================================
---- cpp/src/qmf/Schema.cpp (revision 1056407)
-+++ cpp/src/qmf/Schema.cpp (working copy)
-@@ -192,6 +192,55 @@
+@@ -198,13 +215,8 @@ void ConsoleSessionImpl::close()
+ if (!opened)
+ throw QmfException("The session is already closed");
+
+- // Stop and join the receiver thread
++ // Stop the receiver thread. Don't join it until the destructor is called or open() is called.
+ threadCanceled = true;
+- thread->join();
+- delete thread;
+-
+- // Close the AMQP session
+- session.close();
+ opened = false;
}
+@@ -214,9 +226,13 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout)
+ uint64_t milliseconds = timeout.getMilliseconds();
+ qpid::sys::Mutex::ScopedLock l(lock);
-+bool SchemaImpl::isValidProperty(const std::string& k, const Variant& v) const
-+{
-+ for (list<SchemaProperty>::const_iterator iter = properties.begin(); iter != properties.end(); iter++)
-+ if (iter->getName() == k)
-+ return (isCompatibleType(iter->getType(), v.getType()));
-+ return false;
-+}
-+
-+
-+bool SchemaImpl::isValidMethodInArg(const std::string& m, const std::string& k, const Variant& v) const
-+{
-+ for (list<SchemaMethod>::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) {
-+ if (mIter->getName() == m) {
-+ uint32_t count(mIter->getArgumentCount());
-+ for (uint32_t i = 0; i < count; i++) {
-+ const SchemaProperty prop(mIter->getArgument(i));
-+ if (prop.getName() == k) {
-+ if (prop.getDirection() == DIR_IN || prop.getDirection() == DIR_IN_OUT)
-+ return (isCompatibleType(prop.getType(), v.getType()));
-+ else
-+ return false;
-+ }
-+ }
-+ }
-+ }
-+ return false;
-+}
-+
-+
-+bool SchemaImpl::isValidMethodOutArg(const std::string& m, const std::string& k, const Variant& v) const
-+{
-+ for (list<SchemaMethod>::const_iterator mIter = methods.begin(); mIter != methods.end(); mIter++) {
-+ if (mIter->getName() == m) {
-+ uint32_t count(mIter->getArgumentCount());
-+ for (uint32_t i = 0; i < count; i++) {
-+ const SchemaProperty prop(mIter->getArgument(i));
-+ if (prop.getName() == k) {
-+ if (prop.getDirection() == DIR_OUT || prop.getDirection() == DIR_IN_OUT)
-+ return (isCompatibleType(prop.getType(), v.getType()));
-+ else
-+ return false;
-+ }
-+ }
-+ }
+- if (eventQueue.empty() && milliseconds > 0)
+- cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(),
+- qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC)));
++ if (eventQueue.empty() && milliseconds > 0) {
++ int64_t nsecs(qpid::sys::TIME_INFINITE);
++ if ((uint64_t)(nsecs / 1000000) > milliseconds)
++ nsecs = (int64_t) milliseconds * 1000000;
++ qpid::sys::Duration then(nsecs);
++ cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), then));
+ }
-+ return false;
-+}
-+
-+
- void SchemaImpl::finalize()
- {
- Hash hash;
-@@ -246,6 +295,57 @@
+
+ if (!eventQueue.empty()) {
+ event = eventQueue.front();
+@@ -596,7 +612,7 @@ void ConsoleSessionImpl::run()
+ qpid::sys::TIME_SEC);
+
+ Receiver rx;
+- bool valid = session.nextReceiver(rx, Duration::SECOND);
++ bool valid = session.nextReceiver(rx, Duration::SECOND * maxThreadWaitTime);
+ if (threadCanceled)
+ break;
+ if (valid) {
+@@ -613,6 +629,7 @@ void ConsoleSessionImpl::run()
+ enqueueEvent(ConsoleEvent(new ConsoleEventImpl(CONSOLE_THREAD_FAILED)));
+ }
+
++ session.close();
+ QPID_LOG(debug, "ConsoleSession thread exiting");
}
+diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+index 429dfc4..478d24e 100644
+--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
++++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+@@ -76,6 +76,7 @@ namespace qmf {
+ uint32_t maxAgentAgeMinutes;
+ bool listenOnDirect;
+ bool strictSecurity;
++ uint32_t maxThreadWaitTime;
+ Query agentQuery;
+ bool opened;
+ std::queue<ConsoleEvent> eventQueue;
+diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+index 633401e..f183ff8 100644
+--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
++++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+@@ -1378,13 +1378,26 @@ bool ManagementAgentImpl::ConnectionThread::isSleeping() const
+
+ void ManagementAgentImpl::PublishThread::run()
+ {
+- uint16_t totalSleep;
++ uint16_t totalSleep;
++ uint16_t sleepTime;
-+bool SchemaImpl::isCompatibleType(int qmfType, qpid::types::VariantType qpidType) const
-+{
-+ bool typeValid(false);
-+
-+ switch (qpidType) {
-+ case qpid::types::VAR_VOID:
-+ if (qmfType == SCHEMA_DATA_VOID)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_BOOL:
-+ if (qmfType == SCHEMA_DATA_BOOL)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_UINT8:
-+ case qpid::types::VAR_UINT16:
-+ case qpid::types::VAR_UINT32:
-+ case qpid::types::VAR_UINT64:
-+ case qpid::types::VAR_INT8:
-+ case qpid::types::VAR_INT16:
-+ case qpid::types::VAR_INT32:
-+ case qpid::types::VAR_INT64:
-+ if (qmfType == SCHEMA_DATA_INT)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_FLOAT:
-+ case qpid::types::VAR_DOUBLE:
-+ if (qmfType == SCHEMA_DATA_FLOAT)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_STRING:
-+ if (qmfType == SCHEMA_DATA_STRING)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_MAP:
-+ if (qmfType == SCHEMA_DATA_MAP)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_LIST:
-+ if (qmfType == SCHEMA_DATA_LIST)
-+ typeValid = true;
-+ break;
-+ case qpid::types::VAR_UUID:
-+ if (qmfType == SCHEMA_DATA_UUID)
-+ typeValid = true;
-+ break;
-+ }
-+
-+ return typeValid;
-+}
-+
+ while (!shutdown) {
+ agent.periodicProcessing();
+ totalSleep = 0;
+- while (totalSleep++ < agent.getInterval() && !shutdown) {
+- ::sleep(1);
+
- SchemaImpl& SchemaImplAccess::get(Schema& item)
++ //
++ // Calculate a sleep time that is no greater than 5 seconds and
++ // no less than 1 second.
++ //
++ sleepTime = agent.getInterval();
++ if (sleepTime > 5)
++ sleepTime = 5;
++ else if (sleepTime == 0)
++ sleepTime = 1;
++
++ while (totalSleep < agent.getInterval() && !shutdown) {
++ ::sleep(sleepTime);
++ totalSleep += sleepTime;
+ }
+ }
+ }
+--
+1.7.4.4
+
+From 6ca9eda32ed8c809524b913dd169afa4a35eb58d Mon Sep 17 00:00:00 2001
+From: Ted Ross <ross at localhost.localdomain>
+Date: Mon, 15 Aug 2011 16:25:52 -0400
+Subject: [PATCH 05/14] Fixed EXTERN definitions
+
+---
+ qpid/cpp/include/qpid/framing/FieldTable.h | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/qpid/cpp/include/qpid/framing/FieldTable.h b/qpid/cpp/include/qpid/framing/FieldTable.h
+index e8ec524..bdcef6d 100644
+--- a/qpid/cpp/include/qpid/framing/FieldTable.h
++++ b/qpid/cpp/include/qpid/framing/FieldTable.h
+@@ -65,8 +65,8 @@ class FieldTable
+ QPID_COMMON_EXTERN void decode(Buffer& buffer);
+
+ QPID_COMMON_EXTERN int count() const;
+- QPID_COMMON_EXTERN size_t size() const { return values.size(); }
+- QPID_COMMON_EXTERN bool empty() { return size() == 0; }
++ QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); }
++ QPID_COMMON_INLINE_EXTERN bool empty() { return size() == 0; }
+ QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value);
+ QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const;
+ QPID_COMMON_INLINE_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; }
+--
+1.7.4.4
+
+From 1f68475caffaa3c36ad921684bbaea35c68ce375 Mon Sep 17 00:00:00 2001
+From: Ted Ross <ross at localhost.localdomain>
+Date: Mon, 15 Aug 2011 17:10:15 -0400
+Subject: [PATCH 06/14] Enable qmf2 for mingw32
+
+---
+ qpid/cpp/src/CMakeLists.txt | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
+index 80315b9..978d962 100644
+--- a/qpid/cpp/src/CMakeLists.txt
++++ b/qpid/cpp/src/CMakeLists.txt
+@@ -1081,7 +1081,7 @@ install (TARGETS qmf OPTIONAL
+ COMPONENT ${QPID_COMPONENT_QMF})
+ install_pdb (qmf ${QPID_COMPONENT_QMF})
+
+-if(NOT WIN32)
++#if(NOT WIN32)
+ set (qmf2_HEADERS
+ ../include/qmf/AgentEvent.h
+ ../include/qmf/Agent.h
+@@ -1156,7 +1156,7 @@ if(NOT WIN32)
+ DESTINATION ${QPID_INSTALL_INCLUDEDIR}/qmf
+ COMPONENT ${QPID_COMPONENT_QMF})
+ install_pdb (qmf2 ${QPID_COMPONENT_QMF})
+-endif (NOT WIN32)
++#endif (NOT WIN32)
+
+ set (qmfengine_SOURCES
+ qmf/engine/Agent.cpp
+--
+1.7.4.4
+
+From 337286e57705835975acd215aa1990f3597abc6a Mon Sep 17 00:00:00 2001
+From: Ted Ross <ross at localhost.localdomain>
+Date: Mon, 15 Aug 2011 17:36:24 -0400
+Subject: [PATCH 07/14] Fixed externs in AddressParser
+
+---
+ qpid/cpp/src/qpid/messaging/AddressParser.h | 10 +++++-----
+ 1 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/qpid/cpp/src/qpid/messaging/AddressParser.h b/qpid/cpp/src/qpid/messaging/AddressParser.h
+index 1635331..c51200c 100644
+--- a/qpid/cpp/src/qpid/messaging/AddressParser.h
++++ b/qpid/cpp/src/qpid/messaging/AddressParser.h
+@@ -26,13 +26,13 @@
+ namespace qpid {
+ namespace messaging {
+
+-class AddressParser
++class QPID_MESSAGING_CLASS_EXTERN AddressParser
{
- return *item.impl;
-Index: cpp/src/qmf/DataImpl.h
-===================================================================
---- cpp/src/qmf/DataImpl.h (revision 1056407)
-+++ cpp/src/qmf/DataImpl.h (working copy)
-@@ -24,8 +24,10 @@
- #include "qpid/RefCounted.h"
- #include "qmf/Data.h"
- #include "qmf/SchemaId.h"
-+#include "qmf/Schema.h"
- #include "qmf/DataAddr.h"
- #include "qmf/Agent.h"
-+#include "qmf/AgentSubscription.h"
- #include "qpid/types/Variant.h"
+ public:
+- AddressParser(const std::string&);
+- bool parse(Address& address);
+- bool parseMap(qpid::types::Variant::Map& map);
+- bool parseList(qpid::types::Variant::List& list);
++ QPID_MESSAGING_EXTERN AddressParser(const std::string&);
++ QPID_MESSAGING_EXTERN bool parse(Address& address);
++ QPID_MESSAGING_EXTERN bool parseMap(qpid::types::Variant::Map& map);
++ QPID_MESSAGING_EXTERN bool parseList(qpid::types::Variant::List& list);
+ private:
+ const std::string& input;
+ std::string::size_type current;
+--
+1.7.4.4
+
+From 666f43e30629559d97a71bd737d36ab14d3eeb86 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Tue, 13 Sep 2011 19:34:38 +0000
+Subject: [PATCH 08/14] QPID-3484 - QMF Main-Loop Integration Applied patch
+ from Darryl Pierce.
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1170314 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/bindings/qmf2/examples/cpp/Makefile.am | 5 +-
+ .../qmf2/examples/cpp/event_driven_list_agents.cpp | 107 ++++++++++++
+ qpid/cpp/include/qmf/AgentSession.h | 1 +
+ qpid/cpp/include/qmf/ConsoleSession.h | 1 +
+ qpid/cpp/include/qmf/posix/EventNotifier.h | 62 +++++++
+ qpid/cpp/src/CMakeLists.txt | 5 +
+ qpid/cpp/src/qmf.mk | 4 +
+ qpid/cpp/src/qmf/AgentSession.cpp | 167 +++++--------------
+ qpid/cpp/src/qmf/AgentSessionImpl.h | 175 ++++++++++++++++++++
+ qpid/cpp/src/qmf/ConsoleSession.cpp | 38 ++++-
+ qpid/cpp/src/qmf/ConsoleSessionImpl.h | 17 ++
+ qpid/cpp/src/qmf/EventNotifierImpl.cpp | 56 +++++++
+ qpid/cpp/src/qmf/EventNotifierImpl.h | 48 ++++++
+ qpid/cpp/src/qmf/PosixEventNotifier.cpp | 63 +++++++
+ qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp | 108 ++++++++++++
+ qpid/cpp/src/qmf/PosixEventNotifierImpl.h | 61 +++++++
+ qpid/cpp/src/tests/Qmf2.cpp | 104 ++++++++++++-
+ 17 files changed, 890 insertions(+), 132 deletions(-)
+ create mode 100644 qpid/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp
+ create mode 100644 qpid/cpp/include/qmf/posix/EventNotifier.h
+ create mode 100644 qpid/cpp/src/qmf/AgentSessionImpl.h
+ create mode 100644 qpid/cpp/src/qmf/EventNotifierImpl.cpp
+ create mode 100644 qpid/cpp/src/qmf/EventNotifierImpl.h
+ create mode 100644 qpid/cpp/src/qmf/PosixEventNotifier.cpp
+ create mode 100644 qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
+ create mode 100644 qpid/cpp/src/qmf/PosixEventNotifierImpl.h
+
+diff --git a/qpid/cpp/bindings/qmf2/examples/cpp/Makefile.am b/qpid/cpp/bindings/qmf2/examples/cpp/Makefile.am
+index 84207d4..062fbd0 100644
+--- a/qpid/cpp/bindings/qmf2/examples/cpp/Makefile.am
++++ b/qpid/cpp/bindings/qmf2/examples/cpp/Makefile.am
+@@ -21,7 +21,7 @@ INCLUDE = -I$(top_srcdir)/include
- namespace qmf {
-@@ -37,18 +39,21 @@
- DataImpl(const qpid::types::Variant::Map&, const Agent&);
- qpid::types::Variant::Map asMap() const;
- DataImpl() {}
-+ void addSubscription(boost::shared_ptr<AgentSubscription>);
-+ void delSubscription(uint64_t);
-+ qpid::types::Variant::Map publishSubscription(uint64_t);
-+ const Schema& getSchema() const { return schema; }
+ AM_CPPFLAGS = $(INCLUDE)
- //
- // Methods from API handle
- //
-- DataImpl(const SchemaId& s) : schemaId(s) {}
-- void setSchema(const SchemaId& s) { schemaId = s; }
-+ DataImpl(const Schema& s) : schema(s) {}
- void setAddr(const DataAddr& a) { dataAddr = a; }
-- void setProperty(const std::string& k, const qpid::types::Variant& v) { properties[k] = v; }
-+ void setProperty(const std::string& k, const qpid::types::Variant& v);
- void overwriteProperties(const qpid::types::Variant::Map& m);
-- bool hasSchema() const { return schemaId.isValid(); }
-+ bool hasSchema() const { return schemaId.isValid() || schema.isValid(); }
- bool hasAddr() const { return dataAddr.isValid(); }
-- const SchemaId& getSchemaId() const { return schemaId; }
-+ const SchemaId& getSchemaId() const { if (schema.isValid()) return schema.getSchemaId(); else return schemaId; }
- const DataAddr& getAddr() const { return dataAddr; }
- const qpid::types::Variant& getProperty(const std::string& k) const;
- const qpid::types::Variant::Map& getProperties() const { return properties; }
-@@ -56,7 +61,14 @@
- const Agent& getAgent() const { return agent; }
+-noinst_PROGRAMS=agent list_agents print_events
++noinst_PROGRAMS=agent event_driven_list_agents list_agents print_events
- private:
-+ struct Subscr {
-+ boost::shared_ptr<AgentSubscription> subscription;
-+ qpid::types::Variant::Map deltas;
-+ };
-+ std::map<uint64_t, boost::shared_ptr<Subscr> > subscriptions;
-+
- SchemaId schemaId;
-+ Schema schema;
- DataAddr dataAddr;
- qpid::types::Variant::Map properties;
- Agent agent;
-Index: cpp/src/qmf/AgentSubscription.cpp
-===================================================================
---- cpp/src/qmf/AgentSubscription.cpp (revision 0)
-+++ cpp/src/qmf/AgentSubscription.cpp (revision 0)
-@@ -0,0 +1,51 @@
+ agent_SOURCES=agent.cpp
+ agent_LDADD=$(top_builddir)/src/libqmf2.la
+@@ -29,5 +29,8 @@ agent_LDADD=$(top_builddir)/src/libqmf2.la
+ list_agents_SOURCES=list_agents.cpp
+ list_agents_LDADD=$(top_builddir)/src/libqmf2.la
+
++event_driven_list_agents_SOURCES=event_driven_list_agents.cpp
++event_driven_list_agents_LDADD=$(top_builddir)/src/libqmf2.la
++
+ print_events_SOURCES=print_events.cpp
+ print_events_LDADD=$(top_builddir)/src/libqmf2.la
+diff --git a/qpid/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp b/qpid/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp
+new file mode 100644
+index 0000000..c288aa6
+--- /dev/null
++++ b/qpid/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp
+@@ -0,0 +1,107 @@
+/*
-+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
@@ -369,69 +752,139 @@ Index: cpp/src/qmf/AgentSubscription.cpp
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
-+ *
++ *
+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
++ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "qmf/AgentSubscription.h"
++#include <sys/select.h>
++#include <time.h>
++
++#include <qpid/messaging/Connection.h>
++#include <qpid/messaging/Duration.h>
++#include <qmf/Agent.h>
++#include <qmf/ConsoleEvent.h>
++#include <qmf/ConsoleSession.h>
++#include <qpid/types/Variant.h>
++#include "qmf/posix/EventNotifier.h"
++
++#include <string>
++#include <iostream>
+
++using namespace std;
+using namespace qmf;
++using qpid::types::Variant;
++using qpid::messaging::Duration;
+
-+AgentSubscription::AgentSubscription(uint64_t _id, uint64_t _interval, uint64_t _life,
-+ const std::string& _replyTo, const std::string& _cid, Query _query) :
-+ id(_id), interval(_interval), lifetime(_life), timeSincePublish(0), timeSinceKeepalive(0),
-+ replyTo(_replyTo), cid(_cid), query(_query)
++int main(int argc, char** argv)
+{
-+}
++ string url("localhost");
++ string connectionOptions;
++ string sessionOptions;
++
++ if (argc > 1)
++ url = argv[1];
++ if (argc > 2)
++ connectionOptions = argv[2];
++ if (argc > 3)
++ sessionOptions = argv[3];
+
++ qpid::messaging::Connection connection(url, connectionOptions);
++ connection.open();
+
-+AgentSubscription::~AgentSubscription()
-+{
-+}
++ ConsoleSession session(connection, sessionOptions);
++ session.open();
++ session.setAgentFilter("");
+
++ posix::EventNotifier notifier(session);
+
-+bool AgentSubscription::tick(uint64_t seconds)
-+{
-+ timeSinceKeepalive += seconds;
-+ if (timeSinceKeepalive >= lifetime)
-+ return false;
++ int fd(notifier.getHandle());
++ time_t lastUpdate;
++ bool ftl = false;
+
-+ timeSincePublish += seconds;
-+ if (timeSincePublish >= interval) {
-+ }
++ time(&lastUpdate);
+
-+ return true;
++ while (true) {
++ fd_set rfds;
++ struct timeval tv;
++ int nfds, retval;
++
++ FD_ZERO(&rfds);
++ FD_SET(fd, &rfds);
++ nfds = fd + 1;
++ tv.tv_sec = 10;
++ tv.tv_usec = 0;
++
++ retval = select(nfds, &rfds, NULL, NULL, &tv);
++
++ if (retval > 0 && FD_ISSET(fd, &rfds)) {
++ ConsoleEvent event;
++ while (session.nextEvent(event, Duration::IMMEDIATE)) {
++ string eventType = "";
++ switch(event.getType()) {
++ case CONSOLE_AGENT_ADD: eventType = "Added"; break;
++ case CONSOLE_AGENT_DEL: eventType = "Deleted"; break;
++ case CONSOLE_AGENT_RESTART: eventType = "Restarted"; break;
++ case CONSOLE_AGENT_SCHEMA_UPDATE: eventType = "Schema Updated"; break;
++ case CONSOLE_AGENT_SCHEMA_RESPONSE: eventType = "Schema Response"; break;
++ case CONSOLE_EVENT: eventType = "Event"; break;
++ case CONSOLE_QUERY_RESPONSE: eventType = "Query Response"; break;
++ case CONSOLE_METHOD_RESPONSE: eventType = "Method Response"; break;
++ case CONSOLE_EXCEPTION: eventType = "Exception"; break;
++ case CONSOLE_SUBSCRIBE_ADD: eventType = "Subscription Added"; break;
++ case CONSOLE_SUBSCRIBE_UPDATE: eventType = "Subscription Updated"; break;
++ case CONSOLE_SUBSCRIBE_DEL: eventType = "Subscription Deleted" ; break;
++ case CONSOLE_THREAD_FAILED: eventType = "Thread Failure"; break;
++ default: eventType = "[UNDEFINED]";
++ }
++ cout << "Agent " << eventType << ": " << event.getAgent().getName() << endl;
++ }
++ } else {
++ cout << "No message received within waiting period." << endl;
++ }
++ }
+}
+
-Index: cpp/src/qmf/DataAddr.cpp
-===================================================================
---- cpp/src/qmf/DataAddr.cpp (revision 1056407)
-+++ cpp/src/qmf/DataAddr.cpp (working copy)
-@@ -38,6 +38,7 @@
- bool DataAddr::operator==(const DataAddr& o) { return *impl == *o.impl; }
- bool DataAddr::operator<(const DataAddr& o) { return *impl < *o.impl; }
+diff --git a/qpid/cpp/include/qmf/AgentSession.h b/qpid/cpp/include/qmf/AgentSession.h
+index 5ecfb04..589d364 100644
+--- a/qpid/cpp/include/qmf/AgentSession.h
++++ b/qpid/cpp/include/qmf/AgentSession.h
+@@ -188,6 +188,7 @@ namespace qmf {
+ #ifndef SWIG
+ private:
+ friend class qmf::PrivateImplRef<AgentSession>;
++ friend struct AgentSessionImplAccess;
+ #endif
+ };
-+DataAddr::DataAddr(const qpid::types::Variant::Map& m) { PI::ctor(*this, new DataAddrImpl(m)); }
- DataAddr::DataAddr(const string& n, const string& a, uint32_t e) { PI::ctor(*this, new DataAddrImpl(n, a, e)); }
- const string& DataAddr::getName() const { return impl->getName(); }
- const string& DataAddr::getAgentName() const { return impl->getAgentName(); }
-Index: cpp/src/qmf/SubscriptionImpl.h
-===================================================================
---- cpp/src/qmf/SubscriptionImpl.h (revision 0)
-+++ cpp/src/qmf/SubscriptionImpl.h (revision 0)
-@@ -0,0 +1,57 @@
-+#ifndef _QMF_SUBSCRIPTION_IMPL_H_
-+#define _QMF_SUBSCRIPTION_IMPL_H_
+diff --git a/qpid/cpp/include/qmf/ConsoleSession.h b/qpid/cpp/include/qmf/ConsoleSession.h
+index 5e3a091..022485c 100644
+--- a/qpid/cpp/include/qmf/ConsoleSession.h
++++ b/qpid/cpp/include/qmf/ConsoleSession.h
+@@ -123,6 +123,7 @@ namespace qmf {
+ #ifndef SWIG
+ private:
+ friend class qmf::PrivateImplRef<ConsoleSession>;
++ friend struct ConsoleSessionImplAccess;
+ #endif
+ };
+
+diff --git a/qpid/cpp/include/qmf/posix/EventNotifier.h b/qpid/cpp/include/qmf/posix/EventNotifier.h
+new file mode 100644
+index 0000000..91817cc
+--- /dev/null
++++ b/qpid/cpp/include/qmf/posix/EventNotifier.h
+@@ -0,0 +1,62 @@
++#ifndef __QMF_POSIX_EVENT_NOTIFIER_H
++#define __QMF_POSIX_EVENT_NOTIFIER_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
@@ -439,73 +892,322 @@ Index: cpp/src/qmf/SubscriptionImpl.h
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
-+ *
++ *
+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
++ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/RefCounted.h"
-+#include "qmf/Subscription.h"
++#include <qmf/ImportExport.h>
++#include "qmf/Handle.h"
++#include "qmf/AgentSession.h"
++#include "qmf/ConsoleSession.h"
+
+namespace qmf {
-+ class SubscriptionImpl : public virtual qpid::RefCounted {
-+ public:
-+ //
-+ // Public impl-only methods
-+ //
-+ SubscriptionImpl(int p) : placeholder(p) {}
-+ ~SubscriptionImpl();
+
-+ //
-+ // Methods from API handle
-+ //
-+ void cancel();
-+ bool isActive() const;
-+ void lock();
-+ void unlock();
-+ uint32_t getDataCount() const;
-+ Data getData(uint32_t) const;
++ class PosixEventNotifierImpl;
++ class PosixEventNotifierImplAccess;
+
-+ private:
-+ int placeholder;
-+ };
++namespace posix {
+
-+ struct SubscriptionImplAccess
-+ {
-+ static SubscriptionImpl& get(Subscription&);
-+ static const SubscriptionImpl& get(const Subscription&);
-+ };
-+}
++#ifndef SWIG
++ template <class> class PrivateImplRef;
++#endif
++
++ class QMF_CLASS_EXTERN EventNotifier : public qmf::Handle<qmf::PosixEventNotifierImpl> {
++ public:
++ QMF_EXTERN EventNotifier(::qmf::AgentSession& agentSession);
++ QMF_EXTERN EventNotifier(::qmf::ConsoleSession& consoleSession);
++ QMF_EXTERN EventNotifier(const EventNotifier& that);
++
++ QMF_EXTERN ~EventNotifier();
++
++ QMF_EXTERN EventNotifier& operator=(const EventNotifier& that);
++
++ QMF_EXTERN int getHandle() const;
++
++#ifndef SWIG
++ private:
++ friend class qmf::PrivateImplRef<EventNotifier>;
++ friend struct qmf::PosixEventNotifierImplAccess;
++#endif
++
++ };
++
++}}
+
+#endif
-Index: cpp/src/qmf/SchemaId.cpp
-===================================================================
---- cpp/src/qmf/SchemaId.cpp (revision 1056407)
-+++ cpp/src/qmf/SchemaId.cpp (working copy)
-@@ -78,7 +78,8 @@
- result["_type"] = "_data";
- else
- result["_type"] = "_event";
-- result["_hash"] = hash;
-+ if (!hash.isNull())
-+ result["_hash"] = hash;
- return result;
++
+diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
+index 978d962..2986a90 100644
+--- a/qpid/cpp/src/CMakeLists.txt
++++ b/qpid/cpp/src/CMakeLists.txt
+@@ -1093,6 +1093,7 @@ install_pdb (qmf ${QPID_COMPONENT_QMF})
+ ../include/qmf/exceptions.h
+ ../include/qmf/Handle.h
+ ../include/qmf/ImportExport.h
++ ../include/qmf/posix/EventNotifier.h
+ ../include/qmf/Query.h
+ ../include/qmf/Schema.h
+ ../include/qmf/SchemaId.h
+@@ -1122,6 +1123,10 @@ install_pdb (qmf ${QPID_COMPONENT_QMF})
+ qmf/DataAddrImpl.h
+ qmf/Data.cpp
+ qmf/DataImpl.h
++ qmf/EventNotifierImpl.h
++ qmf/EventNotifierImpl.cpp
++ qmf/PosixEventNotifier.cpp
++ qmf/PosixEventNotifierImpl.cpp
+ qmf/exceptions.cpp
+ qmf/Expression.cpp
+ qmf/Expression.h
+diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk
+index f3462f1..4da8470 100644
+--- a/qpid/cpp/src/qmf.mk
++++ b/qpid/cpp/src/qmf.mk
+@@ -43,6 +43,7 @@ QMF2_API = \
+ ../include/qmf/ConsoleSession.h \
+ ../include/qmf/DataAddr.h \
+ ../include/qmf/Data.h \
++ ../include/qmf/posix/EventNotifier.h \
+ ../include/qmf/exceptions.h \
+ ../include/qmf/Handle.h \
+ ../include/qmf/ImportExport.h \
+@@ -104,6 +105,9 @@ libqmf2_la_SOURCES = \
+ qmf/DataAddrImpl.h \
+ qmf/Data.cpp \
+ qmf/DataImpl.h \
++ qmf/EventNotifierImpl.cpp \
++ qmf/PosixEventNotifier.cpp \
++ qmf/PosixEventNotifierImpl.cpp \
+ qmf/exceptions.cpp \
+ qmf/Expression.cpp \
+ qmf/Expression.h \
+diff --git a/qpid/cpp/src/qmf/AgentSession.cpp b/qpid/cpp/src/qmf/AgentSession.cpp
+index a88782d..d92b2a4 100644
+--- a/qpid/cpp/src/qmf/AgentSession.cpp
++++ b/qpid/cpp/src/qmf/AgentSession.cpp
+@@ -19,134 +19,7 @@
+ *
+ */
+
+-#include "qpid/RefCounted.h"
+-#include "qmf/PrivateImplRef.h"
+-#include "qmf/exceptions.h"
+-#include "qmf/AgentSession.h"
+-#include "qmf/AgentEventImpl.h"
+-#include "qmf/SchemaIdImpl.h"
+-#include "qmf/SchemaImpl.h"
+-#include "qmf/DataAddrImpl.h"
+-#include "qmf/DataImpl.h"
+-#include "qmf/QueryImpl.h"
+-#include "qmf/agentCapability.h"
+-#include "qmf/constants.h"
+-#include "qpid/sys/Mutex.h"
+-#include "qpid/sys/Condition.h"
+-#include "qpid/sys/Thread.h"
+-#include "qpid/sys/Runnable.h"
+-#include "qpid/log/Statement.h"
+-#include "qpid/messaging/Connection.h"
+-#include "qpid/messaging/Session.h"
+-#include "qpid/messaging/Receiver.h"
+-#include "qpid/messaging/Sender.h"
+-#include "qpid/messaging/Message.h"
+-#include "qpid/messaging/AddressParser.h"
+-#include "qpid/management/Buffer.h"
+-#include <queue>
+-#include <map>
+-#include <set>
+-#include <iostream>
+-#include <memory>
+-
+-using namespace std;
+-using namespace qpid::messaging;
+-using namespace qmf;
+-using qpid::types::Variant;
+-
+-namespace qmf {
+- class AgentSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable {
+- public:
+- ~AgentSessionImpl();
+-
+- //
+- // Methods from API handle
+- //
+- AgentSessionImpl(Connection& c, const string& o);
+- void setDomain(const string& d) { checkOpen(); domain = d; }
+- void setVendor(const string& v) { checkOpen(); attributes["_vendor"] = v; }
+- void setProduct(const string& p) { checkOpen(); attributes["_product"] = p; }
+- void setInstance(const string& i) { checkOpen(); attributes["_instance"] = i; }
+- void setAttribute(const string& k, const qpid::types::Variant& v) { checkOpen(); attributes[k] = v; }
+- const string& getName() const { return agentName; }
+- void open();
+- void close();
+- bool nextEvent(AgentEvent& e, Duration t);
+- int pendingEvents() const;
+-
+- void registerSchema(Schema& s);
+- DataAddr addData(Data& d, const string& n, bool persist);
+- void delData(const DataAddr&);
+-
+- void authAccept(AgentEvent& e);
+- void authReject(AgentEvent& e, const string& m);
+- void raiseException(AgentEvent& e, const string& s);
+- void raiseException(AgentEvent& e, const Data& d);
+- void response(AgentEvent& e, const Data& d);
+- void complete(AgentEvent& e);
+- void methodSuccess(AgentEvent& e);
+- void raiseEvent(const Data& d);
+- void raiseEvent(const Data& d, int s);
+-
+- private:
+- typedef map<DataAddr, Data, DataAddrCompare> DataIndex;
+- typedef map<SchemaId, Schema, SchemaIdCompare> SchemaMap;
+-
+- mutable qpid::sys::Mutex lock;
+- qpid::sys::Condition cond;
+- Connection connection;
+- Session session;
+- Sender directSender;
+- Sender topicSender;
+- string domain;
+- Variant::Map attributes;
+- Variant::Map options;
+- string agentName;
+- bool opened;
+- queue<AgentEvent> eventQueue;
+- qpid::sys::Thread* thread;
+- bool threadCanceled;
+- uint32_t bootSequence;
+- uint32_t interval;
+- uint64_t lastHeartbeat;
+- uint64_t lastVisit;
+- bool forceHeartbeat;
+- bool externalStorage;
+- bool autoAllowQueries;
+- bool autoAllowMethods;
+- uint32_t maxSubscriptions;
+- uint32_t minSubInterval;
+- uint32_t subLifetime;
+- bool publicEvents;
+- bool listenOnDirect;
+- bool strictSecurity;
+- uint32_t maxThreadWaitTime;
+- uint64_t schemaUpdateTime;
+- string directBase;
+- string topicBase;
+-
+- SchemaMap schemata;
+- DataIndex globalIndex;
+- map<SchemaId, DataIndex, SchemaIdCompareNoHash> schemaIndex;
+-
+- void checkOpen();
+- void setAgentName();
+- void enqueueEvent(const AgentEvent&);
+- void handleLocateRequest(const Variant::List& content, const Message& msg);
+- void handleMethodRequest(const Variant::Map& content, const Message& msg);
+- void handleQueryRequest(const Variant::Map& content, const Message& msg);
+- void handleSchemaRequest(AgentEvent&);
+- void handleV1SchemaRequest(qpid::management::Buffer&, uint32_t, const Message&);
+- void dispatch(Message);
+- void sendHeartbeat();
+- void send(Message, const Address&);
+- void flushResponses(AgentEvent&, bool);
+- void periodicProcessing(uint64_t);
+- void run();
+- };
+-}
+-
+-typedef qmf::PrivateImplRef<AgentSession> PI;
++#include "qmf/AgentSessionImpl.h"
+
+ AgentSession::AgentSession(AgentSessionImpl* impl) { PI::ctor(*this, impl); }
+ AgentSession::AgentSession(const AgentSession& s) : qmf::Handle<AgentSessionImpl>() { PI::copy(*this, s); }
+@@ -345,6 +218,8 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout)
+ if (!eventQueue.empty()) {
+ event = eventQueue.front();
+ eventQueue.pop();
++ if (eventQueue.empty())
++ alertEventNotifierLH(false);
+ return true;
+ }
+
+@@ -359,6 +234,19 @@ int AgentSessionImpl::pendingEvents() const
+ }
+
+
++void AgentSessionImpl::setEventNotifier(EventNotifierImpl* notifier)
++{
++ qpid::sys::Mutex::ScopedLock l(lock);
++ eventNotifier = notifier;
++}
++
++EventNotifierImpl* AgentSessionImpl::getEventNotifier() const
++{
++ qpid::sys::Mutex::ScopedLock l(lock);
++ return eventNotifier;
++}
++
++
+ void AgentSessionImpl::registerSchema(Schema& schema)
+ {
+ if (!schema.isFinalized())
+@@ -614,8 +502,10 @@ void AgentSessionImpl::enqueueEvent(const AgentEvent& event)
+ qpid::sys::Mutex::ScopedLock l(lock);
+ bool notify = eventQueue.empty();
+ eventQueue.push(event);
+- if (notify)
++ if (notify) {
+ cond.notify();
++ alertEventNotifierLH(true);
++ }
+ }
+
+
+@@ -1059,6 +949,13 @@ void AgentSessionImpl::periodicProcessing(uint64_t seconds)
+ }
+
+
++void AgentSessionImpl::alertEventNotifierLH(bool readable)
++{
++ if (eventNotifier)
++ eventNotifier->setReadable(readable);
++}
++
++
+ void AgentSessionImpl::run()
+ {
+ QPID_LOG(debug, "AgentSession thread started for agent " << agentName);
+@@ -1089,3 +986,15 @@ void AgentSessionImpl::run()
+ QPID_LOG(debug, "AgentSession thread exiting for agent " << agentName);
}
-Index: cpp/src/qmf/constants.h
-===================================================================
---- cpp/src/qmf/constants.h (revision 0)
-+++ cpp/src/qmf/constants.h (revision 0)
-@@ -0,0 +1,83 @@
-+#ifndef QMF_CONSTANTS_H
-+#define QMF_CONSTANTS_H
++
++AgentSessionImpl& AgentSessionImplAccess::get(AgentSession& session)
++{
++ return *session.impl;
++}
++
++
++const AgentSessionImpl& AgentSessionImplAccess::get(const AgentSession& session)
++{
++ return *session.impl;
++}
++
+diff --git a/qpid/cpp/src/qmf/AgentSessionImpl.h b/qpid/cpp/src/qmf/AgentSessionImpl.h
+new file mode 100644
+index 0000000..cf1b1d7
+--- /dev/null
++++ b/qpid/cpp/src/qmf/AgentSessionImpl.h
+@@ -0,0 +1,175 @@
++#ifndef __QMF_AGENT_SESSION_IMPL_H
++#define __QMF_AGENT_SESSION_IMPL_H
++
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
@@ -527,1049 +1229,368 @@ Index: cpp/src/qmf/constants.h
+ *
+ */
+
-+#include <string>
-+
-+namespace qmf {
-+
-+ struct protocol {
-+ /**
-+ * Header key strings
-+ */
-+ static const std::string HEADER_KEY_APP_ID;
-+ static const std::string HEADER_KEY_METHOD;
-+ static const std::string HEADER_KEY_OPCODE;
-+ static const std::string HEADER_KEY_AGENT;
-+ static const std::string HEADER_KEY_CONTENT;
-+ static const std::string HEADER_KEY_PARTIAL;
-+
-+ /**
-+ * Header values per-key
-+ */
-+ static const std::string HEADER_APP_ID_QMF;
++#include "qpid/RefCounted.h"
++#include "qmf/PrivateImplRef.h"
++#include "qmf/exceptions.h"
++#include "qmf/AgentSession.h"
++#include "qmf/AgentEventImpl.h"
++#include "qmf/EventNotifierImpl.h"
++#include "qpid/messaging/Connection.h"
++#include "qpid/sys/Runnable.h"
++#include "qpid/sys/Mutex.h"
++#include "qpid/sys/Condition.h"
++#include "qpid/sys/Thread.h"
++#include "qpid/sys/Runnable.h"
++#include "qpid/log/Statement.h"
++#include "qpid/messaging/Connection.h"
++#include "qpid/messaging/Session.h"
++#include "qpid/messaging/Receiver.h"
++#include "qpid/messaging/Sender.h"
++#include "qpid/messaging/Message.h"
++#include "qpid/messaging/AddressParser.h"
++#include "qpid/management/Buffer.h"
++#include "qpid/RefCounted.h"
++#include "qmf/PrivateImplRef.h"
++#include "qmf/AgentSession.h"
++#include "qmf/exceptions.h"
++#include "qmf/AgentSession.h"
++#include "qmf/SchemaIdImpl.h"
++#include "qmf/SchemaImpl.h"
++#include "qmf/DataAddrImpl.h"
++#include "qmf/DataImpl.h"
++#include "qmf/QueryImpl.h"
++#include "qmf/agentCapability.h"
++#include "qmf/constants.h"
+
-+ static const std::string HEADER_METHOD_REQUEST;
-+ static const std::string HEADER_METHOD_RESPONSE;
-+ static const std::string HEADER_METHOD_INDICATION;
++#include <queue>
++#include <map>
++#include <iostream>
++#include <memory>
+
-+ static const std::string HEADER_OPCODE_EXCEPTION;
-+ static const std::string HEADER_OPCODE_AGENT_LOCATE_REQUEST;
-+ static const std::string HEADER_OPCODE_AGENT_LOCATE_RESPONSE;
-+ static const std::string HEADER_OPCODE_AGENT_HEARTBEAT_INDICATION;
-+ static const std::string HEADER_OPCODE_QUERY_REQUEST;
-+ static const std::string HEADER_OPCODE_QUERY_RESPONSE;
-+ static const std::string HEADER_OPCODE_SUBSCRIBE_REQUEST;
-+ static const std::string HEADER_OPCODE_SUBSCRIBE_RESPONSE;
-+ static const std::string HEADER_OPCODE_SUBSCRIBE_CANCEL_INDICATION;
-+ static const std::string HEADER_OPCODE_SUBSCRIBE_REFRESH_INDICATION;
-+ static const std::string HEADER_OPCODE_DATA_INDICATION;
-+ static const std::string HEADER_OPCODE_METHOD_REQUEST;
-+ static const std::string HEADER_OPCODE_METHOD_RESPONSE;
++using namespace std;
++using namespace qpid::messaging;
++using namespace qmf;
++using qpid::types::Variant;
++using namespace boost;
+
-+ static const std::string HEADER_CONTENT_SCHEMA_ID;
-+ static const std::string HEADER_CONTENT_SCHEMA_CLASS;
-+ static const std::string HEADER_CONTENT_OBJECT_ID;
-+ static const std::string HEADER_CONTENT_DATA;
-+ static const std::string HEADER_CONTENT_EVENT;
-+ static const std::string HEADER_CONTENT_QUERY;
++typedef qmf::PrivateImplRef<AgentSession> PI;
+
-+ /**
-+ * Keywords for Agent attributes
-+ */
-+ static const std::string AGENT_ATTR_VENDOR;
-+ static const std::string AGENT_ATTR_PRODUCT;
-+ static const std::string AGENT_ATTR_INSTANCE;
-+ static const std::string AGENT_ATTR_NAME;
-+ static const std::string AGENT_ATTR_TIMESTAMP;
-+ static const std::string AGENT_ATTR_HEARTBEAT_INTERVAL;
-+ static const std::string AGENT_ATTR_EPOCH;
-+ static const std::string AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP;
-+ };
-+}
++namespace qmf {
++ class AgentSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable {
++ public:
++ ~AgentSessionImpl();
+
-+#endif
-Index: cpp/src/qmf/AgentImpl.h
-===================================================================
---- cpp/src/qmf/AgentImpl.h (revision 1056407)
-+++ cpp/src/qmf/AgentImpl.h (working copy)
-@@ -29,6 +29,7 @@
- #include "qmf/SchemaCache.h"
- #include "qpid/messaging/Session.h"
- #include "qpid/messaging/Message.h"
-+#include "qpid/messaging/Sender.h"
- #include "qpid/sys/Mutex.h"
- #include "qpid/sys/Condition.h"
- #include <boost/shared_ptr.hpp>
-@@ -90,11 +91,13 @@
-
- mutable qpid::sys::Mutex lock;
- std::string name;
-+ std::string directSubject;
- uint32_t epoch;
- ConsoleSessionImpl& session;
- bool touched;
- uint32_t untouchedCount;
- uint32_t capability;
-+ qpid::messaging::Sender sender;
- qpid::types::Variant::Map attributes;
- uint32_t nextCorrelator;
- std::map<uint32_t, boost::shared_ptr<SyncContext> > contextMap;
-Index: cpp/src/qmf/SchemaImpl.h
-===================================================================
---- cpp/src/qmf/SchemaImpl.h (revision 1056407)
-+++ cpp/src/qmf/SchemaImpl.h (working copy)
-@@ -46,6 +46,9 @@
- qpid::types::Variant::Map asMap() const;
- SchemaImpl(qpid::management::Buffer& v1Buffer);
- std::string asV1Content(uint32_t sequence) const;
-+ bool isValidProperty(const std::string& k, const qpid::types::Variant& v) const;
-+ bool isValidMethodInArg(const std::string& m, const std::string& k, const qpid::types::Variant& v) const;
-+ bool isValidMethodOutArg(const std::string& m, const std::string& k, const qpid::types::Variant& v) const;
-
- //
- // Methods from API handle
-@@ -79,6 +82,7 @@
-
- void checkFinal() const;
- void checkNotFinal() const;
-+ bool isCompatibleType(int qmfType, qpid::types::VariantType qpidType) const;
- };
-
- struct SchemaImplAccess
-Index: cpp/src/qmf/DataAddrImpl.h
-===================================================================
---- cpp/src/qmf/DataAddrImpl.h (revision 1056407)
-+++ cpp/src/qmf/DataAddrImpl.h (working copy)
-@@ -32,7 +32,6 @@
- //
- // Impl-only methods
- //
-- DataAddrImpl(const qpid::types::Variant::Map&);
- void setName(const std::string& n) { name = n; }
- void setAgent(const std::string& n, uint32_t e=0) { agentName = n; agentEpoch = e; }
-
-@@ -41,6 +40,7 @@
- //
- bool operator==(const DataAddrImpl&);
- bool operator<(const DataAddrImpl&);
-+ DataAddrImpl(const qpid::types::Variant::Map&);
- DataAddrImpl(const std::string& _name, const std::string& _agentName, uint32_t _agentEpoch=0) :
- agentName(_agentName), name(_name), agentEpoch(_agentEpoch) {}
- const std::string& getName() const { return name; }
-Index: cpp/src/qmf/AgentEvent.cpp
-===================================================================
---- cpp/src/qmf/AgentEvent.cpp (revision 1056407)
-+++ cpp/src/qmf/AgentEvent.cpp (working copy)
-@@ -21,6 +21,7 @@
-
- #include "qmf/AgentEventImpl.h"
- #include "qmf/PrivateImplRef.h"
-+#include "qmf/SchemaImpl.h"
-
- using namespace std;
- using namespace qmf;
-@@ -64,6 +65,8 @@
-
- void AgentEventImpl::addReturnArgument(const string& key, const Variant& val, const string& subtype)
- {
-+ if (schema.isValid() && !SchemaImplAccess::get(schema).isValidMethodOutArg(methodName, key, val))
-+ throw QmfException("Output argument is unknown or the type is incompatible");
- outArguments[key] = val;
- if (!subtype.empty())
- outArgumentSubtypes[key] = subtype;
-Index: cpp/src/qmf/SchemaMethod.cpp
-===================================================================
---- cpp/src/qmf/SchemaMethod.cpp (revision 1056407)
-+++ cpp/src/qmf/SchemaMethod.cpp (working copy)
-@@ -163,7 +163,7 @@
- Variant::Map map;
-
- map["name"] = name;
-- map["argCount"] = arguments.size();
-+ map["argCount"] = (uint64_t) arguments.size();
- if (!desc.empty())
- map["desc"] = desc;
-
-Index: cpp/src/qmf/AgentSession.cpp
-===================================================================
---- cpp/src/qmf/AgentSession.cpp (revision 1056407)
-+++ cpp/src/qmf/AgentSession.cpp (working copy)
-@@ -30,6 +30,7 @@
- #include "qmf/DataImpl.h"
- #include "qmf/QueryImpl.h"
- #include "qmf/agentCapability.h"
-+#include "qmf/constants.h"
- #include "qpid/sys/Mutex.h"
- #include "qpid/sys/Condition.h"
- #include "qpid/sys/Thread.h"
-@@ -84,6 +85,7 @@
- void complete(AgentEvent& e);
- void methodSuccess(AgentEvent& e);
- void raiseEvent(const Data& d);
++ //
++ // Methods from API handle
++ //
++ AgentSessionImpl(Connection& c, const string& o);
++ void setDomain(const string& d) { checkOpen(); domain = d; }
++ void setVendor(const string& v) { checkOpen(); attributes["_vendor"] = v; }
++ void setProduct(const string& p) { checkOpen(); attributes["_product"] = p; }
++ void setInstance(const string& i) { checkOpen(); attributes["_instance"] = i; }
++ void setAttribute(const string& k, const qpid::types::Variant& v) { checkOpen(); attributes[k] = v; }
++ const string& getName() const { return agentName; }
++ void open();
++ void close();
++ bool nextEvent(AgentEvent& e, Duration t);
++ int pendingEvents() const;
++
++ void setEventNotifier(EventNotifierImpl* eventNotifier);
++ EventNotifierImpl* getEventNotifier() const;
++
++ void registerSchema(Schema& s);
++ DataAddr addData(Data& d, const string& n, bool persist);
++ void delData(const DataAddr&);
++
++ void authAccept(AgentEvent& e);
++ void authReject(AgentEvent& e, const string& m);
++ void raiseException(AgentEvent& e, const string& s);
++ void raiseException(AgentEvent& e, const Data& d);
++ void response(AgentEvent& e, const Data& d);
++ void complete(AgentEvent& e);
++ void methodSuccess(AgentEvent& e);
++ void raiseEvent(const Data& d);
+ void raiseEvent(const Data& d, int s);
-
- private:
- typedef map<DataAddr, Data, DataAddrCompare> DataIndex;
-@@ -111,6 +113,12 @@
- bool externalStorage;
- bool autoAllowQueries;
- bool autoAllowMethods;
++
++ private:
++ typedef map<DataAddr, Data, DataAddrCompare> DataIndex;
++ typedef map<SchemaId, Schema, SchemaIdCompare> SchemaMap;
++
++ mutable qpid::sys::Mutex lock;
++ qpid::sys::Condition cond;
++ Connection connection;
++ Session session;
++ Sender directSender;
++ Sender topicSender;
++ string domain;
++ Variant::Map attributes;
++ Variant::Map options;
++ string agentName;
++ bool opened;
++ queue<AgentEvent> eventQueue;
++ EventNotifierImpl* eventNotifier;
++ qpid::sys::Thread* thread;
++ bool threadCanceled;
++ uint32_t bootSequence;
++ uint32_t interval;
++ uint64_t lastHeartbeat;
++ uint64_t lastVisit;
++ bool forceHeartbeat;
++ bool externalStorage;
++ bool autoAllowQueries;
++ bool autoAllowMethods;
+ uint32_t maxSubscriptions;
+ uint32_t minSubInterval;
+ uint32_t subLifetime;
+ bool publicEvents;
+ bool listenOnDirect;
+ bool strictSecurity;
- uint64_t schemaUpdateTime;
- string directBase;
- string topicBase;
-@@ -129,6 +137,7 @@
- void handleV1SchemaRequest(qpid::management::Buffer&, uint32_t, const Message&);
- void dispatch(Message);
- void sendHeartbeat();
++ uint32_t maxThreadWaitTime;
++ uint64_t schemaUpdateTime;
++ string directBase;
++ string topicBase;
++
++ SchemaMap schemata;
++ DataIndex globalIndex;
++ map<SchemaId, DataIndex, SchemaIdCompareNoHash> schemaIndex;
++
++ void checkOpen();
++ void setAgentName();
++ void enqueueEvent(const AgentEvent&);
++ void alertEventNotifierLH(bool readable);
++ void handleLocateRequest(const Variant::List& content, const Message& msg);
++ void handleMethodRequest(const Variant::Map& content, const Message& msg);
++ void handleQueryRequest(const Variant::Map& content, const Message& msg);
++ void handleSchemaRequest(AgentEvent&);
++ void handleV1SchemaRequest(qpid::management::Buffer&, uint32_t, const Message&);
++ void dispatch(Message);
++ void sendHeartbeat();
+ void send(Message, const Address&);
- void flushResponses(AgentEvent&, bool);
- void periodicProcessing(uint64_t);
- void run();
-@@ -163,6 +172,7 @@
- void AgentSession::complete(AgentEvent& e) { impl->complete(e); }
- void AgentSession::methodSuccess(AgentEvent& e) { impl->methodSuccess(e); }
- void AgentSession::raiseEvent(const Data& d) { impl->raiseEvent(d); }
-+void AgentSession::raiseEvent(const Data& d, int s) { impl->raiseEvent(d, s); }
-
- //========================================================================================
- // Impl Method Bodies
-@@ -172,10 +182,12 @@
- connection(c), domain("default"), opened(false), thread(0), threadCanceled(false),
- bootSequence(1), interval(60), lastHeartbeat(0), lastVisit(0), forceHeartbeat(false),
- externalStorage(false), autoAllowQueries(true), autoAllowMethods(true),
-+ maxSubscriptions(64), minSubInterval(3000), subLifetime(300), publicEvents(true),
-+ listenOnDirect(true), strictSecurity(false),
- schemaUpdateTime(uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now())))
- {
- //
-- // Set Capability Level to 1
-+ // Set Agent Capability Level
- //
- attributes["qmf.agent_capability"] = AGENT_CAPABILITY_0_8;
-
-@@ -208,6 +220,30 @@
- iter = optMap.find("allow-methods");
- if (iter != optMap.end())
- autoAllowMethods = iter->second.asBool();
-+
-+ iter = optMap.find("max-subscriptions");
-+ if (iter != optMap.end())
-+ maxSubscriptions = iter->second.asUint32();
-+
-+ iter = optMap.find("min-sub-interval");
-+ if (iter != optMap.end())
-+ minSubInterval = iter->second.asUint32();
++ void flushResponses(AgentEvent&, bool);
++ void periodicProcessing(uint64_t);
++ void run();
++ };
+
-+ iter = optMap.find("sub-lifetime");
-+ if (iter != optMap.end())
-+ subLifetime = iter->second.asUint32();
++ struct AgentSessionImplAccess {
++ static AgentSessionImpl& get(AgentSession& session);
++ static const AgentSessionImpl& get(const AgentSession& session);
++ };
++}
+
-+ iter = optMap.find("public-events");
-+ if (iter != optMap.end())
-+ publicEvents = iter->second.asBool();
+
-+ iter = optMap.find("listen-on-direct");
-+ if (iter != optMap.end())
-+ listenOnDirect = iter->second.asBool();
++#endif
+
-+ iter = optMap.find("strict-security");
-+ if (iter != optMap.end())
-+ strictSecurity = iter->second.asBool();
+diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
+index af83595..d084b8a 100644
+--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
++++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
+@@ -237,6 +237,8 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout)
+ if (!eventQueue.empty()) {
+ event = eventQueue.front();
+ eventQueue.pop();
++ if (eventQueue.empty())
++ alertEventNotifierLH(false);
+ return true;
}
- }
-
-@@ -225,6 +261,8 @@
- throw QmfException("The session is already open");
-
- const string addrArgs(";{create:never,node:{type:topic}}");
-+ const string routableAddr("direct-agent.route." + qpid::types::Uuid(true).str());
-+ attributes["_direct_subject"] = routableAddr;
-
- // Establish messaging addresses
- setAgentName();
-@@ -233,13 +271,20 @@
-
- // Create AMQP session, receivers, and senders
- session = connection.createSession();
-- Receiver directRx = session.createReceiver(directBase + "/" + agentName + addrArgs);
-+ Receiver directRx;
-+ Receiver routableDirectRx = session.createReceiver(topicBase + "/" + routableAddr + addrArgs);
- Receiver topicRx = session.createReceiver(topicBase + "/console.#" + addrArgs);
-
-- directRx.setCapacity(64);
-+ if (listenOnDirect && !strictSecurity) {
-+ directRx = session.createReceiver(directBase + "/" + agentName + addrArgs);
-+ directRx.setCapacity(64);
-+ }
-+
-+ routableDirectRx.setCapacity(64);
- topicRx.setCapacity(64);
-
-- directSender = session.createSender(directBase + addrArgs);
-+ if (!strictSecurity)
-+ directSender = session.createSender(directBase + addrArgs);
- topicSender = session.createSender(topicBase + addrArgs);
-
- // Start the receiver thread
-@@ -421,20 +466,18 @@
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
-- headers["method"] = "response";
-- headers["qmf.opcode"] = "_exception";
-- headers["qmf.content"] = "_data";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_RESPONSE;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_EXCEPTION;
-+ headers[protocol::HEADER_KEY_CONTENT] = protocol::HEADER_CONTENT_DATA;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-
- AgentEventImpl& eventImpl(AgentEventImplAccess::get(event));
- const DataImpl& dataImpl(DataImplAccess::get(data));
-
- msg.setCorrelationId(eventImpl.getCorrelationId());
- encode(dataImpl.asMap(), msg);
-- Sender sender(session.createSender(eventImpl.getReplyTo()));
-- sender.send(msg);
-- sender.close();
-+ send(msg, eventImpl.getReplyTo());
-
- QPID_LOG(trace, "SENT Exception to=" << eventImpl.getReplyTo());
+@@ -251,6 +253,20 @@ int ConsoleSessionImpl::pendingEvents() const
}
-@@ -461,10 +504,10 @@
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
-
-- headers["method"] = "response";
-- headers["qmf.opcode"] = "_method_response";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_RESPONSE;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_METHOD_RESPONSE;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
- AgentEventImpl& eventImpl(AgentEventImplAccess::get(event));
-
-@@ -477,9 +520,7 @@
-
- msg.setCorrelationId(eventImpl.getCorrelationId());
- encode(map, msg);
-- Sender sender(session.createSender(eventImpl.getReplyTo()));
-- sender.send(msg);
-- sender.close();
-+ send(msg, eventImpl.getReplyTo());
-
- QPID_LOG(trace, "SENT MethodResponse to=" << eventImpl.getReplyTo());
- }
-@@ -487,24 +528,50 @@
- void AgentSessionImpl::raiseEvent(const Data& data)
- {
-+ int severity(SEV_NOTICE);
-+ if (data.hasSchema()) {
-+ const Schema& schema(DataImplAccess::get(data).getSchema());
-+ if (schema.isValid())
-+ severity = schema.getDefaultSeverity();
-+ }
-+
-+ raiseEvent(data, severity);
++void ConsoleSessionImpl::setEventNotifier(EventNotifierImpl* notifier)
++{
++ qpid::sys::Mutex::ScopedLock l(lock);
++ this->eventNotifier = notifier;
+}
+
+
-+void AgentSessionImpl::raiseEvent(const Data& data, int severity)
++EventNotifierImpl* ConsoleSessionImpl::getEventNotifier() const
+{
- Message msg;
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
-+ string subject("agent.ind.event");
-
-- // TODO: add severity.package.class to key
-- // or modify to send only to subscriptions with matching queries
-+ if (data.hasSchema()) {
-+ const SchemaId& schemaId(data.getSchemaId());
-+ if (schemaId.getType() != SCHEMA_TYPE_EVENT)
-+ throw QmfException("Cannot call raiseEvent on data that is not an Event");
-+ subject = subject + "." + schemaId.getPackageName() + "." + schemaId.getName();
-+ }
-
-- headers["method"] = "indication";
-- headers["qmf.opcode"] = "_data_indication";
-- headers["qmf.content"] = "_event";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-- msg.setSubject("agent.ind.event");
-+ if (severity < SEV_EMERG || severity > SEV_DEBUG)
-+ throw QmfException("Invalid severity value");
-
-- encode(DataImplAccess::get(data).asMap(), msg);
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_INDICATION;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_DATA_INDICATION;
-+ headers[protocol::HEADER_KEY_CONTENT] = protocol::HEADER_CONTENT_EVENT;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-+ msg.setSubject(subject);
++ qpid::sys::Mutex::ScopedLock l(lock);
++ return this->eventNotifier;
++}
+
-+ Variant::List list;
-+ Variant::Map dataAsMap(DataImplAccess::get(data).asMap());
-+ dataAsMap["_severity"] = severity;
-+ dataAsMap["_timestamp"] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
-+ list.push_back(dataAsMap);
-+ encode(list, msg);
- topicSender.send(msg);
-
-- QPID_LOG(trace, "SENT EventIndication to=agent.ind.event");
-+ QPID_LOG(trace, "SENT EventIndication to=" << topicSender.getName() << "/" << subject);
- }
-
-
-@@ -558,7 +625,7 @@
-
- void AgentSessionImpl::handleLocateRequest(const Variant::List& predicate, const Message& msg)
++
+ uint32_t ConsoleSessionImpl::getAgentCount() const
{
-- QPID_LOG(trace, "RCVD AgentLocateRequest");
-+ QPID_LOG(trace, "RCVD AgentLocateRequest from=" << msg.getReplyTo());
-
- if (!predicate.empty()) {
- Query agentQuery(QUERY_OBJECT);
-@@ -573,28 +640,26 @@
- Variant::Map map;
- Variant::Map& headers(reply.getProperties());
-
-- headers["method"] = "indication";
-- headers["qmf.opcode"] = "_agent_locate_response";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_INDICATION;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_AGENT_LOCATE_RESPONSE;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-
- map["_values"] = attributes;
-- map["_values"].asMap()["timestamp"] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
-- map["_values"].asMap()["heartbeat_interval"] = interval;
-- map["_values"].asMap()["epoch"] = bootSequence;
-- map["_values"].asMap()["schemaUpdated"] = schemaUpdateTime;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_TIMESTAMP] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
-+ map["_values"].asMap()[protocol::AGENT_ATTR_HEARTBEAT_INTERVAL] = interval;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_EPOCH] = bootSequence;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP] = schemaUpdateTime;
-
- encode(map, reply);
-- Sender sender = session.createSender(msg.getReplyTo());
-- sender.send(reply);
-+ send(reply, msg.getReplyTo());
- QPID_LOG(trace, "SENT AgentLocateResponse to=" << msg.getReplyTo());
-- sender.close();
- }
-
-
- void AgentSessionImpl::handleMethodRequest(const Variant::Map& content, const Message& msg)
+ qpid::sys::Mutex::ScopedLock l(lock);
+@@ -292,8 +308,10 @@ void ConsoleSessionImpl::enqueueEventLH(const ConsoleEvent& event)
{
-- QPID_LOG(trace, "RCVD MethodRequest map=" << content << " from=" << msg.getReplyTo());
-+ QPID_LOG(trace, "RCVD MethodRequest map=" << content << " from=" << msg.getReplyTo() << " cid=" << msg.getCorrelationId());
-
- //
- // Construct an AgentEvent to be sent to the application.
-@@ -614,10 +679,6 @@
- }
- eventImpl->setMethodName(iter->second.asString());
-
-- iter = content.find("_object_id");
-- if (iter != content.end())
-- eventImpl->setDataAddr(DataAddr(new DataAddrImpl(iter->second.asMap())));
--
- iter = content.find("_arguments");
- if (iter != content.end())
- eventImpl->setArguments(iter->second.asMap());
-@@ -626,13 +687,39 @@
- if (iter != content.end())
- eventImpl->setArgumentSubtypes(iter->second.asMap());
-
-+ iter = content.find("_object_id");
-+ if (iter != content.end()) {
-+ DataAddr addr(new DataAddrImpl(iter->second.asMap()));
-+ eventImpl->setDataAddr(addr);
-+ DataIndex::const_iterator iter(globalIndex.find(addr));
-+ if (iter == globalIndex.end()) {
-+ AgentEvent event(eventImpl.release());
-+ raiseException(event, "No data object found with the specified address");
-+ return;
-+ }
-+
-+ const Schema& schema(DataImplAccess::get(iter->second).getSchema());
-+ if (schema.isValid()) {
-+ eventImpl->setSchema(schema);
-+ for (Variant::Map::const_iterator aIter = eventImpl->getArguments().begin();
-+ aIter != eventImpl->getArguments().end(); aIter++) {
-+ const Schema& schema(DataImplAccess::get(iter->second).getSchema());
-+ if (!SchemaImplAccess::get(schema).isValidMethodInArg(eventImpl->getMethodName(), aIter->first, aIter->second)) {
-+ AgentEvent event(eventImpl.release());
-+ raiseException(event, "Invalid argument: " + aIter->first);
-+ return;
-+ }
-+ }
-+ }
+ bool notify = eventQueue.empty();
+ eventQueue.push(event);
+- if (notify)
++ if (notify) {
+ cond.notify();
++ alertEventNotifierLH(true);
+ }
-+
- enqueueEvent(AgentEvent(eventImpl.release()));
- }
-
-
- void AgentSessionImpl::handleQueryRequest(const Variant::Map& content, const Message& msg)
- {
-- QPID_LOG(trace, "RCVD QueryRequest query=" << content << " from=" << msg.getReplyTo());
-+ QPID_LOG(trace, "RCVD QueryRequest query=" << content << " from=" << msg.getReplyTo() << " cid=" << msg.getCorrelationId());
-
- //
- // Construct an AgentEvent to be sent to the application or directly handled by the agent.
-@@ -668,19 +755,19 @@
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
-
-- headers["method"] = "response";
-- headers["qmf.opcode"] = "_query_response";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_RESPONSE;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_QUERY_RESPONSE;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-
- {
- qpid::sys::Mutex::ScopedLock l(lock);
- if (query.getTarget() == QUERY_SCHEMA_ID) {
-- headers["qmf.content"] = "_schema_id";
-+ headers[protocol::HEADER_KEY_CONTENT] = "_schema_id";
- for (iter = schemata.begin(); iter != schemata.end(); iter++)
- content.push_back(SchemaIdImplAccess::get(iter->first).asMap());
- } else if (query.getSchemaId().isValid()) {
-- headers["qmf.content"] = "_schema";
-+ headers[protocol::HEADER_KEY_CONTENT] = "_schema";
- iter = schemata.find(query.getSchemaId());
- if (iter != schemata.end())
- content.push_back(SchemaImplAccess::get(iter->second).asMap());
-@@ -698,9 +785,7 @@
-
- msg.setCorrelationId(eventImpl.getCorrelationId());
- encode(content, msg);
-- Sender sender(session.createSender(eventImpl.getReplyTo()));
-- sender.send(msg);
-- sender.close();
-+ send(msg, eventImpl.getReplyTo());
-
- QPID_LOG(trace, "SENT QueryResponse(Schema) to=" << eventImpl.getReplyTo());
}
-@@ -744,13 +829,11 @@
- Message reply;
- Variant::Map& headers(reply.getProperties());
-- headers["qmf.agent"] = agentName;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
- reply.setContent(replyContent);
-- Sender sender = session.createSender(msg.getReplyTo());
-- sender.send(reply);
-+ send(reply, msg.getReplyTo());
- QPID_LOG(trace, "SENT QMFv1 SchemaResponse to=" << msg.getReplyTo());
-- sender.close();
+@@ -602,6 +620,13 @@ void ConsoleSessionImpl::periodicProcessing(uint64_t seconds)
}
-@@ -759,12 +842,23 @@
- const Variant::Map& properties(msg.getProperties());
- Variant::Map::const_iterator iter;
-
-- iter = properties.find("x-amqp-0-10.app-id");
-- if (iter != properties.end() && iter->second.asString() == "qmf2") {
-+ //
-+ // If strict-security is enabled, make sure that reply-to address complies with the
-+ // strict-security addressing pattern (i.e. start with 'qmf.<domain>.topic/direct-console.').
-+ //
-+ if (strictSecurity && msg.getReplyTo()) {
-+ if (msg.getReplyTo().getName() != topicBase || msg.getReplyTo().getSubject().find("direct-console.") != 0) {
-+ QPID_LOG(warning, "Reply-to violates strict-security policy: " << msg.getReplyTo().str());
-+ return;
-+ }
-+ }
++void ConsoleSessionImpl::alertEventNotifierLH(bool readable)
++{
++ if (eventNotifier)
++ eventNotifier->setReadable(readable);
++}
+
-+ iter = properties.find(protocol::HEADER_KEY_APP_ID);
-+ if (iter != properties.end() && iter->second.asString() == protocol::HEADER_APP_ID_QMF) {
- //
- // Dispatch a QMFv2 formatted message
- //
-- iter = properties.find("qmf.opcode");
-+ iter = properties.find(protocol::HEADER_KEY_OPCODE);
- if (iter == properties.end()) {
- QPID_LOG(trace, "Message received with no 'qmf.opcode' header");
- return;
-@@ -776,7 +870,7 @@
- Variant::List content;
- decode(msg, content);
-
-- if (opcode == "_agent_locate_request") handleLocateRequest(content, msg);
-+ if (opcode == protocol::HEADER_OPCODE_AGENT_LOCATE_REQUEST) handleLocateRequest(content, msg);
- else {
- QPID_LOG(trace, "Unexpected QMFv2 opcode with 'amqp/list' content: " << opcode);
- }
-@@ -785,8 +879,8 @@
- Variant::Map content;
- decode(msg, content);
-
-- if (opcode == "_method_request") handleMethodRequest(content, msg);
-- else if (opcode == "_query_request") handleQueryRequest(content, msg);
-+ if (opcode == protocol::HEADER_OPCODE_METHOD_REQUEST) handleMethodRequest(content, msg);
-+ else if (opcode == protocol::HEADER_OPCODE_QUERY_REQUEST) handleQueryRequest(content, msg);
- else {
- QPID_LOG(trace, "Unexpected QMFv2 opcode with 'amqp/map' content: " << opcode);
- }
-@@ -835,17 +929,17 @@
- }
- }
-
-- headers["method"] = "indication";
-- headers["qmf.opcode"] = "_agent_heartbeat_indication";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_INDICATION;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_AGENT_HEARTBEAT_INDICATION;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
- msg.setSubject(address.str());
-
- map["_values"] = attributes;
-- map["_values"].asMap()["timestamp"] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
-- map["_values"].asMap()["heartbeat_interval"] = interval;
-- map["_values"].asMap()["epoch"] = bootSequence;
-- map["_values"].asMap()["schemaUpdated"] = schemaUpdateTime;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_TIMESTAMP] = uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()));
-+ map["_values"].asMap()[protocol::AGENT_ATTR_HEARTBEAT_INTERVAL] = interval;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_EPOCH] = bootSequence;
-+ map["_values"].asMap()[protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP] = schemaUpdateTime;
-
- encode(map, msg);
- topicSender.send(msg);
-@@ -853,19 +947,41 @@
++
+ void ConsoleSessionImpl::run()
+ {
+ QPID_LOG(debug, "ConsoleSession thread started");
+@@ -633,3 +658,14 @@ void ConsoleSessionImpl::run()
+ QPID_LOG(debug, "ConsoleSession thread exiting");
}
-
-+void AgentSessionImpl::send(Message msg, const Address& to)
-+{
-+ Sender sender;
+
-+ if (strictSecurity && to.getName() != topicBase) {
-+ QPID_LOG(warning, "Address violates strict-security policy: " << to);
-+ return;
-+ }
++ConsoleSessionImpl& ConsoleSessionImplAccess::get(ConsoleSession& session)
++{
++ return *session.impl;
++}
+
-+ if (to.getName() == directBase) {
-+ msg.setSubject(to.getSubject());
-+ sender = directSender;
-+ } else if (to.getName() == topicBase) {
-+ msg.setSubject(to.getSubject());
-+ sender = topicSender;
-+ } else
-+ sender = session.createSender(to);
+
-+ sender.send(msg);
++const ConsoleSessionImpl& ConsoleSessionImplAccess::get(const ConsoleSession& session)
++{
++ return *session.impl;
+}
+diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+index 478d24e..660fc9b 100644
+--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
++++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+@@ -27,6 +27,7 @@
+ #include "qmf/SchemaId.h"
+ #include "qmf/Schema.h"
+ #include "qmf/ConsoleEventImpl.h"
++#include "qmf/EventNotifierImpl.h"
+ #include "qmf/SchemaCache.h"
+ #include "qmf/Query.h"
+ #include "qpid/sys/Mutex.h"
+@@ -41,9 +42,14 @@
+ #include "qpid/messaging/Address.h"
+ #include "qpid/management/Buffer.h"
+ #include "qpid/types/Variant.h"
+
-+
- void AgentSessionImpl::flushResponses(AgentEvent& event, bool final)
- {
- Message msg;
- Variant::Map map;
- Variant::Map& headers(msg.getProperties());
-
-- headers["method"] = "response";
-- headers["qmf.opcode"] = "_query_response";
-- headers["qmf.content"] = "_data";
-- headers["qmf.agent"] = agentName;
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_RESPONSE;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_QUERY_RESPONSE;
-+ headers[protocol::HEADER_KEY_CONTENT] = protocol::HEADER_CONTENT_DATA;
-+ headers[protocol::HEADER_KEY_AGENT] = agentName;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
- if (!final)
-- headers["partial"] = Variant();
-+ headers[protocol::HEADER_KEY_PARTIAL] = Variant();
-
- Variant::List body;
- AgentEventImpl& eventImpl(AgentEventImplAccess::get(event));
-@@ -878,9 +994,7 @@
-
- msg.setCorrelationId(eventImpl.getCorrelationId());
- encode(body, msg);
-- Sender sender(session.createSender(eventImpl.getReplyTo()));
-- sender.send(msg);
-- sender.close();
-+ send(msg, eventImpl.getReplyTo());
-
- QPID_LOG(trace, "SENT QueryResponse to=" << eventImpl.getReplyTo());
- }
-@@ -894,6 +1008,7 @@
- //
- if (seconds == lastVisit)
- return;
-+ //uint64_t thisInterval(seconds - lastVisit);
- lastVisit = seconds;
-
- //
-Index: cpp/src/qmf/ConsoleEvent.cpp
-===================================================================
---- cpp/src/qmf/ConsoleEvent.cpp (revision 1056407)
-+++ cpp/src/qmf/ConsoleEvent.cpp (working copy)
-@@ -44,6 +44,8 @@
- Data ConsoleEvent::getData(uint32_t i) const { return impl->getData(i); }
- bool ConsoleEvent::isFinal() const { return impl->isFinal(); }
- const Variant::Map& ConsoleEvent::getArguments() const { return impl->getArguments(); }
-+int ConsoleEvent::getSeverity() const { return impl->getSeverity(); }
-+uint64_t ConsoleEvent::getTimestamp() const { return impl->getTimestamp(); }
-
-
- SchemaId ConsoleEventImpl::getSchemaId(uint32_t i) const
-Index: cpp/src/qmf/Query.cpp
-===================================================================
---- cpp/src/qmf/Query.cpp (revision 1056407)
-+++ cpp/src/qmf/Query.cpp (working copy)
-@@ -50,7 +50,7 @@
- bool Query::matchesPredicate(const qpid::types::Variant::Map& map) const { return impl->matchesPredicate(map); }
-
-
--QueryImpl::QueryImpl(const Variant::Map& map)
-+QueryImpl::QueryImpl(const Variant::Map& map) : predicateCompiled(false)
- {
- Variant::Map::const_iterator iter;
-
-Index: cpp/src/qmf/ConsoleSession.cpp
-===================================================================
---- cpp/src/qmf/ConsoleSession.cpp (revision 1056407)
-+++ cpp/src/qmf/ConsoleSession.cpp (working copy)
-@@ -25,14 +25,20 @@
- #include "qmf/SchemaId.h"
- #include "qmf/SchemaImpl.h"
- #include "qmf/ConsoleEventImpl.h"
-+#include "qmf/constants.h"
- #include "qpid/log/Statement.h"
- #include "qpid/messaging/AddressParser.h"
- #include "qpid/messaging/Sender.h"
- #include "qpid/messaging/Receiver.h"
-
- using namespace std;
--using namespace qpid::messaging;
- using namespace qmf;
-+using qpid::messaging::Address;
-+using qpid::messaging::Connection;
-+using qpid::messaging::Receiver;
-+using qpid::messaging::Sender;
-+using qpid::messaging::Duration;
-+using qpid::messaging::Message;
- using qpid::types::Variant;
-
- typedef qmf::PrivateImplRef<ConsoleSession> PI;
-@@ -51,15 +57,17 @@
- uint32_t ConsoleSession::getAgentCount() const { return impl->getAgentCount(); }
- Agent ConsoleSession::getAgent(uint32_t i) const { return impl->getAgent(i); }
- Agent ConsoleSession::getConnectedBrokerAgent() const { return impl->getConnectedBrokerAgent(); }
-+Subscription ConsoleSession::subscribe(const Query& q, const string& f, const string& o) { return impl->subscribe(q, f, o); }
-+Subscription ConsoleSession::subscribe(const string& q, const string& f, const string& o) { return impl->subscribe(q, f, o); }
-
- //========================================================================================
- // Impl Method Bodies
- //========================================================================================
++#include <boost/shared_ptr.hpp>
+ #include <map>
+ #include <queue>
- ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
-- connection(c), domain("default"), maxAgentAgeMinutes(5), opened(false),
-- thread(0), threadCanceled(false),
-- lastVisit(0), lastAgePass(0), connectedBrokerInAgentList(false), schemaCache(new SchemaCache())
-+ connection(c), domain("default"), maxAgentAgeMinutes(5),
-+ opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
-+ connectedBrokerInAgentList(false), schemaCache(new SchemaCache())
- {
- if (!options.empty()) {
- qpid::messaging::AddressParser parser(options);
-@@ -75,6 +83,14 @@
- iter = optMap.find("max-agent-age");
- if (iter != optMap.end())
- maxAgentAgeMinutes = iter->second.asUint32();
++using namespace boost;
++using namespace std;
+
-+ iter = optMap.find("listen-on-direct");
-+ if (iter != optMap.end())
-+ listenOnDirect = iter->second.asBool();
+ namespace qmf {
+ class ConsoleSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable {
+ public:
+@@ -59,6 +65,10 @@ namespace qmf {
+ void close();
+ bool nextEvent(ConsoleEvent& e, qpid::messaging::Duration t);
+ int pendingEvents() const;
+
-+ iter = optMap.find("strict-security");
-+ if (iter != optMap.end())
-+ strictSecurity = iter->second.asBool();
- }
- }
-
-@@ -110,9 +126,17 @@
- enqueueEventLH(eventImpl.release());
- }
-
-- if (!connectedBrokerInAgentList && agentQuery.matchesPredicate(connectedBrokerAgent.getAttributes())) {
-+ if (!connectedBrokerInAgentList && connectedBrokerAgent.isValid() &&
-+ agentQuery.matchesPredicate(connectedBrokerAgent.getAttributes())) {
- agents[connectedBrokerAgent.getName()] = connectedBrokerAgent;
- connectedBrokerInAgentList = true;
++ void setEventNotifier(EventNotifierImpl* notifier);
++ EventNotifierImpl* getEventNotifier() const;
+
-+ //
-+ // Enqueue a notification of the new agent.
-+ //
-+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_ADD));
-+ eventImpl->setAgent(connectedBrokerAgent);
-+ enqueueEventLH(ConsoleEvent(eventImpl.release()));
- }
- }
-
-@@ -133,24 +157,26 @@
- directBase = "qmf." + domain + ".direct";
- topicBase = "qmf." + domain + ".topic";
-
-- string myKey("qmf-console-" + qpid::types::Uuid(true).str());
-+ string myKey("direct-console." + qpid::types::Uuid(true).str());
-
-- replyAddress = Address(directBase + "/" + myKey + ";{node:{type:topic}}");
-+ replyAddress = Address(topicBase + "/" + myKey + ";{node:{type:topic}}");
-
- // Create AMQP session, receivers, and senders
- session = connection.createSession();
- Receiver directRx = session.createReceiver(replyAddress);
- Receiver topicRx = session.createReceiver(topicBase + "/agent.#"); // TODO: be more discriminating
-- Receiver legacyRx = session.createReceiver("amq.direct/" + myKey + ";{node:{type:topic}}");
-+ if (!strictSecurity) {
-+ Receiver legacyRx = session.createReceiver("amq.direct/" + myKey + ";{node:{type:topic}}");
-+ legacyRx.setCapacity(64);
-+ directSender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
-+ directSender.setCapacity(128);
-+ }
-
- directRx.setCapacity(64);
- topicRx.setCapacity(128);
-- legacyRx.setCapacity(64);
-
-- directSender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
- topicSender = session.createSender(topicBase + ";{create:never,node:{type:topic}}");
-
-- directSender.setCapacity(64);
- topicSender.setCapacity(128);
+ uint32_t getAgentCount() const;
+ Agent getAgent(uint32_t i) const;
+ Agent getConnectedBrokerAgent() const { return connectedBrokerAgent; }
+@@ -80,6 +90,7 @@ namespace qmf {
+ Query agentQuery;
+ bool opened;
+ std::queue<ConsoleEvent> eventQueue;
++ EventNotifierImpl* eventNotifier;
+ qpid::sys::Thread* thread;
+ bool threadCanceled;
+ uint64_t lastVisit;
+@@ -102,11 +113,17 @@ namespace qmf {
+ void handleAgentUpdate(const std::string&, const qpid::types::Variant::Map&, const qpid::messaging::Message&);
+ void handleV1SchemaResponse(qpid::management::Buffer&, uint32_t, const qpid::messaging::Message&);
+ void periodicProcessing(uint64_t);
++ void alertEventNotifierLH(bool readable);
+ void run();
+ uint32_t correlator() { qpid::sys::Mutex::ScopedLock l(corrlock); return nextCorrelator++; }
- // Start the receiver thread
-@@ -219,6 +245,18 @@
+ friend class AgentImpl;
+ };
++
++ struct ConsoleSessionImplAccess {
++ static ConsoleSessionImpl& get(ConsoleSession& session);
++ static const ConsoleSessionImpl& get(const ConsoleSession& session);
++ };
}
-
-+Subscription ConsoleSessionImpl::subscribe(const Query&, const string&, const string&)
+ #endif
+diff --git a/qpid/cpp/src/qmf/EventNotifierImpl.cpp b/qpid/cpp/src/qmf/EventNotifierImpl.cpp
+new file mode 100644
+index 0000000..20114aa
+--- /dev/null
++++ b/qpid/cpp/src/qmf/EventNotifierImpl.cpp
+@@ -0,0 +1,56 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++
++#include "qmf/EventNotifierImpl.h"
++#include "qmf/AgentSessionImpl.h"
++#include "qmf/ConsoleSessionImpl.h"
++
++EventNotifierImpl::EventNotifierImpl(AgentSession& agentSession)
++ : readable(false), agent(agentSession)
+{
-+ return Subscription();
++ AgentSessionImplAccess::get(agent).setEventNotifier(this);
+}
+
+
-+Subscription ConsoleSessionImpl::subscribe(const string&, const string&, const string&)
++EventNotifierImpl::EventNotifierImpl(ConsoleSession& consoleSession)
++ : readable(false), console(consoleSession)
+{
-+ return Subscription();
++ ConsoleSessionImplAccess::get(console).setEventNotifier(this);
+}
+
+
- void ConsoleSessionImpl::enqueueEvent(const ConsoleEvent& event)
- {
- qpid::sys::Mutex::ScopedLock l(lock);
-@@ -241,17 +279,17 @@
- Variant::Map::const_iterator iter;
- Variant::Map::const_iterator oiter;
-
-- oiter = properties.find("qmf.opcode");
-- iter = properties.find("x-amqp-0-10.app-id");
-+ oiter = properties.find(protocol::HEADER_KEY_OPCODE);
-+ iter = properties.find(protocol::HEADER_KEY_APP_ID);
- if (iter == properties.end())
- iter = properties.find("app_id");
-- if (iter != properties.end() && iter->second.asString() == "qmf2" && oiter != properties.end()) {
-+ if (iter != properties.end() && iter->second.asString() == protocol::HEADER_APP_ID_QMF && oiter != properties.end()) {
- //
- // Dispatch a QMFv2 formatted message
- //
- const string& opcode = oiter->second.asString();
-
-- iter = properties.find("qmf.agent");
-+ iter = properties.find(protocol::HEADER_KEY_AGENT);
- if (iter == properties.end()) {
- QPID_LOG(trace, "Message received with no 'qmf.agent' header");
- return;
-@@ -269,7 +307,7 @@
- }
-
- if (msg.getContentType() == "amqp/map" &&
-- (opcode == "_agent_heartbeat_indication" || opcode == "_agent_locate_response")) {
-+ (opcode == protocol::HEADER_OPCODE_AGENT_HEARTBEAT_INDICATION || opcode == protocol::HEADER_OPCODE_AGENT_LOCATE_RESPONSE)) {
- //
- // This is the one case where it's ok (necessary actually) to receive a QMFv2
- // message from an unknown agent (how else are they going to get known?)
-@@ -289,8 +327,8 @@
- Variant::Map content;
- decode(msg, content);
-
-- if (opcode == "_exception") agentImpl.handleException(content, msg);
-- else if (opcode == "_method_response") agentImpl.handleMethodResponse(content, msg);
-+ if (opcode == protocol::HEADER_OPCODE_EXCEPTION) agentImpl.handleException(content, msg);
-+ else if (opcode == protocol::HEADER_OPCODE_METHOD_RESPONSE) agentImpl.handleMethodResponse(content, msg);
- else
- QPID_LOG(error, "Received a map-formatted QMFv2 message with opcode=" << opcode);
-
-@@ -301,8 +339,8 @@
- Variant::List content;
- decode(msg, content);
-
-- if (opcode == "_query_response") agentImpl.handleQueryResponse(content, msg);
-- else if (opcode == "_data_indication") agentImpl.handleDataIndication(content, msg);
-+ if (opcode == protocol::HEADER_OPCODE_QUERY_RESPONSE) agentImpl.handleQueryResponse(content, msg);
-+ else if (opcode == protocol::HEADER_OPCODE_DATA_INDICATION) agentImpl.handleDataIndication(content, msg);
- else
- QPID_LOG(error, "Received a list-formatted QMFv2 message with opcode=" << opcode);
-
-@@ -336,15 +374,17 @@
- Message msg;
- Variant::Map& headers(msg.getProperties());
-
-- headers["method"] = "request";
-- headers["qmf.opcode"] = "_agent_locate_request";
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_REQUEST;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_AGENT_LOCATE_REQUEST;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-
- msg.setReplyTo(replyAddress);
- msg.setCorrelationId("broker-locate");
- msg.setSubject("broker");
-
-- directSender.send(msg);
-+ Sender sender = session.createSender(directBase + ";{create:never,node:{type:topic}}");
-+ sender.send(msg);
-+ sender.close();
-
- QPID_LOG(trace, "SENT AgentLocate to broker");
- }
-@@ -354,19 +394,20 @@
- {
- Message msg;
- Variant::Map& headers(msg.getProperties());
-+ static const string subject("console.request.agent_locate");
-
-- headers["method"] = "request";
-- headers["qmf.opcode"] = "_agent_locate_request";
-- headers["x-amqp-0-10.app-id"] = "qmf2";
-+ headers[protocol::HEADER_KEY_METHOD] = protocol::HEADER_METHOD_REQUEST;
-+ headers[protocol::HEADER_KEY_OPCODE] = protocol::HEADER_OPCODE_AGENT_LOCATE_REQUEST;
-+ headers[protocol::HEADER_KEY_APP_ID] = protocol::HEADER_APP_ID_QMF;
-
- msg.setReplyTo(replyAddress);
- msg.setCorrelationId("agent-locate");
-- msg.setSubject("console.request.agent_locate");
-+ msg.setSubject(subject);
- encode(agentQuery.getPredicate(), msg);
-
- topicSender.send(msg);
-
-- QPID_LOG(trace, "SENT AgentLocate to topic");
-+ QPID_LOG(trace, "SENT AgentLocate to=" << topicSender.getName() << "/" << subject);
- }
-
-
-@@ -382,17 +423,28 @@
- return;
- Variant::Map attrs(iter->second.asMap());
-
-- iter = attrs.find("epoch");
-+ iter = attrs.find(protocol::AGENT_ATTR_EPOCH);
- if (iter != attrs.end())
- epoch = iter->second.asUint32();
-
- if (cid == "broker-locate") {
- qpid::sys::Mutex::ScopedLock l(lock);
-- agent = Agent(new AgentImpl(agentName, epoch, *this));
-+ auto_ptr<AgentImpl> impl(new AgentImpl(agentName, epoch, *this));
-+ for (iter = attrs.begin(); iter != attrs.end(); iter++)
-+ if (iter->first != protocol::AGENT_ATTR_EPOCH)
-+ impl->setAttribute(iter->first, iter->second);
-+ agent = Agent(impl.release());
- connectedBrokerAgent = agent;
- if (!agentQuery || agentQuery.matchesPredicate(attrs)) {
- connectedBrokerInAgentList = true;
- agents[agentName] = agent;
++EventNotifierImpl::~EventNotifierImpl()
++{
++ if (agent.isValid())
++ AgentSessionImplAccess::get(agent).setEventNotifier(NULL);
++ if (console.isValid())
++ ConsoleSessionImplAccess::get(console).setEventNotifier(NULL);
++}
++
++void EventNotifierImpl::setReadable(bool readable)
++{
++ update(readable);
++ this->readable = readable;
++}
++
++
++bool EventNotifierImpl::isReadable() const
++{
++ return this->readable;
++}
+diff --git a/qpid/cpp/src/qmf/EventNotifierImpl.h b/qpid/cpp/src/qmf/EventNotifierImpl.h
+new file mode 100644
+index 0000000..d85f997
+--- /dev/null
++++ b/qpid/cpp/src/qmf/EventNotifierImpl.h
+@@ -0,0 +1,48 @@
++#ifndef __QMF_EVENT_NOTIFIER_IMPL_H
++#define __QMF_EVENT_NOTIFIER_IMPL_H
+
-+ //
-+ // Enqueue a notification of the new agent.
-+ //
-+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_ADD));
-+ eventImpl->setAgent(agent);
-+ enqueueEventLH(ConsoleEvent(eventImpl.release()));
- }
- return;
- }
-@@ -415,7 +467,7 @@
- //
- auto_ptr<AgentImpl> impl(new AgentImpl(agentName, epoch, *this));
- for (iter = attrs.begin(); iter != attrs.end(); iter++)
-- if (iter->first != "epoch")
-+ if (iter->first != protocol::AGENT_ATTR_EPOCH)
- impl->setAttribute(iter->first, iter->second);
- agent = Agent(impl.release());
- agents[agentName] = agent;
-@@ -430,6 +482,7 @@
- //
- // This is a refresh of an agent we are already tracking.
- //
-+ bool detectedRestart(false);
- agent = aIter->second;
- AgentImpl& impl(AgentImplAccess::get(agent));
- impl.touch();
-@@ -442,19 +495,23 @@
- auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_RESTART));
- eventImpl->setAgent(agent);
- enqueueEventLH(ConsoleEvent(eventImpl.release()));
-+ detectedRestart = true;
- }
-
-- iter = attrs.find("schemaUpdated");
-+ iter = attrs.find(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP);
- if (iter != attrs.end()) {
- uint64_t ts(iter->second.asUint64());
-- if (ts > impl.getAttribute("schemaUpdated").asUint64()) {
-+ if (ts > impl.getAttribute(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP).asUint64()) {
- //
- // The agent has added new schema entries since we last heard from it.
-- // Enqueue a notification.
-+ // Update the attribute and, if this doesn't accompany a restart, enqueue a notification.
- //
-- auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_SCHEMA_UPDATE));
-- eventImpl->setAgent(agent);
-- enqueueEventLH(ConsoleEvent(eventImpl.release()));
-+ if (!detectedRestart) {
-+ auto_ptr<ConsoleEventImpl> eventImpl(new ConsoleEventImpl(CONSOLE_AGENT_SCHEMA_UPDATE));
-+ eventImpl->setAgent(agent);
-+ enqueueEventLH(ConsoleEvent(eventImpl.release()));
-+ }
-+ impl.setAttribute(protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP, iter->second);
- }
- }
- }
-Index: cpp/src/qmf/AgentSubscription.h
-===================================================================
---- cpp/src/qmf/AgentSubscription.h (revision 0)
-+++ cpp/src/qmf/AgentSubscription.h (revision 0)
-@@ -0,0 +1,52 @@
-+#ifndef _QMF_AGENT_SUBSCRIPTION_H_
-+#define _QMF_AGENT_SUBSCRIPTION_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
@@ -1577,100 +1598,50 @@ Index: cpp/src/qmf/AgentSubscription.h
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
-+ *
++ *
+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
++ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/sys/IntegerTypes.h"
-+#include "qpid/types/Variant.h"
-+#include "qmf/Query.h"
-+#include "qmf/Data.h"
-+#include <boost/shared_ptr.hpp>
++#include "qmf/AgentSession.h"
++#include "qmf/ConsoleSession.h"
++
++namespace qmf
++{
++ class EventNotifierImpl {
++ private:
++ bool readable;
++ AgentSession agent;
++ ConsoleSession console;
+
-+namespace qmf {
-+ class AgentSubscription {
+ public:
-+ AgentSubscription(uint64_t _id, uint64_t _interval, uint64_t _life,
-+ const std::string& _replyTo, const std::string& _cid, Query _query);
-+ ~AgentSubscription();
-+ bool tick(uint64_t seconds);
-+ void keepalive() { timeSinceKeepalive = 0; }
++ EventNotifierImpl(AgentSession& agentSession);
++ EventNotifierImpl(ConsoleSession& consoleSession);
++ virtual ~EventNotifierImpl();
+
-+ private:
-+ uint64_t id;
-+ uint64_t interval;
-+ uint64_t lifetime;
-+ uint64_t timeSincePublish;
-+ uint64_t timeSinceKeepalive;
-+ const std::string replyTo;
-+ const std::string cid;
-+ Query query;
-+ };
++ void setReadable(bool readable);
++ bool isReadable() const;
+
++ protected:
++ virtual void update(bool readable) = 0;
++ };
+}
+
+#endif
-Index: cpp/src/qmf/Data.cpp
-===================================================================
---- cpp/src/qmf/Data.cpp (revision 1056407)
-+++ cpp/src/qmf/Data.cpp (working copy)
-@@ -21,8 +21,10 @@
-
- #include "qmf/DataImpl.h"
- #include "qmf/DataAddrImpl.h"
-+#include "qmf/SchemaImpl.h"
- #include "qmf/SchemaIdImpl.h"
- #include "qmf/PrivateImplRef.h"
-+#include "qmf/SchemaProperty.h"
-
- using namespace std;
- using namespace qmf;
-@@ -35,8 +37,7 @@
- Data::~Data() { PI::dtor(*this); }
- Data& Data::operator=(const Data& s) { return PI::assign(*this, s); }
-
--Data::Data(const SchemaId& s) { PI::ctor(*this, new DataImpl(s)); }
--void Data::setSchema(const SchemaId& s) { impl->setSchema(s); }
-+Data::Data(const Schema& s) { PI::ctor(*this, new DataImpl(s)); }
- void Data::setAddr(const DataAddr& a) { impl->setAddr(a); }
- void Data::setProperty(const string& k, const qpid::types::Variant& v) { impl->setProperty(k, v); }
- void Data::overwriteProperties(const qpid::types::Variant::Map& m) { impl->overwriteProperties(m); }
-@@ -103,6 +104,20 @@
- }
-
-
-+void DataImpl::setProperty(const std::string& k, const qpid::types::Variant& v)
-+{
-+ if (schema.isValid()) {
-+ //
-+ // If we have a valid schema, make sure that the property is included in the
-+ // schema and that the variant type is compatible with the schema type.
-+ //
-+ if (!SchemaImplAccess::get(schema).isValidProperty(k, v))
-+ throw QmfException("Property '" + k + "' either not in the schema or value is of incompatible type");
-+ }
-+ properties[k] = v;
-+}
-+
+
- DataImpl& DataImplAccess::get(Data& item)
- {
- return *item.impl;
-Index: cpp/src/qmf/constants.cpp
-===================================================================
---- cpp/src/qmf/constants.cpp (revision 0)
-+++ cpp/src/qmf/constants.cpp (revision 0)
-@@ -0,0 +1,77 @@
+diff --git a/qpid/cpp/src/qmf/PosixEventNotifier.cpp b/qpid/cpp/src/qmf/PosixEventNotifier.cpp
+new file mode 100644
+index 0000000..b5c7121
+--- /dev/null
++++ b/qpid/cpp/src/qmf/PosixEventNotifier.cpp
+@@ -0,0 +1,63 @@
+/*
-+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
@@ -1678,81 +1649,68 @@ Index: cpp/src/qmf/constants.cpp
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
-+ *
++ *
+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
++ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "constants.h"
++#include "qmf/posix/EventNotifier.h"
++#include "qmf/PosixEventNotifierImpl.h"
++#include "qmf/PrivateImplRef.h"
+
-+using namespace std;
+using namespace qmf;
++using namespace std;
+
-+/**
-+ * Header key strings
-+ */
-+const string protocol::HEADER_KEY_APP_ID = "x-amqp-0-10.app-id";
-+const string protocol::HEADER_KEY_METHOD = "method";
-+const string protocol::HEADER_KEY_OPCODE = "qmf.opcode";
-+const string protocol::HEADER_KEY_AGENT = "qmf.agent";
-+const string protocol::HEADER_KEY_CONTENT = "qmf.content";
-+const string protocol::HEADER_KEY_PARTIAL = "partial";
++typedef qmf::PrivateImplRef<posix::EventNotifier> PI;
+
-+/**
-+ * Header values per-key
-+ */
-+const string protocol::HEADER_APP_ID_QMF = "qmf2";
++posix::EventNotifier::EventNotifier(AgentSession& agentSession)
++{
++ PI::ctor(*this, new PosixEventNotifierImpl(agentSession));
++}
+
-+const string protocol::HEADER_METHOD_REQUEST = "request";
-+const string protocol::HEADER_METHOD_RESPONSE = "response";
-+const string protocol::HEADER_METHOD_INDICATION = "indication";
+
-+const string protocol::HEADER_OPCODE_EXCEPTION = "_exception";
-+const string protocol::HEADER_OPCODE_AGENT_LOCATE_REQUEST = "_agent_locate_request";
-+const string protocol::HEADER_OPCODE_AGENT_LOCATE_RESPONSE = "_agent_locate_response";
-+const string protocol::HEADER_OPCODE_AGENT_HEARTBEAT_INDICATION = "_agent_heartbeat_indication";
-+const string protocol::HEADER_OPCODE_QUERY_REQUEST = "_query_request";
-+const string protocol::HEADER_OPCODE_QUERY_RESPONSE = "_query_response";
-+const string protocol::HEADER_OPCODE_SUBSCRIBE_REQUEST = "_subscribe_request";
-+const string protocol::HEADER_OPCODE_SUBSCRIBE_RESPONSE = "_subscribe_response";
-+const string protocol::HEADER_OPCODE_SUBSCRIBE_CANCEL_INDICATION = "_subscribe_cancel_indication";
-+const string protocol::HEADER_OPCODE_SUBSCRIBE_REFRESH_INDICATION = "_subscribe_refresh_indication";
-+const string protocol::HEADER_OPCODE_DATA_INDICATION = "_data_indication";
-+const string protocol::HEADER_OPCODE_METHOD_REQUEST = "_method_request";
-+const string protocol::HEADER_OPCODE_METHOD_RESPONSE = "_method_response";
++posix::EventNotifier::EventNotifier(ConsoleSession& consoleSession)
++{
++ PI::ctor(*this, new PosixEventNotifierImpl(consoleSession));
++}
+
-+const string protocol::HEADER_CONTENT_SCHEMA_ID = "_schema_id";
-+const string protocol::HEADER_CONTENT_SCHEMA_CLASS = "_schema_class";
-+const string protocol::HEADER_CONTENT_OBJECT_ID = "_object_id";
-+const string protocol::HEADER_CONTENT_DATA = "_data";
-+const string protocol::HEADER_CONTENT_EVENT = "_event";
-+const string protocol::HEADER_CONTENT_QUERY = "_query";
+
-+/**
-+ * Keywords for Agent attributes
-+ */
-+const string protocol::AGENT_ATTR_VENDOR = "_vendor";
-+const string protocol::AGENT_ATTR_PRODUCT = "_product";
-+const string protocol::AGENT_ATTR_INSTANCE = "_instance";
-+const string protocol::AGENT_ATTR_NAME = "_name";
-+const string protocol::AGENT_ATTR_TIMESTAMP = "_timestamp";
-+const string protocol::AGENT_ATTR_HEARTBEAT_INTERVAL = "_heartbeat_interval";
-+const string protocol::AGENT_ATTR_EPOCH = "_epoch";
-+const string protocol::AGENT_ATTR_SCHEMA_UPDATED_TIMESTAMP = "_schema_updated";
-Index: cpp/src/qmf/Subscription.cpp
-===================================================================
---- cpp/src/qmf/Subscription.cpp (revision 0)
-+++ cpp/src/qmf/Subscription.cpp (revision 0)
-@@ -0,0 +1,88 @@
++posix::EventNotifier::EventNotifier(const posix::EventNotifier& that)
++ : Handle<PosixEventNotifierImpl>()
++{
++ PI::copy(*this, that);
++}
++
++
++posix::EventNotifier::~EventNotifier()
++{
++ PI::dtor(*this);
++}
++
++posix::EventNotifier& posix::EventNotifier::operator=(const posix::EventNotifier& that)
++{
++ return PI::assign(*this, that);
++}
++
++
++int posix::EventNotifier::getHandle() const
++{
++ return impl->getHandle();
++}
++
+diff --git a/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp b/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
+new file mode 100644
+index 0000000..abc9cad
+--- /dev/null
++++ b/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
+@@ -0,0 +1,108 @@
+/*
-+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
@@ -1760,14832 +1718,780 @@ Index: cpp/src/qmf/Subscription.cpp
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
-+ *
++ *
+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
++ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "qmf/PrivateImplRef.h"
-+#include "qmf/exceptions.h"
-+#include "qmf/SubscriptionImpl.h"
-+#include "qmf/DataImpl.h"
++#include "PosixEventNotifierImpl.h"
+
-+using namespace std;
-+using namespace qmf;
-+using qpid::types::Variant;
++#include <fcntl.h>
++#include <unistd.h>
+
-+typedef PrivateImplRef<Subscription> PI;
++#define BUFFER_SIZE 10
+
-+Subscription::Subscription(SubscriptionImpl* impl) { PI::ctor(*this, impl); }
-+Subscription::Subscription(const Subscription& s) : qmf::Handle<SubscriptionImpl>() { PI::copy(*this, s); }
-+Subscription::~Subscription() { PI::dtor(*this); }
-+Subscription& Subscription::operator=(const Subscription& s) { return PI::assign(*this, s); }
++using namespace qmf;
+
-+void Subscription::cancel() { impl->cancel(); }
-+bool Subscription::isActive() const { return impl->isActive(); }
-+void Subscription::lock() { impl->lock(); }
-+void Subscription::unlock() { impl->unlock(); }
-+uint32_t Subscription::getDataCount() const { return impl->getDataCount(); }
-+Data Subscription::getData(uint32_t i) const { return impl->getData(i); }
++PosixEventNotifierImpl::PosixEventNotifierImpl(AgentSession& agentSession)
++ : EventNotifierImpl(agentSession)
++{
++ openHandle();
++}
+
+
-+void SubscriptionImpl::cancel()
++PosixEventNotifierImpl::PosixEventNotifierImpl(ConsoleSession& consoleSession)
++ : EventNotifierImpl(consoleSession)
+{
++ openHandle();
+}
+
+
-+bool SubscriptionImpl::isActive() const
++PosixEventNotifierImpl::~PosixEventNotifierImpl()
+{
-+ return false;
++ closeHandle();
+}
+
+
-+void SubscriptionImpl::lock()
++void PosixEventNotifierImpl::update(bool readable)
+{
++ char buffer[BUFFER_SIZE];
++
++ if(readable && !this->isReadable()) {
++ (void) ::write(myHandle, "1", 1);
++ }
++ else if(!readable && this->isReadable()) {
++ (void) ::read(yourHandle, buffer, BUFFER_SIZE);
++ }
+}
+
+
-+void SubscriptionImpl::unlock()
++void PosixEventNotifierImpl::openHandle()
+{
++ int pair[2];
++
++ if(::pipe(pair) == -1)
++ throw QmfException("Unable to open event notifier handle.");
++
++ yourHandle = pair[0];
++ myHandle = pair[1];
++
++ int flags;
++
++ flags = ::fcntl(yourHandle, F_GETFL);
++ if((::fcntl(yourHandle, F_SETFL, flags | O_NONBLOCK)) == -1)
++ throw QmfException("Unable to make remote handle non-blocking.");
++
++ flags = ::fcntl(myHandle, F_GETFL);
++ if((::fcntl(myHandle, F_SETFL, flags | O_NONBLOCK)) == -1)
++ throw QmfException("Unable to make local handle non-blocking.");
+}
+
+
-+uint32_t SubscriptionImpl::getDataCount() const
++void PosixEventNotifierImpl::closeHandle()
+{
-+ return 0;
++ if(myHandle > 0) {
++ ::close(myHandle);
++ myHandle = -1;
++ }
++
++ if(yourHandle > 0) {
++ ::close(yourHandle);
++ yourHandle = -1;
++ }
+}
+
+
-+Data SubscriptionImpl::getData(uint32_t) const
++PosixEventNotifierImpl& PosixEventNotifierImplAccess::get(posix::EventNotifier& notifier)
+{
-+ return Data();
++ return *notifier.impl;
+}
+
+
-+SubscriptionImpl& SubscriptionImplAccess::get(Subscription& item)
++const PosixEventNotifierImpl& PosixEventNotifierImplAccess::get(const posix::EventNotifier& notifier)
+{
-+ return *item.impl;
++ return *notifier.impl;
+}
+
+diff --git a/qpid/cpp/src/qmf/PosixEventNotifierImpl.h b/qpid/cpp/src/qmf/PosixEventNotifierImpl.h
+new file mode 100644
+index 0000000..c8a7446
+--- /dev/null
++++ b/qpid/cpp/src/qmf/PosixEventNotifierImpl.h
+@@ -0,0 +1,61 @@
++#ifndef __QMF_POSIX_EVENT_NOTIFIER_IMPL_H
++#define __QMF_POSIX_EVENT_NOTIFIER_IMPL_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 "qmf/posix/EventNotifier.h"
++#include "qmf/EventNotifierImpl.h"
++#include "qpid/RefCounted.h"
+
-+const SubscriptionImpl& SubscriptionImplAccess::get(const Subscription& item)
++namespace qmf
+{
-+ return *item.impl;
++ class AgentSession;
++ class ConsoleSession;
++
++ class PosixEventNotifierImpl : public EventNotifierImpl, public virtual qpid::RefCounted
++ {
++ public:
++ PosixEventNotifierImpl(AgentSession& agentSession);
++ PosixEventNotifierImpl(ConsoleSession& consoleSession);
++ virtual ~PosixEventNotifierImpl();
++
++ int getHandle() const { return yourHandle; }
++
++ private:
++ int myHandle;
++ int yourHandle;
++
++ void openHandle();
++ void closeHandle();
++
++ protected:
++ void update(bool readable);
++ };
++
++ struct PosixEventNotifierImplAccess
++ {
++ static PosixEventNotifierImpl& get(posix::EventNotifier& notifier);
++ static const PosixEventNotifierImpl& get(const posix::EventNotifier& notifier);
++ };
++
+}
-Index: cpp/src/qmf/AgentEventImpl.h
-===================================================================
---- cpp/src/qmf/AgentEventImpl.h (revision 1056407)
-+++ cpp/src/qmf/AgentEventImpl.h (working copy)
-@@ -29,6 +29,7 @@
- #include "qmf/Query.h"
- #include "qmf/DataAddr.h"
- #include "qmf/Data.h"
-+#include "qmf/Schema.h"
- #include <queue>
-
- namespace qmf {
-@@ -45,6 +46,7 @@
- void setArguments(const qpid::types::Variant::Map& a) { arguments = a; }
- void setArgumentSubtypes(const qpid::types::Variant::Map& a) { argumentSubtypes = a; }
- void setReplyTo(const qpid::messaging::Address& r) { replyTo = r; }
-+ void setSchema(const Schema& s) { schema = s; }
- const qpid::messaging::Address& getReplyTo() { return replyTo; }
- void setCorrelationId(const std::string& c) { correlationId = c; }
- const std::string& getCorrelationId() { return correlationId; }
-@@ -73,6 +75,7 @@
- std::string correlationId;
- Query query;
- DataAddr dataAddr;
-+ Schema schema;
- std::string methodName;
- qpid::types::Variant::Map arguments;
- qpid::types::Variant::Map argumentSubtypes;
-Index: cpp/src/qmf/ConsoleEventImpl.h
-===================================================================
---- cpp/src/qmf/ConsoleEventImpl.h (revision 1056407)
-+++ cpp/src/qmf/ConsoleEventImpl.h (working copy)
-@@ -42,6 +42,8 @@
- void addSchemaId(const SchemaId& s) { newSchemaIds.push_back(SchemaId(s)); }
- void setFinal() { final = true; }
- void setArguments(const qpid::types::Variant::Map& a) { arguments = a; }
-+ void setSeverity(int s) { severity = s; }
-+ void setTimestamp(uint64_t t) { timestamp = t; }
-
- //
- // Methods from API handle
-@@ -56,6 +58,8 @@
- Data getData(uint32_t i) const;
- bool isFinal() const { return final; }
- const qpid::types::Variant::Map& getArguments() const { return arguments; }
-+ int getSeverity() const { return severity; }
-+ uint64_t getTimestamp() const { return timestamp; }
-
- private:
- const ConsoleEventCode eventType;
-@@ -66,6 +70,8 @@
- std::list<Data> dataList;
- std::list<SchemaId> newSchemaIds;
- qpid::types::Variant::Map arguments;
-+ int severity;
-+ uint64_t timestamp;
- };
-
- struct ConsoleEventImplAccess
-Index: cpp/src/qmf/ConsoleSessionImpl.h
-===================================================================
---- cpp/src/qmf/ConsoleSessionImpl.h (revision 1056407)
-+++ cpp/src/qmf/ConsoleSessionImpl.h (working copy)
-@@ -61,6 +61,8 @@
- uint32_t getAgentCount() const;
- Agent getAgent(uint32_t i) const;
- Agent getConnectedBrokerAgent() const { return connectedBrokerAgent; }
-+ Subscription subscribe(const Query&, const std::string& agentFilter, const std::string& options);
-+ Subscription subscribe(const std::string&, const std::string& agentFilter, const std::string& options);
-
- protected:
- mutable qpid::sys::Mutex lock;
-@@ -71,6 +73,8 @@
- qpid::messaging::Sender topicSender;
- std::string domain;
- uint32_t maxAgentAgeMinutes;
-+ bool listenOnDirect;
-+ bool strictSecurity;
- Query agentQuery;
- bool opened;
- std::queue<ConsoleEvent> eventQueue;
-Index: cpp/src/qmf.mk
-===================================================================
---- cpp/src/qmf.mk (revision 1056407)
-+++ cpp/src/qmf.mk (working copy)
-@@ -51,7 +51,8 @@
- ../include/qmf/SchemaId.h \
- ../include/qmf/SchemaMethod.h \
- ../include/qmf/SchemaProperty.h \
-- ../include/qmf/SchemaTypes.h
-+ ../include/qmf/SchemaTypes.h \
-+ ../include/qmf/Subscription.h
-
-
- #
-@@ -91,10 +92,14 @@
- qmf/AgentEventImpl.h \
- qmf/AgentImpl.h \
- qmf/AgentSession.cpp \
-+ qmf/AgentSubscription.cpp \
-+ qmf/AgentSubscription.h \
- qmf/ConsoleEvent.cpp \
- qmf/ConsoleEventImpl.h \
- qmf/ConsoleSession.cpp \
- qmf/ConsoleSessionImpl.h \
-+ qmf/constants.cpp \
-+ qmf/constants.h \
- qmf/DataAddr.cpp \
- qmf/DataAddrImpl.h \
- qmf/Data.cpp \
-@@ -116,7 +121,9 @@
- qmf/SchemaMethod.cpp \
- qmf/SchemaMethodImpl.h \
- qmf/SchemaProperty.cpp \
-- qmf/SchemaPropertyImpl.h
-+ qmf/SchemaPropertyImpl.h \
-+ qmf/Subscription.cpp \
-+ qmf/SubscriptionImpl.h
-
- libqmfengine_la_SOURCES = \
- $(QMF_ENGINE_API) \
-Index: cpp/src/qpid/agent/ManagementAgentImpl.h
-===================================================================
---- cpp/src/qpid/agent/ManagementAgentImpl.h (revision 1056407)
-+++ cpp/src/qpid/agent/ManagementAgentImpl.h (working copy)
-@@ -128,12 +128,14 @@
- };
-
- struct QueuedMethod {
-- QueuedMethod(const std::string& _cid, const std::string& _reply, const std::string& _body) :
-- cid(_cid), replyTo(_reply), body(_body) {}
-+ QueuedMethod(const std::string& _cid, const std::string& _rte, const std::string& _rtk, const std::string& _body, const std::string& _uid) :
-+ cid(_cid), replyToExchange(_rte), replyToKey(_rtk), body(_body), userId(_uid) {}
-
- std::string cid;
-- std::string replyTo;
-+ std::string replyToExchange;
-+ std::string replyToKey;
- std::string body;
-+ std::string userId;
- };
-
- typedef std::deque<QueuedMethod*> MethodQueue;
-@@ -277,16 +279,16 @@
- uint8_t type=ManagementItem::CLASS_KIND_TABLE);
- bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
- void sendHeartbeat();
-- void sendException(const std::string& replyToKey, const std::string& cid,
-+ void sendException(const std::string& replyToExchange, const std::string& replyToKey, const std::string& cid,
- const std::string& text, uint32_t code=1);
- void handlePackageRequest (qpid::framing::Buffer& inBuffer);
- void handleClassQuery (qpid::framing::Buffer& inBuffer);
-- void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, const std::string& replyTo);
-- void invokeMethodRequest (const std::string& body, const std::string& cid, const std::string& replyTo);
-+ void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, const std::string& rte, const std::string& rtk);
-+ void invokeMethodRequest (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk, const std::string& userId);
-
-- void handleGetQuery (const std::string& body, const std::string& cid, const std::string& replyTo);
-- void handleLocateRequest (const std::string& body, const std::string& sequence, const std::string& replyTo);
-- void handleMethodRequest (const std::string& body, const std::string& sequence, const std::string& replyTo);
-+ void handleGetQuery (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk);
-+ void handleLocateRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk);
-+ void handleMethodRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk, const std::string& userId);
- void handleConsoleAddedIndication();
- void getHeartbeatContent (qpid::types::Variant::Map& map);
- };
-Index: cpp/src/qpid/agent/ManagementAgentImpl.cpp
-===================================================================
---- cpp/src/qpid/agent/ManagementAgentImpl.cpp (revision 1056407)
-+++ cpp/src/qpid/agent/ManagementAgentImpl.cpp (working copy)
-@@ -339,8 +339,10 @@
- headers["qmf.content"] = "_event";
- headers["qmf.agent"] = name_address;
-
-- MapCodec::encode(map_, content);
-- connThreadBody.sendBuffer(content, "", headers, topicExchange, key.str());
-+ Variant::List list;
-+ list.push_back(map_);
-+ ListCodec::encode(list, content);
-+ connThreadBody.sendBuffer(content, "", headers, topicExchange, key.str(), "amqp/list");
- }
-
- uint32_t ManagementAgentImpl::pollCallbacks(uint32_t callLimit)
-@@ -360,7 +362,7 @@
- methodQueue.pop_front();
- {
- sys::Mutex::ScopedUnlock unlock(agentLock);
-- invokeMethodRequest(item->body, item->cid, item->replyTo);
-+ invokeMethodRequest(item->body, item->cid, item->replyToExchange, item->replyToKey, item->userId);
- delete item;
- }
- }
-@@ -495,7 +497,7 @@
- QPID_LOG(trace, "SENT AgentHeartbeat name=" << name_address);
- }
-
--void ManagementAgentImpl::sendException(const string& replyToKey, const string& cid,
-+void ManagementAgentImpl::sendException(const string& rte, const string& rtk, const string& cid,
- const string& text, uint32_t code)
- {
- Variant::Map map;
-@@ -512,12 +514,12 @@
- map["_values"] = values;
-
- MapCodec::encode(map, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyToKey);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
++
++#endif
++
+diff --git a/qpid/cpp/src/tests/Qmf2.cpp b/qpid/cpp/src/tests/Qmf2.cpp
+index 66c774a..bc263d5 100644
+--- a/qpid/cpp/src/tests/Qmf2.cpp
++++ b/qpid/cpp/src/tests/Qmf2.cpp
+@@ -23,12 +23,36 @@
+ #include "qmf/QueryImpl.h"
+ #include "qmf/SchemaImpl.h"
+ #include "qmf/exceptions.h"
+-
++#include "qpid/messaging/Connection.h"
++#include "qmf/PosixEventNotifierImpl.h"
++#include "qmf/AgentSession.h"
++#include "qmf/AgentSessionImpl.h"
++#include "qmf/ConsoleSession.h"
++#include "qmf/ConsoleSessionImpl.h"
+ #include "unit_test.h"
- QPID_LOG(trace, "SENT Exception code=" << code <<" text=" << text);
- }
++using namespace std;
+ using namespace qpid::types;
++using namespace qpid::messaging;
+ using namespace qmf;
--void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& replyTo)
-+void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& rte, const string& rtk)
- {
- sys::Mutex::ScopedLock lock(agentLock);
- string packageName;
-@@ -544,7 +546,7 @@
- outBuffer.putRawData(body);
- outLen = MA_BUFFER_SIZE - outBuffer.available();
- outBuffer.reset();
-- connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
-+ connThreadBody.sendBuffer(outBuffer, outLen, rte, rtk);
++bool isReadable(int fd)
++{
++ fd_set rfds;
++ struct timeval tv;
++ int nfds, result;
++
++ FD_ZERO(&rfds);
++ FD_SET(fd, &rfds);
++ nfds = fd + 1;
++ tv.tv_sec = 0;
++ tv.tv_usec = 0;
++
++ result = select(nfds, &rfds, NULL, NULL, &tv);
++
++ return result > 0;
++}
++
+ namespace qpid {
+ namespace tests {
- QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name);
- }
-@@ -559,7 +561,7 @@
- QPID_LOG(trace, "RCVD ConsoleAddedInd");
+@@ -315,6 +339,84 @@ QPID_AUTO_TEST_CASE(testSchema)
+ BOOST_CHECK_THROW(method.getArgument(3), QmfException);
}
--void ManagementAgentImpl::invokeMethodRequest(const string& body, const string& cid, const string& replyTo)
-+void ManagementAgentImpl::invokeMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId)
- {
- string methodName;
- bool failed = false;
-@@ -570,11 +572,9 @@
-
- MapCodec::decode(body, inMap);
-
-- outMap["_values"] = Variant::Map();
--
- if ((oid = inMap.find("_object_id")) == inMap.end() ||
- (mid = inMap.find("_method_name")) == inMap.end()) {
-- sendException(replyTo, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
-+ sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
- Manageable::STATUS_PARAMETER_INVALID);
- failed = true;
- } else {
-@@ -593,6 +593,8 @@
- inArgs = (mid->second).asMap();
- }
-
-+ QPID_LOG(trace, "Invoking Method: name=" << methodName << " args=" << inArgs);
++QPID_AUTO_TEST_CASE(testAgentSessionEventListener)
++{
++ Connection connection("localhost");
++ AgentSession session(connection, "");
++ posix::EventNotifier notifier(session);
+
- boost::shared_ptr<ManagementObject> oPtr;
- {
- sys::Mutex::ScopedLock lock(agentLock);
-@@ -602,11 +604,11 @@
- }
++ AgentSessionImpl& sessionImpl = AgentSessionImplAccess::get(session);
++
++ BOOST_CHECK(sessionImpl.getEventNotifier() != 0);
++}
++
++QPID_AUTO_TEST_CASE(testConsoleSessionEventListener)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ posix::EventNotifier notifier(session);
++
++ ConsoleSessionImpl& sessionImpl = ConsoleSessionImplAccess::get(session);
++
++ BOOST_CHECK(sessionImpl.getEventNotifier() != 0);
++}
++
++QPID_AUTO_TEST_CASE(testGetHandle)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ posix::EventNotifier notifier(session);
++
++ BOOST_CHECK(notifier.getHandle() > 0);
++}
++
++QPID_AUTO_TEST_CASE(testSetReadableToFalse)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ posix::EventNotifier notifier(session);
++ PosixEventNotifierImplAccess::get(notifier).setReadable(false);
++
++ bool readable(isReadable(notifier.getHandle()));
++ BOOST_CHECK(!readable);
++}
++
++QPID_AUTO_TEST_CASE(testSetReadable)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ posix::EventNotifier notifier(session);
++ PosixEventNotifierImplAccess::get(notifier).setReadable(true);
++
++ bool readable(isReadable(notifier.getHandle()));
++ BOOST_CHECK(readable);
++}
++
++QPID_AUTO_TEST_CASE(testSetReadableMultiple)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ posix::EventNotifier notifier(session);
++ for (int i = 0; i < 15; i++)
++ PosixEventNotifierImplAccess::get(notifier).setReadable(true);
++ PosixEventNotifierImplAccess::get(notifier).setReadable(false);
++
++ bool readable(isReadable(notifier.getHandle()));
++ BOOST_CHECK(!readable);
++}
++
++QPID_AUTO_TEST_CASE(testDeleteNotifier)
++{
++ Connection connection("localhost");
++ ConsoleSession session(connection, "");
++ ConsoleSessionImpl& sessionImpl = ConsoleSessionImplAccess::get(session);
++ {
++ posix::EventNotifier notifier(session);
++ BOOST_CHECK(sessionImpl.getEventNotifier() != 0);
++ }
++ BOOST_CHECK(sessionImpl.getEventNotifier() == 0);
++}
++
+ QPID_AUTO_TEST_SUITE_END()
- if (oPtr.get() == 0) {
-- sendException(replyTo, cid, Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT),
-+ sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT),
- Manageable::STATUS_UNKNOWN_OBJECT);
- failed = true;
- } else {
-- oPtr->doMethod(methodName, inArgs, callMap);
-+ oPtr->doMethod(methodName, inArgs, callMap, userId);
+ }} // namespace qpid::tests
+--
+1.7.4.4
+
+From 0918bc94f925d413d8021a855cf566f6a55c654c Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Wed, 14 Sep 2011 21:41:11 +0000
+Subject: [PATCH 09/14] QPID-3484 - Fixed handling of unused return values to
+ prevent compiler warnings.
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1170860 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp | 8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp b/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
+index abc9cad..011dbcc 100644
+--- a/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
++++ b/qpid/cpp/src/qmf/PosixEventNotifierImpl.cpp
+@@ -18,9 +18,11 @@
+ */
- if (callMap["_status_code"].asUint32() == 0) {
- outMap["_arguments"] = Variant::Map();
-@@ -615,13 +617,13 @@
- if (iter->first != "_status_code" && iter->first != "_status_text")
- outMap["_arguments"].asMap()[iter->first] = iter->second;
- } else {
-- sendException(replyTo, cid, callMap["_status_text"], callMap["_status_code"]);
-+ sendException(rte, rtk, cid, callMap["_status_text"], callMap["_status_code"]);
- failed = true;
- }
- }
+ #include "PosixEventNotifierImpl.h"
++#include "qpid/log/Statement.h"
- } catch(types::InvalidConversion& e) {
-- sendException(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION);
-+ sendException(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION);
- failed = true;
- }
- }
-@@ -633,11 +635,11 @@
- headers["qmf.opcode"] = "_method_response";
- QPID_LOG(trace, "SENT MethodResponse map=" << outMap);
- MapCodec::encode(outMap, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
- }
- }
+ #include <fcntl.h>
+ #include <unistd.h>
++#include <errno.h>
--void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid, const string& replyTo)
-+void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid, const string& rte, const string& rtk)
- {
- moveNewObjectsLH();
+ #define BUFFER_SIZE 10
-@@ -664,12 +666,12 @@
- */
- i = inMap.find("_what");
- if (i == inMap.end()) {
-- sendException(replyTo, cid, "_what element missing in Query");
-+ sendException(rte, rtk, cid, "_what element missing in Query");
- return;
- }
+@@ -51,10 +53,12 @@ void PosixEventNotifierImpl::update(bool readable)
+ char buffer[BUFFER_SIZE];
- if (i->second.getType() != qpid::types::VAR_STRING) {
-- sendException(replyTo, cid, "_what element is not a string");
-+ sendException(rte, rtk, cid, "_what element is not a string");
- return;
+ if(readable && !this->isReadable()) {
+- (void) ::write(myHandle, "1", 1);
++ if (::write(myHandle, "1", 1) == -1)
++ QPID_LOG(error, "PosixEventNotifierImpl::update write failed: " << errno);
}
-
-@@ -707,8 +709,8 @@
- headers.erase("partial");
-
- ListCodec::encode(list_, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
-- QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
-+ QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << rte << "/" << rtk);
- return;
- }
- } else { // match using schema_id, if supplied
-@@ -769,8 +771,8 @@
- if (++objCount >= maxV2ReplyObjs) {
- objCount = 0;
- ListCodec::encode(list_, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
-- QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
-+ QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << rte << "/" << rtk);
- content.clear();
- list_.clear();
- }
-@@ -782,8 +784,8 @@
- // Send last "non-partial" message to indicate CommandComplete
- headers.erase("partial");
- ListCodec::encode(list_, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
-- QPID_LOG(trace, "SENT QueryResponse (empty with no 'partial' indicator) to=" << replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
-+ QPID_LOG(trace, "SENT QueryResponse (last message, no 'partial' indicator) to=" << rte << "/" << rtk);
-
- } else if (i->second.asString() == "SCHEMA_ID") {
- headers["qmf.content"] = "_schema_id";
-@@ -804,16 +806,16 @@
-
- headers.erase("partial");
- ListCodec::encode(list_, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo, "amqp/list");
-- QPID_LOG(trace, "SENT QueryResponse (SchemaId) to=" << replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list");
-+ QPID_LOG(trace, "SENT QueryResponse (SchemaId) to=" << rte << "/" << rtk);
-
- } else {
- // Unknown query target
-- sendException(replyTo, cid, "Query for _what => '" + i->second.asString() + "' not supported");
-+ sendException(rte, rtk, cid, "Query for _what => '" + i->second.asString() + "' not supported");
+ else if(!readable && this->isReadable()) {
+- (void) ::read(yourHandle, buffer, BUFFER_SIZE);
++ if (::read(yourHandle, buffer, BUFFER_SIZE) == -1)
++ QPID_LOG(error, "PosixEventNotifierImpl::update read failed: " << errno);
}
}
--void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid, const string& replyTo)
-+void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid, const string& rte, const string& rtk)
- {
- QPID_LOG(trace, "RCVD AgentLocateRequest");
-
-@@ -827,9 +829,9 @@
-
- getHeartbeatContent(map);
- MapCodec::encode(map, content);
-- connThreadBody.sendBuffer(content, cid, headers, directExchange, replyTo);
-+ connThreadBody.sendBuffer(content, cid, headers, rte, rtk);
-
-- QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << replyTo);
-+ QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << rte << "/" << rtk);
+--
+1.7.4.4
+
+From c1fe836092355bf45c7118517e49d9307a12c7c8 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at apache.org>
+Date: Fri, 16 Sep 2011 14:34:39 +0000
+Subject: [PATCH 10/14] QPID-3484 - Added missing constructor for
+ EventNotifier, fixed initialization bug.
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1171592 13f79535-47bb-0310-9956-ffa450edef68
+---
+ qpid/cpp/include/qmf/posix/EventNotifier.h | 1 +
+ qpid/cpp/src/qmf/AgentSession.cpp | 16 ++++++++++++++--
+ qpid/cpp/src/qmf/AgentSessionImpl.h | 1 +
+ qpid/cpp/src/qmf/ConsoleSession.cpp | 20 ++++++++++++++++----
+ qpid/cpp/src/qmf/ConsoleSessionImpl.h | 1 +
+ qpid/cpp/src/qmf/PosixEventNotifier.cpp | 2 ++
+ 6 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/qpid/cpp/include/qmf/posix/EventNotifier.h b/qpid/cpp/include/qmf/posix/EventNotifier.h
+index 91817cc..ebc1cb5 100644
+--- a/qpid/cpp/include/qmf/posix/EventNotifier.h
++++ b/qpid/cpp/include/qmf/posix/EventNotifier.h
+@@ -38,6 +38,7 @@ namespace posix {
+
+ class QMF_CLASS_EXTERN EventNotifier : public qmf::Handle<qmf::PosixEventNotifierImpl> {
+ public:
++ QMF_EXTERN EventNotifier(PosixEventNotifierImpl* impl = 0);
+ QMF_EXTERN EventNotifier(::qmf::AgentSession& agentSession);
+ QMF_EXTERN EventNotifier(::qmf::ConsoleSession& consoleSession);
+ QMF_EXTERN EventNotifier(const EventNotifier& that);
+diff --git a/qpid/cpp/src/qmf/AgentSession.cpp b/qpid/cpp/src/qmf/AgentSession.cpp
+index d92b2a4..251c25f 100644
+--- a/qpid/cpp/src/qmf/AgentSession.cpp
++++ b/qpid/cpp/src/qmf/AgentSession.cpp
+@@ -55,7 +55,7 @@ void AgentSession::raiseEvent(const Data& d, int s) { impl->raiseEvent(d, s); }
+ //========================================================================================
- {
- sys::Mutex::ScopedLock lock(agentLock);
-@@ -837,12 +839,12 @@
- }
+ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) :
+- connection(c), domain("default"), opened(false), thread(0), threadCanceled(false),
++ connection(c), domain("default"), opened(false), eventNotifier(0), thread(0), threadCanceled(false),
+ bootSequence(1), interval(60), lastHeartbeat(0), lastVisit(0), forceHeartbeat(false),
+ externalStorage(false), autoAllowQueries(true), autoAllowMethods(true),
+ maxSubscriptions(64), minSubInterval(3000), subLifetime(300), publicEvents(true),
+@@ -191,7 +191,7 @@ void AgentSessionImpl::open()
}
--void ManagementAgentImpl::handleMethodRequest(const string& body, const string& cid, const string& replyTo)
-+void ManagementAgentImpl::handleMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId)
- {
- if (extThread) {
- sys::Mutex::ScopedLock lock(agentLock);
-
-- methodQueue.push_back(new QueuedMethod(cid, replyTo, body));
-+ methodQueue.push_back(new QueuedMethod(cid, rte, rtk, body, userId));
- if (pipeHandle != 0) {
- pipeHandle->write("X", 1);
- } else if (notifyable != 0) {
-@@ -861,7 +863,7 @@
- inCallback = false;
- }
- } else {
-- invokeMethodRequest(body, cid, replyTo);
-+ invokeMethodRequest(body, cid, rte, rtk, userId);
- }
-
- QPID_LOG(trace, "RCVD MethodRequest");
-@@ -869,21 +871,27 @@
- void ManagementAgentImpl::received(Message& msg)
+-void AgentSessionImpl::close()
++void AgentSessionImpl::closeAsync()
{
-+ string replyToExchange;
- string replyToKey;
- framing::MessageProperties mp = msg.getMessageProperties();
- if (mp.hasReplyTo()) {
- const framing::ReplyTo& rt = mp.getReplyTo();
-+ replyToExchange = rt.getExchange();
- replyToKey = rt.getRoutingKey();
- }
+ if (!opened)
+ return;
+@@ -202,6 +202,18 @@ void AgentSessionImpl::close()
+ }
-+ string userId;
-+ if (mp.hasUserId())
-+ userId = mp.getUserId();
-+
- if (mp.hasAppId() && mp.getAppId() == "qmf2")
- {
- string opcode = mp.getApplicationHeaders().getAsString("qmf.opcode");
- string cid = msg.getMessageProperties().getCorrelationId();
-- if (opcode == "_agent_locate_request") handleLocateRequest(msg.getData(), cid, replyToKey);
-- else if (opcode == "_method_request") handleMethodRequest(msg.getData(), cid, replyToKey);
-- else if (opcode == "_query_request") handleGetQuery(msg.getData(), cid, replyToKey);
-+ if (opcode == "_agent_locate_request") handleLocateRequest(msg.getData(), cid, replyToExchange, replyToKey);
-+ else if (opcode == "_method_request") handleMethodRequest(msg.getData(), cid, replyToExchange, replyToKey, userId);
-+ else if (opcode == "_query_request") handleGetQuery(msg.getData(), cid, replyToExchange, replyToKey);
- else {
- QPID_LOG(warning, "Support for QMF V2 Opcode [" << opcode << "] TBD!!!");
- }
-@@ -900,7 +908,7 @@
++void AgentSessionImpl::close()
++{
++ closeAsync();
++
++ if (thread) {
++ thread->join();
++ delete thread;
++ thread = 0;
++ }
++}
++
++
+ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout)
+ {
+ uint64_t milliseconds = timeout.getMilliseconds();
+diff --git a/qpid/cpp/src/qmf/AgentSessionImpl.h b/qpid/cpp/src/qmf/AgentSessionImpl.h
+index cf1b1d7..9039a59 100644
+--- a/qpid/cpp/src/qmf/AgentSessionImpl.h
++++ b/qpid/cpp/src/qmf/AgentSessionImpl.h
+@@ -84,6 +84,7 @@ namespace qmf {
+ void setAttribute(const string& k, const qpid::types::Variant& v) { checkOpen(); attributes[k] = v; }
+ const string& getName() const { return agentName; }
+ void open();
++ void closeAsync();
+ void close();
+ bool nextEvent(AgentEvent& e, Duration t);
+ int pendingEvents() const;
+diff --git a/qpid/cpp/src/qmf/ConsoleSession.cpp b/qpid/cpp/src/qmf/ConsoleSession.cpp
+index d084b8a..2dfc894 100644
+--- a/qpid/cpp/src/qmf/ConsoleSession.cpp
++++ b/qpid/cpp/src/qmf/ConsoleSession.cpp
+@@ -67,7 +67,7 @@ Subscription ConsoleSession::subscribe(const string& q, const string& f, const s
- if (checkHeader(inBuffer, &opcode, &sequence))
- {
-- if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToKey);
-+ if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
- else if (opcode == 'x') handleConsoleAddedIndication();
- else
- QPID_LOG(warning, "Ignoring old-format QMF Request! opcode=" << char(opcode));
-@@ -1161,10 +1169,10 @@
- void ManagementAgentImpl::getHeartbeatContent(qpid::types::Variant::Map& map)
+ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) :
+ connection(c), domain("default"), maxAgentAgeMinutes(5), listenOnDirect(true), strictSecurity(false), maxThreadWaitTime(5),
+- opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
++ opened(false), eventNotifier(0), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0),
+ connectedBrokerInAgentList(false), schemaCache(new SchemaCache()), nextCorrelator(1)
{
- map["_values"] = attrMap;
-- map["_values"].asMap()["timestamp"] = uint64_t(Duration(EPOCH, now()));
-- map["_values"].asMap()["heartbeat_interval"] = interval;
-- map["_values"].asMap()["epoch"] = bootSequence;
-- map["_values"].asMap()["schema_timestamp"] = uint64_t(schemaTimestamp);
-+ map["_values"].asMap()["_timestamp"] = uint64_t(Duration(EPOCH, now()));
-+ map["_values"].asMap()["_heartbeat_interval"] = interval;
-+ map["_values"].asMap()["_epoch"] = bootSequence;
-+ map["_values"].asMap()["_schema_updated"] = uint64_t(schemaTimestamp);
+ if (!options.empty()) {
+@@ -210,7 +210,7 @@ void ConsoleSessionImpl::open()
}
- void ManagementAgentImpl::ConnectionThread::run()
-Index: cpp/src/qpid/management/ManagementAgent.h
-===================================================================
---- cpp/src/qpid/management/ManagementAgent.h (revision 1056407)
-+++ cpp/src/qpid/management/ManagementAgent.h (working copy)
-@@ -306,7 +306,11 @@
- void sendBufferLH(framing::Buffer& buf,
- uint32_t length,
- qpid::broker::Exchange::shared_ptr exchange,
-- std::string routingKey);
-+ const std::string& routingKey);
-+ void sendBufferLH(framing::Buffer& buf,
-+ uint32_t length,
-+ const std::string& exchange,
-+ const std::string& routingKey);
- void sendBufferLH(const std::string& data,
- const std::string& cid,
- const qpid::types::Variant::Map& headers,
-@@ -314,6 +318,13 @@
- qpid::broker::Exchange::shared_ptr exchange,
- const std::string& routingKey,
- uint64_t ttl_msec = 0);
-+ void sendBufferLH(const std::string& data,
-+ const std::string& cid,
-+ const qpid::types::Variant::Map& headers,
-+ const std::string& content_type,
-+ const std::string& exchange,
-+ const std::string& routingKey,
-+ uint64_t ttl_msec = 0);
- void moveNewObjectsLH();
-
- bool authorizeAgentMessageLH(qpid::broker::Message& msg);
-@@ -337,20 +348,20 @@
- void deleteOrphanedAgentsLH();
- void sendCommandCompleteLH(const std::string& replyToKey, uint32_t sequence,
- uint32_t code = 0, const std::string& text = "OK");
-- void sendExceptionLH(const std::string& replyToKey, const std::string& cid, const std::string& text, uint32_t code=1, bool viaLocal=false);
-+ void sendExceptionLH(const std::string& rte, const std::string& rtk, const std::string& cid, const std::string& text, uint32_t code=1, bool viaLocal=false);
- void handleBrokerRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handlePackageQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handlePackageIndLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handleClassQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handleClassIndLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
-- void handleSchemaRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
-+ void handleSchemaRequestLH (framing::Buffer& inBuffer, const std::string& replyToEx ,const std::string& replyToKey, uint32_t sequence);
- void handleSchemaResponseLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handleAttachRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
- void handleGetQueryLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence);
- void handleMethodRequestLH (framing::Buffer& inBuffer, const std::string& replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
-- void handleGetQueryLH (const std::string& body, const std::string& replyToKey, const std::string& cid, bool viaLocal);
-- void handleMethodRequestLH (const std::string& body, const std::string& replyToKey, const std::string& cid, const qpid::broker::ConnectionToken* connToken, bool viaLocal);
-- void handleLocateRequestLH (const std::string& body, const std::string &replyToKey, const std::string& cid);
-+ void handleGetQueryLH (const std::string& body, const std::string& replyToEx, const std::string& replyToKey, const std::string& cid, bool viaLocal);
-+ void handleMethodRequestLH (const std::string& body, const std::string& replyToEx, const std::string& replyToKey, const std::string& cid, const qpid::broker::ConnectionToken* connToken, bool viaLocal);
-+ void handleLocateRequestLH (const std::string& body, const std::string& replyToEx, const std::string& replyToKey, const std::string& cid);
-
-
- size_t validateSchema(framing::Buffer&, uint8_t kind);
-Index: cpp/src/qpid/management/ManagementAgent.cpp
-===================================================================
---- cpp/src/qpid/management/ManagementAgent.cpp (revision 1056407)
-+++ cpp/src/qpid/management/ManagementAgent.cpp (working copy)
-@@ -404,8 +404,10 @@
-
- string content;
-- MapCodec::encode(map_, content);
-- sendBufferLH(content, "", headers, "amqp/map", v2Topic, key.str());
-+ Variant::List list_;
-+ list_.push_back(map_);
-+ ListCodec::encode(list_, content);
-+ sendBufferLH(content, "", headers, "amqp/list", v2Topic, key.str());
- QPID_LOG(trace, "SEND raiseEvent (v2) class=" << event.getPackageName() << "." << event.getEventName());
- }
-
-@@ -504,7 +506,7 @@
- void ManagementAgent::sendBufferLH(Buffer& buf,
- uint32_t length,
- qpid::broker::Exchange::shared_ptr exchange,
-- string routingKey)
-+ const string& routingKey)
+-void ConsoleSessionImpl::close()
++void ConsoleSessionImpl::closeAsync()
{
- if (suppressed) {
- QPID_LOG(trace, "Suppressed management message to " << routingKey);
-@@ -549,6 +551,17 @@
+ if (!opened)
+ throw QmfException("The session is already closed");
+@@ -221,6 +221,18 @@ void ConsoleSessionImpl::close()
}
-+void ManagementAgent::sendBufferLH(Buffer& buf,
-+ uint32_t length,
-+ const string& exchange,
-+ const string& routingKey)
++void ConsoleSessionImpl::close()
+{
-+ qpid::broker::Exchange::shared_ptr ex(broker->getExchanges().get(exchange));
-+ if (ex.get() != 0)
-+ sendBufferLH(buf, length, ex, routingKey);
-+}
++ closeAsync();
+
-+
- // NOTE WELL: assumes userLock is held by caller (LH)
- // NOTE EVEN WELLER: drops this lock when delivering the message!!!
- void ManagementAgent::sendBufferLH(const string& data,
-@@ -612,6 +625,20 @@
- }
-
-
-+void ManagementAgent::sendBufferLH(const string& data,
-+ const string& cid,
-+ const Variant::Map& headers,
-+ const string& content_type,
-+ const string& exchange,
-+ const string& routingKey,
-+ uint64_t ttl_msec)
-+{
-+ qpid::broker::Exchange::shared_ptr ex(broker->getExchanges().get(exchange));
-+ if (ex.get() != 0)
-+ sendBufferLH(data, cid, headers, content_type, ex, routingKey, ttl_msec);
++ if (thread) {
++ thread->join();
++ delete thread;
++ thread = 0;
++ }
+}
+
+
- void ManagementAgent::moveNewObjectsLH()
+ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout)
{
- sys::Mutex::ScopedLock lock (addLock);
-@@ -840,9 +867,9 @@
- headers["qmf.agent"] = name_address;
-
- map["_values"] = attrMap;
-- map["_values"].asMap()["timestamp"] = uint64_t(sys::Duration(sys::EPOCH, sys::now()));
-- map["_values"].asMap()["heartbeat_interval"] = interval;
-- map["_values"].asMap()["epoch"] = bootSequence;
-+ map["_values"].asMap()["_timestamp"] = uint64_t(sys::Duration(sys::EPOCH, sys::now()));
-+ map["_values"].asMap()["_heartbeat_interval"] = interval;
-+ map["_values"].asMap()["_epoch"] = bootSequence;
-
- string content;
- MapCodec::encode(map, content);
-@@ -944,7 +971,7 @@
- replyToKey << " seq=" << sequence);
- }
-
--void ManagementAgent::sendExceptionLH(const string& replyToKey, const string& cid,
-+void ManagementAgent::sendExceptionLH(const string& rte, const string& rtk, const string& cid,
- const string& text, uint32_t code, bool viaLocal)
+ uint64_t milliseconds = timeout.getMilliseconds();
+@@ -256,14 +268,14 @@ int ConsoleSessionImpl::pendingEvents() const
+ void ConsoleSessionImpl::setEventNotifier(EventNotifierImpl* notifier)
{
- static const string addr_exchange("qmf.default.direct");
-@@ -963,7 +990,7 @@
- map["_values"] = values;
-
- MapCodec::encode(map, content);
-- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyToKey);
-+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
-
- QPID_LOG(trace, "SENT Exception code=" << code <<" text=" << text);
- }
-@@ -1083,8 +1110,8 @@
- return;
- }
-
-+ string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
- if (acl != 0) {
-- string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
- map<acl::Property, string> params;
- params[acl::PROP_SCHEMAPACKAGE] = packageName;
- params[acl::PROP_SCHEMACLASS] = className;
-@@ -1115,7 +1142,7 @@
- outBuffer.record();
- sys::Mutex::ScopedUnlock u(userLock);
- string outBuf;
-- iter->second->doMethod(methodName, inArgs, outBuf);
-+ iter->second->doMethod(methodName, inArgs, outBuf, userId);
- outBuffer.putRawData(outBuf);
- } catch(exception& e) {
- outBuffer.restore();
-@@ -1131,7 +1158,7 @@
+ qpid::sys::Mutex::ScopedLock l(lock);
+- this->eventNotifier = notifier;
++ eventNotifier = notifier;
}
--void ManagementAgent::handleMethodRequestLH (const string& body, const string& replyTo,
-+void ManagementAgent::handleMethodRequestLH (const string& body, const string& rte, const string& rtk,
- const string& cid, const ConnectionToken* connToken, bool viaLocal)
+ EventNotifierImpl* ConsoleSessionImpl::getEventNotifier() const
{
- string methodName;
-@@ -1151,7 +1178,7 @@
-
- if ((oid = inMap.find("_object_id")) == inMap.end() ||
- (mid = inMap.find("_method_name")) == inMap.end()) {
-- sendExceptionLH(replyTo, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
-+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID),
- Manageable::STATUS_PARAMETER_INVALID, viaLocal);
- return;
- }
-@@ -1170,7 +1197,7 @@
- inArgs = (mid->second).asMap();
- }
- } catch(exception& e) {
-- sendExceptionLH(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
-+ sendExceptionLH(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
- return;
- }
-
-@@ -1179,7 +1206,7 @@
- if (iter == managementObjects.end() || iter->second->isDeleted()) {
- stringstream estr;
- estr << "No object found with ID=" << objId;
-- sendExceptionLH(replyTo, cid, estr.str(), 1, viaLocal);
-+ sendExceptionLH(rte, rtk, cid, estr.str(), 1, viaLocal);
- return;
- }
-
-@@ -1189,18 +1216,18 @@
-
- i = disallowed.find(make_pair(iter->second->getClassName(), methodName));
- if (i != disallowed.end()) {
-- sendExceptionLH(replyTo, cid, i->second, Manageable::STATUS_FORBIDDEN, viaLocal);
-+ sendExceptionLH(rte, rtk, cid, i->second, Manageable::STATUS_FORBIDDEN, viaLocal);
- return;
- }
-
-+ string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
- if (acl != 0) {
-- string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
- map<acl::Property, string> params;
- params[acl::PROP_SCHEMAPACKAGE] = iter->second->getPackageName();
- params[acl::PROP_SCHEMACLASS] = iter->second->getClassName();
-
- if (!acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, ¶ms)) {
-- sendExceptionLH(replyTo, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
-+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
- Manageable::STATUS_FORBIDDEN, viaLocal);
- return;
- }
-@@ -1210,11 +1237,11 @@
-
- QPID_LOG(trace, "RECV MethodRequest (v2) class=" << iter->second->getPackageName()
- << ":" << iter->second->getClassName() << " method=" <<
-- methodName << " replyTo=" << replyTo << " objId=" << objId << " inArgs=" << inArgs);
-+ methodName << " replyTo=" << rte << "/" << rtk << " objId=" << objId << " inArgs=" << inArgs);
-
- try {
- sys::Mutex::ScopedUnlock u(userLock);
-- iter->second->doMethod(methodName, inArgs, callMap);
-+ iter->second->doMethod(methodName, inArgs, callMap, userId);
- errorCode = callMap["_status_code"].asUint32();
- if (errorCode == 0) {
- outMap["_arguments"] = Variant::Map();
-@@ -1225,18 +1252,18 @@
- } else
- error = callMap["_status_text"].asString();
- } catch(exception& e) {
-- sendExceptionLH(replyTo, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
-+ sendExceptionLH(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION, viaLocal);
- return;
- }
-
- if (errorCode != 0) {
-- sendExceptionLH(replyTo, cid, error, errorCode, viaLocal);
-+ sendExceptionLH(rte, rtk, cid, error, errorCode, viaLocal);
- return;
- }
-
- MapCodec::encode(outMap, content);
-- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyTo);
-- QPID_LOG(trace, "SEND MethodResponse (v2) to=" << replyTo << " seq=" << cid << " map=" << outMap);
-+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
-+ QPID_LOG(trace, "SEND MethodResponse (v2) to=" << rte << "/" << rtk << " seq=" << cid << " map=" << outMap);
+ qpid::sys::Mutex::ScopedLock l(lock);
+- return this->eventNotifier;
++ return eventNotifier;
}
-@@ -1383,7 +1410,7 @@
- buf.putRawData(reinterpret_cast<uint8_t*>(&data[0]), data.size());
- }
-
--void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& replyToKey, uint32_t sequence)
-+void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, const string& rte, const string& rtk, uint32_t sequence)
+diff --git a/qpid/cpp/src/qmf/ConsoleSessionImpl.h b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+index 660fc9b..2f1f631 100644
+--- a/qpid/cpp/src/qmf/ConsoleSessionImpl.h
++++ b/qpid/cpp/src/qmf/ConsoleSessionImpl.h
+@@ -62,6 +62,7 @@ namespace qmf {
+ void setDomain(const std::string& d) { domain = d; }
+ void setAgentFilter(const std::string& f);
+ void open();
++ void closeAsync();
+ void close();
+ bool nextEvent(ConsoleEvent& e, qpid::messaging::Duration t);
+ int pendingEvents() const;
+diff --git a/qpid/cpp/src/qmf/PosixEventNotifier.cpp b/qpid/cpp/src/qmf/PosixEventNotifier.cpp
+index b5c7121..a364cc1 100644
+--- a/qpid/cpp/src/qmf/PosixEventNotifier.cpp
++++ b/qpid/cpp/src/qmf/PosixEventNotifier.cpp
+@@ -26,6 +26,8 @@ using namespace std;
+
+ typedef qmf::PrivateImplRef<posix::EventNotifier> PI;
+
++posix::EventNotifier::EventNotifier(PosixEventNotifierImpl* impl) { PI::ctor(*this, impl); }
++
+ posix::EventNotifier::EventNotifier(AgentSession& agentSession)
{
- string packageName;
- SchemaClassKey key;
-@@ -1392,7 +1419,7 @@
- key.decode(inBuffer);
-
- QPID_LOG(trace, "RECV SchemaRequest class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) <<
-- "), replyTo=" << replyToKey << " seq=" << sequence);
-+ "), replyTo=" << rte << "/" << rtk << " seq=" << sequence);
-
- PackageMap::iterator pIter = packages.find(packageName);
- if (pIter != packages.end()) {
-@@ -1408,17 +1435,17 @@
- classInfo.appendSchema(outBuffer);
- outLen = MA_BUFFER_SIZE - outBuffer.available();
- outBuffer.reset();
-- sendBufferLH(outBuffer, outLen, dExchange, replyToKey);
-- QPID_LOG(trace, "SEND SchemaResponse to=" << replyToKey << " seq=" << sequence);
-+ sendBufferLH(outBuffer, outLen, rte, rtk);
-+ QPID_LOG(trace, "SEND SchemaResponse to=" << rte << "/" << rtk << " seq=" << sequence);
- }
- else
-- sendCommandCompleteLH(replyToKey, sequence, 1, "Schema not available");
-+ sendCommandCompleteLH(rtk, sequence, 1, "Schema not available");
- }
- else
-- sendCommandCompleteLH(replyToKey, sequence, 1, "Class key not found");
-+ sendCommandCompleteLH(rtk, sequence, 1, "Class key not found");
- }
- else
-- sendCommandCompleteLH(replyToKey, sequence, 1, "Package not found");
-+ sendCommandCompleteLH(rtk, sequence, 1, "Package not found");
- }
-
- void ManagementAgent::handleSchemaResponseLH(Buffer& inBuffer, const string& /*replyToKey*/, uint32_t sequence)
-@@ -1678,7 +1705,7 @@
- }
-
-
--void ManagementAgent::handleGetQueryLH(const string& body, const string& replyTo, const string& cid, bool viaLocal)
-+void ManagementAgent::handleGetQueryLH(const string& body, const string& rte, const string& rtk, const string& cid, bool viaLocal)
+ PI::ctor(*this, new PosixEventNotifierImpl(agentSession));
+--
+1.7.4.4
+
+From e5dda70d9a87b570a7386071762860d9a5eae107 Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at redhat.com>
+Date: Wed, 14 Sep 2011 14:59:18 -0400
+Subject: [PATCH 11/14] unused-result.patch
+
+---
+ qpid/cpp/src/qmf/engine/ResilientConnection.cpp | 4 ++--
+ qpid/cpp/src/qpid/broker/Daemon.cpp | 10 +++++-----
+ qpid/cpp/src/qpid/sys/posix/LockFile.cpp | 2 +-
+ qpid/cpp/src/tests/BrokerMgmtAgent.cpp | 2 +-
+ qpid/cpp/src/tests/ForkedBroker.cpp | 2 +-
+ 5 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/qpid/cpp/src/qmf/engine/ResilientConnection.cpp b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp
+index 41dd9ff..851193c 100644
+--- a/qpid/cpp/src/qmf/engine/ResilientConnection.cpp
++++ b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp
+@@ -334,7 +334,7 @@ void ResilientConnectionImpl::notify()
{
- moveNewObjectsLH();
-
-@@ -1699,17 +1726,17 @@
- */
- i = inMap.find("_what");
- if (i == inMap.end()) {
-- sendExceptionLH(replyTo, cid, "_what element missing in Query");
-+ sendExceptionLH(rte, rtk, cid, "_what element missing in Query");
- return;
+ if (notifyFd != -1)
+ {
+- (void) ::write(notifyFd, ".", 1);
++ if (::write(notifyFd, ".", 1)) {}
}
+ }
- if (i->second.getType() != qpid::types::VAR_STRING) {
-- sendExceptionLH(replyTo, cid, "_what element is not a string");
-+ sendExceptionLH(rte, rtk, cid, "_what element is not a string");
- return;
- }
+@@ -431,7 +431,7 @@ void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind k
- if (i->second.asString() != "OBJECT") {
-- sendExceptionLH(replyTo, cid, "Query for _what => '" + i->second.asString() + "' not supported");
-+ sendExceptionLH(rte, rtk, cid, "Query for _what => '" + i->second.asString() + "' not supported");
- return;
+ if (notifyFd != -1)
+ {
+- (void) ::write(notifyFd, ".", 1);
++ if (::write(notifyFd, ".", 1)) {}
}
+ }
-@@ -1768,8 +1795,8 @@
- string content;
-
- ListCodec::encode(list_, content);
-- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
-- QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << replyTo);
-+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
-+ QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << rte << "/" << rtk);
- return;
+diff --git a/qpid/cpp/src/qpid/broker/Daemon.cpp b/qpid/cpp/src/qpid/broker/Daemon.cpp
+index c36538b..281345b 100644
+--- a/qpid/cpp/src/qpid/broker/Daemon.cpp
++++ b/qpid/cpp/src/qpid/broker/Daemon.cpp
+@@ -93,13 +93,13 @@ void Daemon::fork()
+ catch (const exception& e) {
+ QPID_LOG(critical, "Unexpected error: " << e.what());
+ uint16_t port = 0;
+- (void) write(pipeFds[1], &port, sizeof(uint16_t));
++ if (write(pipeFds[1], &port, sizeof(uint16_t))) {};
+
+ std::string pipeFailureMessage = e.what();
+- (void) write ( pipeFds[1],
+- pipeFailureMessage.c_str(),
+- strlen(pipeFailureMessage.c_str())
+- );
++ if (write(pipeFds[1],
++ pipeFailureMessage.c_str(),
++ strlen(pipeFailureMessage.c_str())
++ )) {};
}
- } else {
-@@ -1821,27 +1848,26 @@
- string content;
- while (_list.size() > 1) {
- ListCodec::encode(_list.front().asList(), content);
-- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
-+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
- _list.pop_front();
-- QPID_LOG(trace, "SENT QueryResponse (partial, query by schema_id) to=" << replyTo << " size=" << content.length());
-+ QPID_LOG(trace, "SENT QueryResponse (partial, query by schema_id) to=" << rte << "/" << rtk << " size=" << content.length());
- }
- headers.erase("partial");
- ListCodec::encode(_list.size() ? _list.front().asList() : Variant::List(), content);
-- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
-- QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << replyTo << " size=" << content.length());
-+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
-+ QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << rte << "/" << rtk << " size=" << content.length());
- return;
}
-
- // Unrecognized query - Send empty message to indicate CommandComplete
- string content;
- ListCodec::encode(Variant::List(), content);
-- sendBufferLH(content, cid, headers, "amqp/list", v2Direct, replyTo);
-- QPID_LOG(trace, "SENT QueryResponse (empty) to=" << replyTo);
-+ sendBufferLH(content, cid, headers, "amqp/list", rte, rtk);
-+ QPID_LOG(trace, "SENT QueryResponse (empty) to=" << rte << "/" << rtk);
- }
-
-
--void ManagementAgent::handleLocateRequestLH(const string&, const string& replyTo,
-- const string& cid)
-+void ManagementAgent::handleLocateRequestLH(const string&, const string& rte, const string& rtk, const string& cid)
- {
- QPID_LOG(trace, "RCVD AgentLocateRequest");
-
-@@ -1853,16 +1879,16 @@
- headers["qmf.agent"] = name_address;
-
- map["_values"] = attrMap;
-- map["_values"].asMap()["timestamp"] = uint64_t(sys::Duration(sys::EPOCH, sys::now()));
-- map["_values"].asMap()["heartbeat_interval"] = interval;
-- map["_values"].asMap()["epoch"] = bootSequence;
-+ map["_values"].asMap()["_timestamp"] = uint64_t(sys::Duration(sys::EPOCH, sys::now()));
-+ map["_values"].asMap()["_heartbeat_interval"] = interval;
-+ map["_values"].asMap()["_epoch"] = bootSequence;
-
- string content;
- MapCodec::encode(map, content);
-- sendBufferLH(content, cid, headers, "amqp/map", v2Direct, replyTo);
-+ sendBufferLH(content, cid, headers, "amqp/map", rte, rtk);
- clientWasAdded = true;
-
-- QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << replyTo);
-+ QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << rte << "/" << rtk);
- }
-
-
-@@ -1984,13 +2010,14 @@
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
- if (p && p->hasReplyTo()) {
- const framing::ReplyTo& rt = p->getReplyTo();
-- string replyToKey = rt.getRoutingKey();
-+ string rte = rt.getExchange();
-+ string rtk = rt.getRoutingKey();
- string cid;
- if (p && p->hasCorrelationId())
- cid = p->getCorrelationId();
-
- if (mapMsg) {
-- sendExceptionLH(replyToKey, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
-+ sendExceptionLH(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
- Manageable::STATUS_FORBIDDEN, false);
- } else {
-
-@@ -2002,7 +2029,7 @@
- outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
- outLen = MA_BUFFER_SIZE - outBuffer.available();
- outBuffer.reset();
-- sendBufferLH(outBuffer, outLen, dExchange, replyToKey);
-+ sendBufferLH(outBuffer, outLen, rte, rtk);
+ else { // Parent
+diff --git a/qpid/cpp/src/qpid/sys/posix/LockFile.cpp b/qpid/cpp/src/qpid/sys/posix/LockFile.cpp
+index f5a6c29..c1f1c37 100755
+--- a/qpid/cpp/src/qpid/sys/posix/LockFile.cpp
++++ b/qpid/cpp/src/qpid/sys/posix/LockFile.cpp
+@@ -58,7 +58,7 @@ LockFile::~LockFile() {
+ if (impl) {
+ int f = impl->fd;
+ if (f >= 0) {
+- (void) ::lockf(f, F_ULOCK, 0); // Suppress warnings about ignoring return value.
++ if(::lockf(f, F_ULOCK, 0)) {} // Suppress warnings about ignoring return value.
+ ::close(f);
+ impl->fd = -1;
+ }
+diff --git a/qpid/cpp/src/tests/BrokerMgmtAgent.cpp b/qpid/cpp/src/tests/BrokerMgmtAgent.cpp
+index 1d5289d..02aa87f 100644
+--- a/qpid/cpp/src/tests/BrokerMgmtAgent.cpp
++++ b/qpid/cpp/src/tests/BrokerMgmtAgent.cpp
+@@ -604,7 +604,7 @@ namespace qpid {
+ std::stringstream key;
+ key << "testobj-" << i;
+ TestManageable *tm = new TestManageable(agent, key.str());
+- (void) tm->GetManagementObject()->writePropertiesSize();
++ if (tm->GetManagementObject()->writePropertiesSize()) {}
+ agent->addObject(tm->GetManagementObject(), key.str());
+ tmv.push_back(tm);
}
-
- QPID_LOG(trace, "SEND MethodResponse status=FORBIDDEN" << " seq=" << sequence);
-@@ -2016,12 +2043,15 @@
-
- void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
- {
-- string replyToKey;
-+ string rte;
-+ string rtk;
-+
- const framing::MessageProperties* p =
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
- if (p && p->hasReplyTo()) {
- const framing::ReplyTo& rt = p->getReplyTo();
-- replyToKey = rt.getRoutingKey();
-+ rte = rt.getExchange();
-+ rtk = rt.getRoutingKey();
+diff --git a/qpid/cpp/src/tests/ForkedBroker.cpp b/qpid/cpp/src/tests/ForkedBroker.cpp
+index 10674b5..de1b42d 100644
+--- a/qpid/cpp/src/tests/ForkedBroker.cpp
++++ b/qpid/cpp/src/tests/ForkedBroker.cpp
+@@ -68,7 +68,7 @@ ForkedBroker::~ForkedBroker() {
}
- else
- return;
-@@ -2053,11 +2083,11 @@
- }
-
- if (opcode == "_method_request")
-- return handleMethodRequestLH(body, replyToKey, cid, msg.getPublisher(), viaLocal);
-+ return handleMethodRequestLH(body, rte, rtk, cid, msg.getPublisher(), viaLocal);
- else if (opcode == "_query_request")
-- return handleGetQueryLH(body, replyToKey, cid, viaLocal);
-+ return handleGetQueryLH(body, rte, rtk, cid, viaLocal);
- else if (opcode == "_agent_locate_request")
-- return handleLocateRequestLH(body, replyToKey, cid);
-+ return handleLocateRequestLH(body, rte, rtk, cid);
-
- QPID_LOG(warning, "Support for QMF Opcode [" << opcode << "] TBD!!!");
- return;
-@@ -2070,16 +2100,16 @@
- if (!checkHeader(inBuffer, &opcode, &sequence))
- return;
-
-- if (opcode == 'B') handleBrokerRequestLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'P') handlePackageQueryLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'p') handlePackageIndLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'Q') handleClassQueryLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'q') handleClassIndLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'S') handleSchemaRequestLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 's') handleSchemaResponseLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'A') handleAttachRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
-- else if (opcode == 'G') handleGetQueryLH (inBuffer, replyToKey, sequence);
-- else if (opcode == 'M') handleMethodRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
-+ if (opcode == 'B') handleBrokerRequestLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'P') handlePackageQueryLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'p') handlePackageIndLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'Q') handleClassQueryLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'q') handleClassIndLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'S') handleSchemaRequestLH (inBuffer, rte, rtk, sequence);
-+ else if (opcode == 's') handleSchemaResponseLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'A') handleAttachRequestLH (inBuffer, rtk, sequence, msg.getPublisher());
-+ else if (opcode == 'G') handleGetQueryLH (inBuffer, rtk, sequence);
-+ else if (opcode == 'M') handleMethodRequestLH (inBuffer, rtk, sequence, msg.getPublisher());
+ if (!dataDir.empty())
+ {
+- (void) ::system(("rm -rf "+dataDir).c_str());
++ if(::system(("rm -rf "+dataDir).c_str())) {}
}
}
-Index: cpp/src/qpid/management/Manageable.cpp
-===================================================================
---- cpp/src/qpid/management/Manageable.cpp (revision 1056407)
-+++ cpp/src/qpid/management/Manageable.cpp (working copy)
-@@ -46,3 +46,8 @@
- return STATUS_UNKNOWN_METHOD;
- }
-
-+bool Manageable::AuthorizeMethod(uint32_t, Args&, const std::string&)
-+{
-+ return true;
-+}
-+
-Index: cpp/bindings/swig_python_typemaps.i
-===================================================================
---- cpp/bindings/swig_python_typemaps.i (revision 1056407)
-+++ cpp/bindings/swig_python_typemaps.i (working copy)
-@@ -32,11 +32,11 @@
- void PyToList(PyObject*, qpid::types::Variant::List*);
-
- qpid::types::Variant PyToVariant(PyObject* value) {
-+ if (PyBool_Check(value)) return qpid::types::Variant(bool(PyInt_AS_LONG(value) ? true : false));
- if (PyFloat_Check(value)) return qpid::types::Variant(PyFloat_AS_DOUBLE(value));
-- if (PyString_Check(value)) return qpid::types::Variant(std::string(PyString_AS_STRING(value)));
- if (PyInt_Check(value)) return qpid::types::Variant(int64_t(PyInt_AS_LONG(value)));
- if (PyLong_Check(value)) return qpid::types::Variant(int64_t(PyLong_AsLongLong(value)));
-- if (PyBool_Check(value)) return qpid::types::Variant(bool(PyInt_AS_LONG(value) ? true : false));
-+ if (PyString_Check(value)) return qpid::types::Variant(std::string(PyString_AS_STRING(value)));
- if (PyDict_Check(value)) {
- qpid::types::Variant::Map map;
- PyToMap(value, &map);
-@@ -271,19 +271,27 @@
- Py_INCREF($result);
- }
-
--%typemap(typecheck) qpid::types::Variant::Map& {
-- $1 = PyDict_Check($input) ? 1 : 0;
--}
--
- /*
- * Variant types: C++ --> Python
- */
-+%typemap(out) qpid::types::Variant::Map {
-+ $result = MapToPy(&$1);
-+ if ($result)
-+ Py_INCREF($result);
-+}
-+
- %typemap(out) qpid::types::Variant::Map& {
- $result = MapToPy($1);
- if ($result)
- Py_INCREF($result);
- }
-
-+%typemap(out) qpid::types::Variant::List {
-+ $result = ListToPy(&$1);
-+ if ($result)
-+ Py_INCREF($result);
-+}
-+
- %typemap(out) qpid::types::Variant::List& {
- $result = ListToPy($1);
- if ($result)
-@@ -314,6 +322,16 @@
- PyToList($input, $1);
- }
-
-+%typemap(in) const qpid::types::Variant::Map const & {
-+ $1 = new qpid::types::Variant::Map();
-+ PyToMap($input, $1);
-+}
-+
-+%typemap(in) const qpid::types::Variant::List const & {
-+ $1 = new qpid::types::Variant::List();
-+ PyToList($input, $1);
-+}
-+
- %typemap(freearg) qpid::types::Variant& {
- delete $1;
- }
-@@ -334,7 +352,7 @@
- $1 = PyDict_Check($input) ? 1 : 0;
- }
-
--%typemap(typecheck) qpid::types::Variant::List& {
-+%typemap(typecheck) qpid::types::Variant::List& {
- $1 = PyList_Check($input) ? 1 : 0;
- }
-
-@@ -348,6 +366,24 @@
- PyBool_Check($input)) ? 1 : 0;
- }
-
-+%typemap(typecheck) const qpid::types::Variant::Map const & {
-+ $1 = PyDict_Check($input) ? 1 : 0;
-+}
-+
-+%typemap(typecheck) const qpid::types::Variant::List const & {
-+ $1 = PyList_Check($input) ? 1 : 0;
-+}
-+
-+%typemap(typecheck) const qpid::types::Variant const & {
-+ $1 = (PyFloat_Check($input) ||
-+ PyString_Check($input) ||
-+ PyInt_Check($input) ||
-+ PyLong_Check($input) ||
-+ PyDict_Check($input) ||
-+ PyList_Check($input) ||
-+ PyBool_Check($input)) ? 1 : 0;
-+}
-+
- %typemap(typecheck) bool {
- $1 = PyBool_Check($input) ? 1 : 0;
- }
-Index: cpp/bindings/swig_ruby_typemaps.i
-===================================================================
---- cpp/bindings/swig_ruby_typemaps.i (revision 1056407)
-+++ cpp/bindings/swig_ruby_typemaps.i (working copy)
-@@ -237,10 +237,18 @@
- /*
- * Variant types: C++ --> Ruby
- */
-+%typemap(out) qpid::types::Variant::Map {
-+ $result = MapToRb(&$1);
-+}
-+
- %typemap(out) qpid::types::Variant::Map& {
- $result = MapToRb($1);
- }
-
-+%typemap(out) qpid::types::Variant::List {
-+ $result = ListToRb(&$1);
-+}
-+
- %typemap(out) qpid::types::Variant::List& {
- $result = ListToRb($1);
- }
-@@ -267,6 +275,16 @@
- RbToList($input, $1);
- }
-
-+%typemap(in) const qpid::types::Variant::Map const & {
-+ $1 = new qpid::types::Variant::Map();
-+ RbToMap($input, $1);
-+}
-+
-+%typemap(in) const qpid::types::Variant::List const & {
-+ $1 = new qpid::types::Variant::List();
-+ RbToList($input, $1);
-+}
-+
- %typemap(freearg) qpid::types::Variant& {
- delete $1;
- }
-@@ -300,6 +318,23 @@
- TYPE($input) == T_FALSE) ? 1 : 0;
- }
-
-+%typemap(typecheck) qpid::types::Variant::Map const & {
-+ $1 = (TYPE($input) == T_HASH) ? 1 : 0;
-+}
-+
-+%typemap(typecheck) qpid::types::Variant::List const & {
-+ $1 = (TYPE($input) == T_ARRAY) ? 1 : 0;
-+}
-+
-+%typemap(typecheck) const qpid::types::Variant const & {
-+ $1 = (TYPE($input) == T_FLOAT ||
-+ TYPE($input) == T_STRING ||
-+ TYPE($input) == T_FIXNUM ||
-+ TYPE($input) == T_BIGNUM ||
-+ TYPE($input) == T_TRUE ||
-+ TYPE($input) == T_FALSE) ? 1 : 0;
-+}
-+
- %typemap(typecheck) bool {
- $1 = (TYPE($input) == T_TRUE ||
- TYPE($input) == T_FALSE) ? 1 : 0;
-Index: cpp/bindings/qmf2/python/Makefile.am
-===================================================================
---- cpp/bindings/qmf2/python/Makefile.am (revision 1056407)
-+++ cpp/bindings/qmf2/python/Makefile.am (working copy)
-@@ -27,13 +27,16 @@
-
- EXTRA_DIST = python.i
- BUILT_SOURCES = $(generated_file_list)
-+SWIG_FLAGS = -w362,401
-
- $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_python_typemaps.i
-- swig -c++ -python -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i
-+ swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i
-
- pylibdir = $(PYTHON_LIB)
-
- lib_LTLIBRARIES = _cqmf2.la
-+cqpiddir = $(pythondir)
-+cqpid_PYTHON = qmf2.py cqmf2.py
-
- _cqmf2_la_LDFLAGS = -avoid-version -module -shared
- _cqmf2_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs $(top_builddir)/src/libqmf2.la
-Index: cpp/bindings/qmf2/python/qmf2.py
-===================================================================
---- cpp/bindings/qmf2/python/qmf2.py (revision 1056407)
-+++ cpp/bindings/qmf2/python/qmf2.py (working copy)
-@@ -137,7 +137,91 @@
- pass
-
-
-+#===================================================================================================
-+# CONSOLE HANDLER
-+#===================================================================================================
-+class ConsoleHandler(Thread):
-
-+ def __init__(self, consoleSession):
-+ Thread.__init__(self)
-+ self.__session = consoleSession
-+ self.__running = True
-+
-+ def cancel(self):
-+ """
-+ Stop the handler thread.
-+ """
-+ self.__running = None
-+
-+ def run(self):
-+ event = cqmf2.ConsoleEvent()
-+ while self.__running:
-+ valid = self.__session._impl.nextEvent(event, cqpid.Duration.SECOND)
-+ if valid and self.__running:
-+ if event.getType() == cqmf2.CONSOLE_AGENT_ADD:
-+ self.agentAdded(Agent(event.getAgent()))
-+
-+ elif event.getType() == cqmf2.CONSOLE_AGENT_DEL:
-+ reason = 'filter'
-+ if event.getAgentDelReason() == cqmf2.AGENT_DEL_AGED:
-+ reason = 'aged'
-+ self.agentDeleted(Agent(event.getAgent()), reason)
-+
-+ elif event.getType() == cqmf2.CONSOLE_AGENT_RESTART:
-+ self.agentRestarted(Agent(event.getAgent()))
-+
-+ elif event.getType() == cqmf2.CONSOLE_AGENT_SCHEMA_UPDATE:
-+ self.agentSchemaUpdated(Agent(event.getAgent()))
-+
-+ elif event.getType() == cqmf2.CONSOLE_EVENT:
-+ self.eventRaised(Agent(event.getAgent()), Data(event.getData(0)), event.getTimestamp(), event.getSeverity())
-+
-+ ##
-+ ## The following methods are intended to be overridden in a sub-class. They are
-+ ## handlers for events that occur on QMF consoles.
-+ ##
-+
-+ #
-+ # A new agent, whose attributes match the console's agent filter, has been discovered.
-+ #
-+ def agentAdded(self, agent):
-+ pass
-+
-+ #
-+ # A known agent has been removed from the agent list. There are two possible reasons
-+ # for agent deletion:
-+ #
-+ # 1) 'aged' - The agent hasn't been heard from for the maximum age interval and is
-+ # presumed dead.
-+ # 2) 'filter' - The agent no longer matches the console's agent-filter and has been
-+ # effectively removed from the agent list. Such occurrences are likely
-+ # to be seen immediately after setting the filter to a new value.
-+ #
-+ def agentDeleted(self, agent, reason):
-+ pass
-+
-+ #
-+ # An agent-restart was detected. This occurs when the epoch number advertised by the
-+ # agent changes. It indicates that the agent in question was shut-down/crashed and
-+ # restarted.
-+ #
-+ def agentRestarted(self, agent):
-+ pass
-+
-+ #
-+ # The agent has registered new schema information which can now be queried, if desired.
-+ #
-+ def agentSchemaUpdated(self, agent):
-+ pass
-+
-+ #
-+ # An agent raised an event. The 'data' argument is a Data object that contains the
-+ # content of the event.
-+ #
-+ def eventRaised(self, agent, data, timestamp, severity):
-+ pass
-+
-+
- #===================================================================================================
- # CONSOLE SESSION
- #===================================================================================================
-@@ -147,6 +231,16 @@
-
- def __init__(self, connection, options=""):
- """
-+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
-+ ##
-+ ## domain:NAME - QMF Domain to join [default: "default"]
-+ ## max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
-+ ## an agent before deleting it [default: 5]
-+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ ## If False: Listen only on the routable direct address
-+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
-+ ##
- """
- self._impl = cqmf2.ConsoleSession(connection, options)
-
-@@ -195,6 +289,24 @@
-
- def __init__(self, connection, options=""):
- """
-+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
-+ ##
-+ ## interval:N - Heartbeat interval in seconds [default: 60]
-+ ## external:{True,False} - Use external data storage (queries and subscriptions are pass-through) [default: False]
-+ ## allow-queries:{True,False} - If True: automatically allow all queries [default]
-+ ## If False: generate an AUTH_QUERY event to allow per-query authorization
-+ ## allow-methods:{True,False} - If True: automatically allow all methods [default]
-+ ## If False: generate an AUTH_METHOD event to allow per-method authorization
-+ ## max-subscriptions:N - Maximum number of concurrent subscription queries permitted [default: 64]
-+ ## min-sub-interval:N - Minimum publish interval (in milliseconds) permitted for a subscription [default: 3000]
-+ ## sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
-+ ## public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
-+ ## If False: QMF events are only sent to authorized subscribers
-+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ ## If False: Listen only on the routable direct address
-+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
-+ ##
- """
- self._impl = cqmf2.AgentSession(connection, options)
-
-@@ -261,7 +373,15 @@
- else:
- self._impl.raiseException(handle, data)
-
-- ## TODO: async and external operations
-+ def raiseEvent(self, data, severity=None):
-+ """
-+ """
-+ if not severity:
-+ self._impl.raiseEvent(data._impl)
-+ else:
-+ if (severity.__class__ != int and severity.__class__ != long) or severity < 0 or severity > 7:
-+ raise Exception("Severity must be an int between 0..7")
-+ self._impl.raiseEvent(data._impl, severity);
-
-
- #===================================================================================================
-@@ -311,7 +431,7 @@
- """
- """
- if q.__class__ == Query:
-- q_arg = Query._impl
-+ q_arg = q._impl
- else:
- q_arg = q
- dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout)
-@@ -366,11 +486,35 @@
- """
- """
-
-- def __init__(self, *kwargs):
-+ def __init__(self, arg1, arg2=None, arg3=None, *kwargs):
- """
- """
-- pass
-+ if arg1.__class__ == DataAddr:
-+ self._impl = cqmf2.Query(arg1._impl)
-
-+ def getAddr(self):
-+ """
-+ """
-+ return DataAddr(self._impl.getDataAddr())
-+
-+ def getSchemaId(self):
-+ """
-+ """
-+ return SchemaId(self._impl.getSchemaId())
-+
-+ def getPredicate(self):
-+ """
-+ """
-+ return self._impl.getPredicate()
-+
-+ def matches(self, data):
-+ """
-+ """
-+ m = data
-+ if data.__class__ == Data:
-+ m = data.getProperties()
-+ return self._impl.matchesPredicate(m)
-+
- #===================================================================================================
- # DATA
- #===================================================================================================
-@@ -385,10 +529,8 @@
- self._impl = cqmf2.Data()
- elif arg.__class__ == cqmf2.Data:
- self._impl = arg
-- elif arg.__class__ == SchemaId:
-+ elif arg.__class__ == Schema:
- self._impl = cqmf2.Data(arg._impl)
-- elif arg.__class__ == Schema:
-- self._impl = cqmf2.Data(arg.getSchemaId()._impl)
- else:
- raise Exception("Unsupported initializer for Data")
- self._schema = None
-@@ -412,6 +554,17 @@
- """
- return Agent(self._impl.getAgent())
-
-+ def update(self, timeout=5):
-+ dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout)
-+ agent = self._impl.getAgent()
-+ query = cqmf2.Query(self._impl.getAddr())
-+ result = agent.query(query, dur)
-+ if result.getType() != cqmf2.CONSOLE_QUERY_RESPONSE:
-+ raise "Update query failed"
-+ if result.getDataCount == 0:
-+ raise "Object no longer exists on agent"
-+ self._impl = cqmf2.Data(result.getData(0))
-+
- def getProperties(self):
- """
- """
-@@ -444,6 +597,7 @@
- ## validate that we have the right number of arguments supplied, and marshall them
- ## into a map for transmission.
- ##
-+ arglist = []
- methods = self._schema.getMethods()
- for m in methods:
- if m.getName() == name:
-@@ -519,8 +673,13 @@
- """
- """
-
-- def __init__(self, impl):
-- self._impl = impl
-+ def __init__(self, arg, agentName=""):
-+ if arg.__class__ == dict:
-+ self._impl = cqmf2.DataAddr(arg)
-+ elif arg.__class__ == cqmf2.DataAddr:
-+ self._impl = arg
-+ else:
-+ self._impl = cqmf2.DataAddr(arg, agentName)
-
- def __repr__(self):
- return "%s:%s" % (self.getAgentName(), self.getName())
-@@ -530,6 +689,11 @@
- self.getName() == other.getName() and \
- self.getAgentEpoch() == other.getAgentEpoch()
-
-+ def asMap(self):
-+ """
-+ """
-+ return self._impl.asMap()
-+
- def getAgentName(self):
- """
- """
-@@ -683,6 +847,11 @@
- """
- return self._impl.getName()
-
-+ def getType(self):
-+ """
-+ """
-+ return self._impl.getType()
-+
- def getAccess(self):
- """
- """
-Index: cpp/bindings/qmf2/ruby/qmf2.rb
-===================================================================
---- cpp/bindings/qmf2/ruby/qmf2.rb (revision 1056407)
-+++ cpp/bindings/qmf2/ruby/qmf2.rb (working copy)
-@@ -78,21 +78,292 @@
- end
-
- ##==============================================================================
-- ## AGENT HANDLER TODO
-+ ## AGENT HANDLER
- ##==============================================================================
-
- class AgentHandler
-- def get_query(context, query, userId); end
-- def method_call(context, name, object_id, args, userId); end
-+
-+ def initialize(session)
-+ @_session = session
-+ @_running = false
-+ @_thread = nil
-+ end
-+
-+ ##
-+ ## Call the "start" method to run the handler on a new thread.
-+ ##
-+ def start
-+ @_thread = Thread.new do
-+ run
-+ end
-+ end
-+
-+ ##
-+ ## Request that the running thread complete and exit.
-+ ##
-+ def cancel
-+ @_running = false
-+ @_thread.join if @_thread
-+ @_thread = nil
-+ end
-+
-+ ##
-+ ## Call the "run" method only if you want the handler to run on your own thread.
-+ ##
-+ def run
-+ @_running = true
-+ event = Cqmf2::AgentEvent.new
-+ while @_running do
-+ valid = @_session.impl.nextEvent(event, Cqpid::Duration.SECOND)
-+ if valid and @_running
-+ case event.getType
-+ when Cqmf2::AGENT_AUTH_QUERY
-+ yes = authorize_query(Query.new(event.getQuery()), event.getUserId())
-+ if yes == true
-+ @_session.impl.authAccept(event)
-+ else
-+ @_session.impl.authReject(event)
-+ end
-+
-+ when Cqmf2::AGENT_QUERY
-+ context = QueryContext.new(@_session, event)
-+ get_query(context, Query.new(event.getQuery()), event.getUserId())
-+
-+ when Cqmf2::AGENT_METHOD
-+ context = MethodContext.new(@_session, event)
-+ begin
-+ method_call(context, event.getMethodName(), event.getDataAddr(), event.getArguments(), event.getUserId())
-+ rescue Exception => ex
-+ @_session.impl.raiseException(event, "#{ex}")
-+ end
-+
-+ end
-+ end
-+ end
-+ end
-+
-+
-+ ##
-+ ## The following methods are intended to be overridden in a sub-class. They are
-+ ## handlers for events that occur on QMF consoles.
-+ ##
-+
-+ #
-+ # This method will only be invoked if the "allow-queries" option is enabled on the
-+ # agent session. When invoked, it provides the query and the authenticated user-id
-+ # of the querying client.
-+ #
-+ # This method must return true if the query is permitted, false otherwise.
-+ #
-+ def authorize_query(query, user_id); end
-+
-+ #
-+ # This method will only be invoked if the "external" option is "True" on the agent
-+ # session. When invoked, the method should begin the process of responding to a data
-+ # query. The authenticated user-id of the requestor is provided for informational
-+ # purposes. The 'context' variable is used to provide the results back to the requestor.
-+ #
-+ # For each matching Data object, call context.response(data). When the query is complete,
-+ # call context.complete(). After completing the query, you should not use 'context' any
-+ # longer.
-+ #
-+ # Note: It is not necessary to process the query synchronously. If desired, this method
-+ # may store the context for asynchronous processing or pass it to another thread for
-+ # processing. There is no restriction on the number of contexts that may be in-flight
-+ # concurrently.
-+ #
-+ def get_query(context, query, user_id); end
-+
-+ #
-+ # This method is invoked when a console calls a QMF method on the agent. Supplied are
-+ # a context for the response, the method name, the data address of the data object being
-+ # called, the input arguments (a dictionary), and the caller's authenticated user-id.
-+ #
-+ # A method call can end one of two ways: Successful completion, in which the output
-+ # arguments (if any) are supplied; and Exceptional completion if there is an error.
-+ #
-+ # Successful Completion:
-+ # For each output argument, assign the value directly to context (context.arg1 = "value")
-+ # Once arguments are assigned, call context._success().
-+ #
-+ # Exceptional Completion:
-+ # Method 1: Call context._exception(data) where 'data' is a string or a Data object.
-+ # Method 2: Raise an exception (raise "Error Text") synchronously in the method body.
-+ #
-+ # Note: Like get_query, method_call may process methods synchronously or asynchronously.
-+ # This method may store the context for later asynchronous processing. There is no
-+ # restriction on the number of contexts that may be in-flight concurrently.
-+ #
-+ # However, "Method 2" for Exceptional Completion can only be done synchronously.
-+ #
-+ def method_call(context, method_name, data_addr, args, user_id); end
- end
-
-+ class QueryContext
-+ def initialize(agent, context)
-+ @agent = agent
-+ @context = context
-+ end
-+
-+ def response(data)
-+ @agent.impl.response(@context, data.impl)
-+ end
-+
-+ def complete
-+ @agent.impl.complete(@context)
-+ end
-+ end
-+
-+ class MethodContext
-+ def initialize(agent, context)
-+ @agent = agent
-+ @context = context
-+ end
-+
-+ def _success
-+ @agent.impl.methodSuccess(@context)
-+ end
-+
-+ def _exception(ex)
-+ if ex.class == Data
-+ @agent.impl.raiseException(@context, ex.impl)
-+ else
-+ @agent.impl.raiseException(@context, ex)
-+ end
-+ end
-+
-+ def method_missing(name_in, *args)
-+ name = name_in.to_s
-+ if name[name.length - 1] == 61
-+ name = name[0..name.length - 2]
-+ @context.impl.addReturnArgument(name, args[0])
-+ else
-+ super.method_missing(name_in, args)
-+ end
-+ end
-+ end
-+
- ##==============================================================================
-+ ## CONSOLE HANDLER
-+ ##==============================================================================
-+
-+ class ConsoleHandler
-+
-+ def initialize(session)
-+ @_session = session
-+ @_running = false
-+ @_thread = nil
-+ end
-+
-+ ##
-+ ## Call the "start" method to run the handler on a new thread.
-+ ##
-+ def start
-+ @_thread = Thread.new do
-+ run
-+ end
-+ end
-+
-+ ##
-+ ## Request that the running thread complete and exit.
-+ ##
-+ def cancel
-+ @_running = false
-+ @_thread.join if @_thread
-+ @_thread = nil
-+ end
-+
-+ ##
-+ ## Call the "run" method only if you want the handler to run on your own thread.
-+ ##
-+ def run
-+ @_running = true
-+ event = Cqmf2::ConsoleEvent.new
-+ while @_running do
-+ valid = @_session.impl.nextEvent(event, Cqpid::Duration.SECOND)
-+ if valid and @_running
-+ case event.getType
-+ when Cqmf2::CONSOLE_AGENT_ADD
-+ agent_added(Agent.new(event.getAgent))
-+
-+ when Cqmf2::CONSOLE_AGENT_DEL
-+ reason = :filter
-+ reason = :aged if event.getAgentDelReason == Cqmf2::AGENT_DEL_AGED
-+ agent_deleted(Agent.new(event.getAgent), reason)
-+
-+ when Cqmf2::CONSOLE_AGENT_RESTART
-+ agent_restarted(Agent.new(event.getAgent))
-+
-+ when Cqmf2::CONSOLE_AGENT_SCHEMA_UPDATE
-+ agent_schema_updated(Agent.new(event.getAgent))
-+
-+ when Cqmf2::CONSOLE_EVENT
-+ event_raised(Agent.new(event.getAgent), Data.new(event.getData(0)), event.getTimestamp, event.getSeverity)
-+
-+ end
-+ end
-+ end
-+ end
-+
-+
-+ ##
-+ ## The following methods are intended to be overridden in a sub-class. They are
-+ ## handlers for events that occur on QMF consoles.
-+ ##
-+
-+ #
-+ # A new agent, whose attributes match the console's agent filter, has been discovered.
-+ #
-+ def agent_added(agent); end
-+
-+ #
-+ # A known agent has been removed from the agent list. There are two possible reasons
-+ # for agent deletion:
-+ #
-+ # 1) :aged - The agent hasn't been heard from for the maximum age interval and is
-+ # presumed dead.
-+ # 2) :filter - The agent no longer matches the console's agent-filter and has been
-+ # effectively removed from the agent list. Such occurrences are likely
-+ # to be seen immediately after setting the filter to a new value.
-+ #
-+ def agent_deleted(agent, reason); end
-+
-+ #
-+ # An agent-restart was detected. This occurs when the epoch number advertised by the
-+ # agent changes. It indicates that the agent in question was shut-down/crashed and
-+ # restarted.
-+ #
-+ def agent_restarted(agent); end
-+
-+ #
-+ # The agent has registered new schema information which can now be queried, if desired.
-+ #
-+ def agent_schema_updated(agent); end
-+
-+ #
-+ # An agent raised an event. The 'data' argument is a Data object that contains the
-+ # content of the event.
-+ #
-+ def event_raised(agent, data, timestamp, severity); end
-+ end
-+
-+ ##==============================================================================
- ## CONSOLE SESSION
- ##==============================================================================
-
- class ConsoleSession
- attr_reader :impl
-
-+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
-+ ##
-+ ## domain:NAME - QMF Domain to join [default: "default"]
-+ ## max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
-+ ## an agent before deleting it [default: 5]
-+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ ## If False: Listen only on the routable direct address
-+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
-+ ##
- def initialize(connection, options="")
- @impl = Cqmf2::ConsoleSession.new(connection, options)
- end
-@@ -101,7 +372,7 @@
- def set_agent_filter(filter) @impl.setAgentFilter(filter) end
-
- def open() @impl.open end
-- def close() @imp.close end
-+ def close() @impl.close end
-
- def agents
- result = []
-@@ -124,6 +395,24 @@
- class AgentSession
- attr_reader :impl
-
-+ ## The options string is of the form "{key:value,key:value}". The following keys are supported:
-+ ##
-+ ## interval:N - Heartbeat interval in seconds [default: 60]
-+ ## external:{True,False} - Use external data storage (queries and subscriptions are pass-through) [default: False]
-+ ## allow-queries:{True,False} - If True: automatically allow all queries [default]
-+ ## If False: generate an AUTH_QUERY event to allow per-query authorization
-+ ## allow-methods:{True,False} - If True: automatically allow all methods [default]
-+ ## If False: generate an AUTH_METHOD event to allow per-method authorization
-+ ## max-subscriptions:N - Maximum number of concurrent subscription queries permitted [default: 64]
-+ ## min-sub-interval:N - Minimum publish interval (in milliseconds) permitted for a subscription [default: 3000]
-+ ## sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
-+ ## public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
-+ ## If False: QMF events are only sent to authorized subscribers
-+ ## listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ ## If False: Listen only on the routable direct address
-+ ## strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ ## - If False: Operate more flexibly with regard to use of messaging facilities [default]
-+ ##
- def initialize(connection, options="")
- @impl = Cqmf2::AgentSession.new(connection, options)
- end
-@@ -134,10 +423,10 @@
- def set_instance(val) @impl.setInstance(val) end
- def set_attribute(key, val) @impl.setAttribute(key, val) end
- def open() @impl.open end
-- def close() @imp.close end
-+ def close() @impl.close end
- def register_schema(cls) @impl.registerSchema(cls.impl) end
-
-- def add_data(data, name="", persistent=:false)
-+ def add_data(data, name="", persistent=false)
- DataAddr.new(@impl.addData(data.impl, name, persistent))
- end
-
-@@ -145,15 +434,11 @@
- @impl.del_data(addr.impl)
- end
-
-- def method_success(handle)
-- @impl.methodSuccess(handle)
-- end
--
-- def raise_exception(handle, data)
-- if data.class == Data
-- @impl.raiseException(handle, data.impl)
-+ def raise_event(data, severity=nil)
-+ if !severity
-+ @impl.raiseEvent(data.impl)
- else
-- @impl.raiseException(handle, data)
-+ @impl.raiseEvent(data.impl, severity)
- end
- end
- end
-@@ -228,14 +513,26 @@
- end
-
- ##==============================================================================
-- ## QUERY TODO
-+ ## QUERY
- ##==============================================================================
-
- class Query
- attr_reader :impl
-- def initialize
-- @impl = nil
-+ def initialize(arg1, arg2=nil, arg3=nil)
-+ if arg1.class == Qmf2::DataAddr
-+ @impl = Cqmf2::Query.new(arg1.impl)
-+ end
- end
-+
-+ def addr() DataAddr.new(@impl.getDataAddr()) end
-+ def schema_id() SchemaId.new(@impl.getSchemaId()) end
-+ def predicate() @impl.getPredicate() end
-+
-+ def matches?(data)
-+ map = data
-+ map = data.properties if data.class == Data
-+ @impl.matchesPredicate(map)
-+ end
- end
-
- ##==============================================================================
-@@ -246,18 +543,17 @@
- attr_reader :impl
-
- def initialize(arg=nil)
-+ @schema = nil
- if arg == nil
- @impl = Cqmf2::Data.new
- elsif arg.class == Cqmf2::Data
- @impl = arg
-- elsif arg.class == SchemaId
-- @impl = Cqmf2::Data(arg.impl)
- elsif arg.class == Schema
-- @impl = Cqmf2::Data(arg.impl.getSchemaId)
-+ @impl = Cqmf2::Data.new(arg.impl)
-+ @schema = arg
- else
- raise "Unsupported initializer for Data"
- end
-- @schema = nil
- end
-
- def to_s
-@@ -271,6 +567,10 @@
- return nil
- end
-
-+ def set_addr(addr)
-+ @impl.setAddr(addr.impl)
-+ end
-+
- def addr
- if @impl.hasAddr
- return DataAddr.new(@impl.getAddr)
-@@ -282,6 +582,17 @@
- return Agent.new(@impl.getAgent)
- end
-
-+ def update(timeout=5)
-+ dur = Cqpid::Duration.new(Cqpid::Duration.SECOND.getMilliseconds * timeout)
-+ agent = @impl.getAgent
-+ query = Cqmf2::Query.new(@impl.getAddr)
-+ result = agent.query(query, dur)
-+ raise "Update query failed" if result.getType != Cqmf2::CONSOLE_QUERY_RESPONSE
-+ raise "Object no longer exists on agent" if result.getDataCount == 0
-+ @impl = Cqmf2::Data.new(result.getData(0))
-+ return nil
-+ end
-+
- def properties
- return @impl.getProperties
- end
-@@ -392,14 +703,21 @@
- class DataAddr
- attr_reader :impl
-
-- def initialize(impl)
-- @impl = impl
-+ def initialize(arg, agentName="")
-+ if arg.class == Hash
-+ @impl = Cqmf2::DataAddr.new(arg)
-+ elsif arg.class == Cqmf2::DataAddr
-+ @impl = arg
-+ else
-+ @impl = Cqmf2::DataAddr.new(arg, agentName)
-+ end
- end
-
- def ==(other)
- return @impl == other.impl
- end
-
-+ def as_map() @impl.asMap end
- def agent_name() @impl.getAgentName end
- def name() @impl.getName end
- def agent_epoch() @impl.getAgentEpoch end
-Index: cpp/bindings/qmf2/ruby/Makefile.am
-===================================================================
---- cpp/bindings/qmf2/ruby/Makefile.am (revision 1056407)
-+++ cpp/bindings/qmf2/ruby/Makefile.am (working copy)
-@@ -23,14 +23,16 @@
-
- EXTRA_DIST = ruby.i
- BUILT_SOURCES = cqmf2.cpp
-+SWIG_FLAGS = -w362,401
-
- rubylibdir = $(RUBY_LIB)
-
- cqmf2.cpp: $(srcdir)/ruby.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_ruby_typemaps.i
-- $(SWIG) -ruby -c++ -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/ruby.i
-+ $(SWIG) -ruby -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/ruby.i
-
- rubylibarchdir = $(RUBY_LIB_ARCH)
- rubylibarch_LTLIBRARIES = cqmf2.la
-+dist_rubylib_DATA = qmf2.rb
-
- cqmf2_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)"
- cqmf2_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqmf2 $(top_builddir)/src/libqmf2.la
-Index: cpp/bindings/qmf2/qmf2.i
-===================================================================
---- cpp/bindings/qmf2/qmf2.i (revision 1056407)
-+++ cpp/bindings/qmf2/qmf2.i (working copy)
-@@ -33,6 +33,7 @@
- #include <qmf/SchemaMethod.h>
- #include <qmf/SchemaProperty.h>
- #include <qmf/SchemaTypes.h>
-+#include <qmf/Subscription.h>
-
- %}
-
-@@ -54,6 +55,7 @@
- %include <qmf/SchemaMethod.h>
- %include <qmf/SchemaProperty.h>
- %include <qmf/SchemaTypes.h>
-+%include <qmf/Subscription.h>
-
- %{
-
-Index: cpp/bindings/qmf2/examples/python/agent.py
-===================================================================
---- cpp/bindings/qmf2/examples/python/agent.py (revision 1056407)
-+++ cpp/bindings/qmf2/examples/python/agent.py (working copy)
-@@ -34,7 +34,8 @@
- ##
- ## Create and open a messaging connection to a broker.
- ##
-- self.connection = cqpid.Connection(url)
-+ self.connection = cqpid.Connection(url, "{reconnect:True}")
-+ self.session = None
- self.connection.open()
-
- ##
-@@ -56,7 +57,8 @@
- """
- Clean up the session and connection.
- """
-- self.session.close()
-+ if self.session:
-+ self.session.close()
- self.connection.close()
-
-
-@@ -67,26 +69,43 @@
- if addr == self.controlAddr:
- self.control.methodCount += 1
-
-- if methodName == "stop":
-- self.session.methodSuccess(handle)
-- self.cancel()
-+ try:
-+ if methodName == "stop":
-+ self.session.methodSuccess(handle)
-+ self.cancel()
-
-- elif methodName == "echo":
-- handle.addReturnArgument("sequence", args["sequence"])
-- handle.addReturnArgument("map", args["map"])
-- self.session.methodSuccess(handle)
-+ elif methodName == "echo":
-+ handle.addReturnArgument("sequence", args["sequence"])
-+ handle.addReturnArgument("map", args["map"])
-+ self.session.methodSuccess(handle)
-
-- elif methodName == "fail":
-- if args['useString']:
-- self.session.raiseException(handle, args['stringVal'])
-- else:
-- ex = Data(self.sch_exception)
-- ex.whatHappened = "It Failed"
-- ex.howBad = 75
-- ex.details = args['details']
-- self.session.raiseException(handle, ex)
-+ elif methodName == "event":
-+ ev = Data(self.sch_event)
-+ ev.text = args['text']
-+ self.session.raiseEvent(ev, args['severity'])
-+ self.session.methodSuccess(handle)
-
-+ elif methodName == "fail":
-+ if args['useString']:
-+ self.session.raiseException(handle, args['stringVal'])
-+ else:
-+ ex = Data(self.sch_exception)
-+ ex.whatHappened = "It Failed"
-+ ex.howBad = 75
-+ ex.details = args['details']
-+ self.session.raiseException(handle, ex)
-
-+ elif methodName == "create_child":
-+ name = args['name']
-+ child = Data(self.sch_child)
-+ child.name = name
-+ addr = self.session.addData(child, name)
-+ handle.addReturnArgument("childAddr", addr.asMap())
-+ self.session.methodSuccess(handle)
-+ except BaseException, e:
-+ self.session.raiseException(handle, "%r" % e)
-+
-+
- def setupSchema(self):
- """
- Create and register the schema for this agent.
-@@ -118,17 +137,41 @@
- echoMethod.addArgument(SchemaProperty("map", SCHEMA_DATA_MAP, direction=DIR_IN_OUT))
- self.sch_control.addMethod(echoMethod)
-
-+ eventMethod = SchemaMethod("event", desc="Raise an Event")
-+ eventMethod.addArgument(SchemaProperty("text", SCHEMA_DATA_STRING, direction=DIR_IN))
-+ eventMethod.addArgument(SchemaProperty("severity", SCHEMA_DATA_INT, direction=DIR_IN))
-+ self.sch_control.addMethod(eventMethod)
-+
- failMethod = SchemaMethod("fail", desc="Expected to Fail")
- failMethod.addArgument(SchemaProperty("useString", SCHEMA_DATA_BOOL, direction=DIR_IN))
- failMethod.addArgument(SchemaProperty("stringVal", SCHEMA_DATA_STRING, direction=DIR_IN))
- failMethod.addArgument(SchemaProperty("details", SCHEMA_DATA_MAP, direction=DIR_IN))
- self.sch_control.addMethod(failMethod)
-
-+ createMethod = SchemaMethod("create_child", desc="Create Child Object")
-+ createMethod.addArgument(SchemaProperty("name", SCHEMA_DATA_STRING, direction=DIR_IN))
-+ createMethod.addArgument(SchemaProperty("childAddr", SCHEMA_DATA_MAP, direction=DIR_OUT))
-+ self.sch_control.addMethod(createMethod)
-+
- ##
-+ ## Declare a child object
-+ ##
-+ self.sch_child = Schema(SCHEMA_TYPE_DATA, package, "child")
-+ self.sch_child.addProperty(SchemaProperty("name", SCHEMA_DATA_STRING))
-+
-+ ##
-+ ## Declare the event class
-+ ##
-+ self.sch_event = Schema(SCHEMA_TYPE_EVENT, package, "event")
-+ self.sch_event.addProperty(SchemaProperty("text", SCHEMA_DATA_STRING))
-+
-+ ##
- ## Register our schemata with the agent session.
- ##
- self.session.registerSchema(self.sch_exception)
- self.session.registerSchema(self.sch_control)
-+ self.session.registerSchema(self.sch_child)
-+ self.session.registerSchema(self.sch_event)
-
-
- def populateData(self):
-@@ -141,10 +184,13 @@
- self.controlAddr = self.session.addData(self.control, "singleton")
-
-
-+try:
-+ agent = ExampleAgent("localhost")
-+ agent.setupSchema()
-+ agent.populateData()
-+ agent.run() # Use agent.start() to launch the agent in a separate thread
-+ agent.shutdown()
-+except Exception, e:
-+ print "Exception Caught:", e
-
--agent = ExampleAgent("localhost")
--agent.setupSchema()
--agent.populateData()
--agent.run() # Use agent.start() to launch the agent in a separate thread
--agent.shutdown()
-
-Index: cpp/bindings/qmf2/examples/ruby/agent_external.rb
-===================================================================
---- cpp/bindings/qmf2/examples/ruby/agent_external.rb (revision 0)
-+++ cpp/bindings/qmf2/examples/ruby/agent_external.rb (revision 0)
-@@ -0,0 +1,84 @@
-+#
-+# Licensed to the Apache Software Foundation (ASF) under one
-+# or more contributor license agreements. See the NOTICE file
-+# distributed with this work for additional information
-+# regarding copyright ownership. The ASF licenses this file
-+# to you under the Apache License, Version 2.0 (the
-+# "License"); you may not use this file except in compliance
-+# with the License. You may obtain a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing,
-+# software distributed under the License is distributed on an
-+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-+# KIND, either express or implied. See the License for the
-+# specific language governing permissions and limitations
-+# under the License.
-+#
-+
-+require 'cqpid'
-+require 'qmf2'
-+
-+class MyAgent < Qmf2::AgentHandler
-+
-+ def initialize(session, data)
-+ super(session)
-+ @data = data
-+ end
-+
-+ def authorize_query(query, user_id)
-+ puts "Authorizing #{user_id}"
-+ return true
-+ end
-+
-+ def get_query(context, query, user_id)
-+ puts "Get Query"
-+ context.response(@data)
-+ context.complete
-+ end
-+
-+ def method_call(context, method_name, data_addr, args, user_id)
-+ puts "Method: #{method_name}"
-+ context._success
-+ end
-+
-+end
-+
-+
-+class Program
-+
-+ def initialize(url)
-+ @url = url
-+ @sess_options = "{allow-queries:False, external:True}"
-+ end
-+
-+ def setup_schema(agent)
-+ @cls_control = Qmf2::Schema.new(Qmf2::SCHEMA_TYPE_DATA, "org.package", "control")
-+ @cls_control.add_property(Qmf2::SchemaProperty.new("state", Qmf2::SCHEMA_DATA_STRING))
-+ agent.register_schema(@cls_control)
-+ end
-+
-+ def run
-+ connection = Cqpid::Connection.new(@url)
-+ connection.open
-+
-+ session = Qmf2::AgentSession.new(connection, @sess_options)
-+ session.set_vendor("package.org")
-+ session.set_product("external_agent")
-+ setup_schema(session)
-+ session.open
-+
-+ @control = Qmf2::Data.new(@cls_control)
-+ @control.state = "OPERATIONAL-EXTERNAL"
-+ @control.set_addr(Qmf2::DataAddr.new("singleton"))
-+
-+ main = MyAgent.new(session, @control)
-+ main.run
-+ end
-+end
-+
-+prog = Program.new("localhost")
-+prog.run
-+
-+
-Index: cpp/bindings/qmf2/examples/ruby/find_agents.rb
-===================================================================
---- cpp/bindings/qmf2/examples/ruby/find_agents.rb (revision 0)
-+++ cpp/bindings/qmf2/examples/ruby/find_agents.rb (revision 0)
-@@ -0,0 +1,63 @@
-+#
-+# Licensed to the Apache Software Foundation (ASF) under one
-+# or more contributor license agreements. See the NOTICE file
-+# distributed with this work for additional information
-+# regarding copyright ownership. The ASF licenses this file
-+# to you under the Apache License, Version 2.0 (the
-+# "License"); you may not use this file except in compliance
-+# with the License. You may obtain a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing,
-+# software distributed under the License is distributed on an
-+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-+# KIND, either express or implied. See the License for the
-+# specific language governing permissions and limitations
-+# under the License.
-+#
-+
-+require 'cqpid'
-+require 'qmf2'
-+
-+class FindAgents < Qmf2::ConsoleHandler
-+
-+ def initialize(session)
-+ super(session)
-+ end
-+
-+ def agent_added(agent)
-+ puts "Agent Added: #{agent.name}"
-+ end
-+
-+ def agent_deleted(agent, reason)
-+ puts "Agent Deleted: #{agent.to_s} reason: #{reason}"
-+ end
-+
-+ def agent_restarted(agent)
-+ puts "Agent Restarted: #{agent.to_s} epoch: #{agent.epoch}"
-+ end
-+
-+ def agent_schema_updated(agent)
-+ puts "Agent with new Schemata: #{agent.to_s}"
-+ end
-+
-+ def event_raised(agent, data, timestamp, severity)
-+ puts "Event Raised time=#{timestamp} sev=#{severity} data=#{data.properties}"
-+ end
-+end
-+
-+
-+url = "localhost"
-+options = ""
-+
-+connection = Cqpid::Connection.new(url, options)
-+connection.open
-+
-+session = Qmf2::ConsoleSession.new(connection)
-+session.open
-+session.set_agent_filter("[]")
-+
-+main = FindAgents.new(session)
-+main.run
-+
-Index: cpp/bindings/qmf2/examples/ruby/agent_internal.rb
-===================================================================
---- cpp/bindings/qmf2/examples/ruby/agent_internal.rb (revision 0)
-+++ cpp/bindings/qmf2/examples/ruby/agent_internal.rb (revision 0)
-@@ -0,0 +1,77 @@
-+#
-+# Licensed to the Apache Software Foundation (ASF) under one
-+# or more contributor license agreements. See the NOTICE file
-+# distributed with this work for additional information
-+# regarding copyright ownership. The ASF licenses this file
-+# to you under the Apache License, Version 2.0 (the
-+# "License"); you may not use this file except in compliance
-+# with the License. You may obtain a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing,
-+# software distributed under the License is distributed on an
-+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-+# KIND, either express or implied. See the License for the
-+# specific language governing permissions and limitations
-+# under the License.
-+#
-+
-+require 'cqpid'
-+require 'qmf2'
-+
-+class MyAgent < Qmf2::AgentHandler
-+
-+ def initialize(session)
-+ super(session)
-+ end
-+
-+ def authorize_query(query, user_id)
-+ puts "Authorizing #{user_id}"
-+ return true
-+ end
-+
-+ def method_call(context, method_name, data_addr, args, user_id)
-+ puts "Method: #{method_name}"
-+ context._success
-+ end
-+
-+end
-+
-+
-+class Program
-+
-+ def initialize(url)
-+ @url = url
-+ @sess_options = "{allow-queries:False}"
-+ end
-+
-+ def setup_schema(agent)
-+ @cls_control = Qmf2::Schema.new(Qmf2::SCHEMA_TYPE_DATA, "org.package", "control")
-+ @cls_control.add_property(Qmf2::SchemaProperty.new("state", Qmf2::SCHEMA_DATA_STRING))
-+ agent.register_schema(@cls_control)
-+ end
-+
-+ def run
-+ connection = Cqpid::Connection.new(@url)
-+ connection.open
-+
-+ session = Qmf2::AgentSession.new(connection, @sess_options)
-+ session.set_vendor("package.org")
-+ session.set_product("internal_agent")
-+ setup_schema(session)
-+ session.open
-+
-+ control = Qmf2::Data.new(@cls_control)
-+ control.state = "OPERATIONAL"
-+ session.add_data(control)
-+
-+ main = MyAgent.new(session)
-+ main.run
-+ end
-+end
-+
-+prog = Program.new("localhost")
-+prog.run
-+
-+
-Index: cpp/bindings/qmf2/examples/cpp/agent.cpp
-===================================================================
---- cpp/bindings/qmf2/examples/cpp/agent.cpp (revision 1056407)
-+++ cpp/bindings/qmf2/examples/cpp/agent.cpp (working copy)
-@@ -48,6 +48,8 @@
- AgentSession session;
- Schema sch_exception;
- Schema sch_control;
-+ Schema sch_child;
-+ Schema sch_event;
- Data control;
- DataAddr controlAddr;
-
-@@ -60,7 +62,7 @@
- //
- // Create and open a messaging connection to a broker.
- //
-- connection = qpid::messaging::Connection(url);
-+ connection = qpid::messaging::Connection(url, "{reconnect:True}");
- connection.open();
-
- //
-@@ -114,17 +116,41 @@
- echoMethod.addArgument(SchemaProperty("map", SCHEMA_DATA_MAP, "{dir:INOUT}"));
- sch_control.addMethod(echoMethod);
-
-+ SchemaMethod eventMethod("event", "{desc:'Raise an Event'}");
-+ eventMethod.addArgument(SchemaProperty("text", SCHEMA_DATA_STRING, "{dir:IN}"));
-+ eventMethod.addArgument(SchemaProperty("severity", SCHEMA_DATA_INT, "{dir:IN}"));
-+ sch_control.addMethod(eventMethod);
-+
- SchemaMethod failMethod("fail", "{desc:'Expected to Fail'}");
- failMethod.addArgument(SchemaProperty("useString", SCHEMA_DATA_BOOL, "{dir:IN}"));
- failMethod.addArgument(SchemaProperty("stringVal", SCHEMA_DATA_STRING, "{dir:IN}"));
- failMethod.addArgument(SchemaProperty("details", SCHEMA_DATA_MAP, "{dir:IN}"));
- sch_control.addMethod(failMethod);
-
-+ SchemaMethod createMethod("create_child", "{desc:'Create Child Object'}");
-+ createMethod.addArgument(SchemaProperty("name", SCHEMA_DATA_STRING, "{dir:IN}"));
-+ createMethod.addArgument(SchemaProperty("childAddr", SCHEMA_DATA_MAP, "{dir:OUT}"));
-+ sch_control.addMethod(createMethod);
-+
- //
-+ // Declare the child class
-+ //
-+ sch_child = Schema(SCHEMA_TYPE_DATA, package, "child");
-+ sch_child.addProperty(SchemaProperty("name", SCHEMA_DATA_STRING));
-+
-+ //
-+ // Declare the event class
-+ //
-+ sch_event = Schema(SCHEMA_TYPE_EVENT, package, "event");
-+ sch_event.addProperty(SchemaProperty("text", SCHEMA_DATA_STRING));
-+
-+ //
- // Register our schemata with the agent session.
- //
- session.registerSchema(sch_exception);
- session.registerSchema(sch_control);
-+ session.registerSchema(sch_child);
-+ session.registerSchema(sch_event);
- }
-
- void ExampleAgent::populateData()
-@@ -132,7 +158,7 @@
- //
- // Create a control object and give it to the agent session to manage.
- //
-- control = Data(sch_control.getSchemaId());
-+ control = Data(sch_control);
- control.setProperty("state", "OPERATIONAL");
- control.setProperty("methodCount", 0);
- controlAddr = session.addData(control, "singleton");
-@@ -160,31 +186,55 @@
- const string& name(event.getMethodName());
- control.setProperty("methodCount", control.getProperty("methodCount").asUint32() + 1);
-
-- if (controlAddr == event.getDataAddr()) {
-- if (name == "stop") {
-- cout << "Stopping: message=" << event.getArguments()["message"] << endl;
-- session.methodSuccess(event);
-- return false;
-- }
-+ try {
-+ if (controlAddr == event.getDataAddr()) {
-+ if (name == "stop") {
-+ cout << "Stopping: message=" << event.getArguments()["message"] << endl;
-+ session.methodSuccess(event);
-+ return false;
-+ }
-
-- if (name == "echo") {
-- event.addReturnArgument("sequence", event.getArguments()["sequence"]);
-- event.addReturnArgument("map", event.getArguments()["map"]);
-- session.methodSuccess(event);
-- return true;
-- }
-+ if (name == "echo") {
-+ event.addReturnArgument("sequence", event.getArguments()["sequence"]);
-+ event.addReturnArgument("map", event.getArguments()["map"]);
-+ session.methodSuccess(event);
-+ return true;
-+ }
-
-- if (name == "fail") {
-- if (event.getArguments()["useString"])
-- session.raiseException(event, event.getArguments()["stringVal"]);
-- else {
-- Data ex(sch_exception.getSchemaId());
-- ex.setProperty("whatHappened", "It Failed");
-- ex.setProperty("howBad", 75);
-- ex.setProperty("details", event.getArguments()["details"]);
-- session.raiseException(event, ex);
-+ if (name == "event") {
-+ Data ev(sch_event);
-+ ev.setProperty("text", event.getArguments()["text"]);
-+ session.raiseEvent(ev, event.getArguments()["severity"]);
-+ session.methodSuccess(event);
-+ return true;
- }
-+
-+ if (name == "fail") {
-+ if (event.getArguments()["useString"])
-+ session.raiseException(event, event.getArguments()["stringVal"]);
-+ else {
-+ Data ex(sch_exception);
-+ ex.setProperty("whatHappened", "It Failed");
-+ ex.setProperty("howBad", 75);
-+ ex.setProperty("details", event.getArguments()["details"]);
-+ session.raiseException(event, ex);
-+ }
-+ }
-+
-+ if (name == "create_child") {
-+ const string& name(event.getArguments()["name"]);
-+ Data child(sch_child);
-+ child.setProperty("name", name);
-+ DataAddr addr(session.addData(child, name));
-+ event.addReturnArgument("childAddr", addr.asMap());
-+ session.methodSuccess(event);
-+ }
- }
-+ } catch (const exception& e) {
-+ //
-+ // Pass the exception on to the caller.
-+ //
-+ session.raiseException(event, e.what());
- }
-
- return true;
-Index: cpp/bindings/qmf2/examples/cpp/print_events.cpp
-===================================================================
---- cpp/bindings/qmf2/examples/cpp/print_events.cpp (revision 0)
-+++ cpp/bindings/qmf2/examples/cpp/print_events.cpp (revision 0)
-@@ -0,0 +1,64 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one
-+ * or more contributor license agreements. See the NOTICE file
-+ * distributed with this work for additional information
-+ * regarding copyright ownership. The ASF licenses this file
-+ * to you under the Apache License, Version 2.0 (the
-+ * "License"); you may not use this file except in compliance
-+ * with the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing,
-+ * software distributed under the License is distributed on an
-+ * "AS IS" BASIS, WITHOUT 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/Connection.h>
-+#include <qpid/messaging/Duration.h>
-+#include <qmf/ConsoleSession.h>
-+#include <qmf/ConsoleEvent.h>
-+#include <qmf/Data.h>
-+#include <qpid/types/Variant.h>
-+#include <string>
-+#include <iostream>
-+
-+using namespace std;
-+using namespace qmf;
-+using qpid::types::Variant;
-+using qpid::messaging::Duration;
-+
-+int main(int argc, char** argv)
-+{
-+ string url("localhost");
-+ string connectionOptions;
-+ string sessionOptions;
-+
-+ if (argc > 1)
-+ url = argv[1];
-+ if (argc > 2)
-+ connectionOptions = argv[2];
-+ if (argc > 3)
-+ sessionOptions = argv[3];
-+
-+ qpid::messaging::Connection connection(url, connectionOptions);
-+ connection.open();
-+
-+ ConsoleSession session(connection, sessionOptions);
-+ session.open();
-+
-+ while (true) {
-+ ConsoleEvent event;
-+ if (session.nextEvent(event)) {
-+ if (event.getType() == CONSOLE_EVENT) {
-+ const Data& data(event.getData(0));
-+ cout << "Event: timestamp=" << event.getTimestamp() << " severity=" <<
-+ event.getSeverity() << " content=" << data.getProperties() << endl;
-+ }
-+ }
-+ }
-+}
-+
-Index: cpp/bindings/qmf2/examples/cpp/Makefile.am
-===================================================================
---- cpp/bindings/qmf2/examples/cpp/Makefile.am (revision 1056407)
-+++ cpp/bindings/qmf2/examples/cpp/Makefile.am (working copy)
-@@ -21,6 +21,13 @@
-
- AM_CPPFLAGS = $(INCLUDE)
-
--noinst_PROGRAMS=agent
-+noinst_PROGRAMS=agent list_agents print_events
-+
- agent_SOURCES=agent.cpp
- agent_LDADD=$(top_builddir)/src/libqmf2.la
-+
-+list_agents_SOURCES=list_agents.cpp
-+list_agents_LDADD=$(top_builddir)/src/libqmf2.la
-+
-+print_events_SOURCES=print_events.cpp
-+print_events_LDADD=$(top_builddir)/src/libqmf2.la
-Index: cpp/bindings/qmf2/examples/cpp/list_agents.cpp
-===================================================================
---- cpp/bindings/qmf2/examples/cpp/list_agents.cpp (revision 0)
-+++ cpp/bindings/qmf2/examples/cpp/list_agents.cpp (revision 0)
-@@ -0,0 +1,73 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one
-+ * or more contributor license agreements. See the NOTICE file
-+ * distributed with this work for additional information
-+ * regarding copyright ownership. The ASF licenses this file
-+ * to you under the Apache License, Version 2.0 (the
-+ * "License"); you may not use this file except in compliance
-+ * with the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing,
-+ * software distributed under the License is distributed on an
-+ * "AS IS" BASIS, WITHOUT 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/Connection.h>
-+#include <qpid/messaging/Duration.h>
-+#include <qmf/ConsoleSession.h>
-+#include <qmf/ConsoleEvent.h>
-+#include <qmf/Agent.h>
-+#include <qpid/types/Variant.h>
-+#include <string>
-+#include <iostream>
-+
-+using namespace std;
-+using namespace qmf;
-+using qpid::types::Variant;
-+using qpid::messaging::Duration;
-+
-+int main(int argc, char** argv)
-+{
-+ string url("localhost");
-+ string connectionOptions;
-+ string sessionOptions;
-+
-+ if (argc > 1)
-+ url = argv[1];
-+ if (argc > 2)
-+ connectionOptions = argv[2];
-+ if (argc > 3)
-+ sessionOptions = argv[3];
-+
-+ qpid::messaging::Connection connection(url, connectionOptions);
-+ connection.open();
-+
-+ ConsoleSession session(connection, sessionOptions);
-+ session.open();
-+
-+ session.setAgentFilter("");
-+
-+ while (true) {
-+ ConsoleEvent event;
-+ if (session.nextEvent(event)) {
-+ if (event.getType() == CONSOLE_AGENT_ADD) {
-+ string extra;
-+ if (event.getAgent().getName() == session.getConnectedBrokerAgent().getName())
-+ extra = " [Connected Broker]";
-+ cout << "Agent Added: " << event.getAgent().getName() << extra << endl;
-+ }
-+ if (event.getType() == CONSOLE_AGENT_DEL) {
-+ if (event.getAgentDelReason() == AGENT_DEL_AGED)
-+ cout << "Agent Aged: " << event.getAgent().getName() << endl;
-+ else
-+ cout << "Agent Filtered: " << event.getAgent().getName() << endl;
-+ }
-+ }
-+ }
-+}
-+
-Index: cpp/bootstrap
-===================================================================
---- cpp/bootstrap (revision 1056407)
-+++ cpp/bootstrap (working copy)
-@@ -36,7 +36,7 @@
- \$(mgen_cmd)
- EOF
-
--automake
-+automake --add-missing
- autoconf
-
- # Optionally do the build as well.
-Index: cpp/include/qmf/Agent.h
-===================================================================
---- cpp/include/qmf/Agent.h (revision 1056407)
-+++ cpp/include/qmf/Agent.h (working copy)
-@@ -23,6 +23,7 @@
-
- #include <qmf/ImportExport.h>
- #include "qmf/Handle.h"
-+//#include "qmf/Subscription.h"
- #include "qmf/exceptions.h"
- #include "qpid/messaging/Duration.h"
- #include "qpid/types/Variant.h"
-@@ -61,6 +62,12 @@
- QMF_EXTERN uint32_t queryAsync(const Query&);
- QMF_EXTERN uint32_t queryAsync(const std::string&);
-
-+ /**
-+ * Create a subscription to this agent
-+ */
-+ //QMF_EXTERN Subscription subscribe(const Query&, const std::string& options = "");
-+ //QMF_EXTERN Subscription subscribe(const std::string&, const std::string& options = "");
-+
- QMF_EXTERN ConsoleEvent callMethod(const std::string&, const qpid::types::Variant::Map&, const DataAddr&,
- qpid::messaging::Duration timeout=qpid::messaging::Duration::MINUTE);
- QMF_EXTERN uint32_t callMethodAsync(const std::string&, const qpid::types::Variant::Map&, const DataAddr&);
-Index: cpp/include/qmf/AgentSession.h
-===================================================================
---- cpp/include/qmf/AgentSession.h (revision 1056407)
-+++ cpp/include/qmf/AgentSession.h (working copy)
-@@ -57,11 +57,20 @@
- * The options string is of the form "{key:value,key:value}". The following keys are supported:
- *
- * interval:N - Heartbeat interval in seconds [default: 60]
-- * external:{True,False} - Use external data storage (queries are pass-through) [default: False]
-+ * external:{True,False} - Use external data storage (queries and subscriptions are pass-through) [default: False]
- * allow-queries:{True,False} - If True: automatically allow all queries [default]
- * If False: generate an AUTH_QUERY event to allow per-query authorization
- * allow-methods:{True,False} - If True: automatically allow all methods [default]
- * If False: generate an AUTH_METHOD event to allow per-method authorization
-+ * max-subscriptions:N - Maximum number of concurrent subscription queries permitted [default: 64]
-+ * min-sub-interval:N - Minimum publish interval (in milliseconds) permitted for a subscription [default: 3000]
-+ * sub-lifetime:N - Lifetime (in seconds with no keepalive) for a subscription [default: 300]
-+ * public-events:{True,False} - If True: QMF events are sent to the topic exchange [default]
-+ * If False: QMF events are only sent to authorized subscribers
-+ * listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ * If False: Listen only on the routable direct address
-+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
- */
- QMF_EXTERN AgentSession(qpid::messaging::Connection&, const std::string& options="");
-
-@@ -143,7 +152,7 @@
- * authReject - Reject/forbid an authorization request.
- * raiseException - indicate failure of an operation (i.e. query or method call).
- * response - Provide data in response to a query (only for option: external:True)
-- * complete - Indicate that the response to a query is complete (external:true only)
-+ * complete - Indicate that the response to a query is complete (external:True only)
- * methodSuccess - Indicate the successful completion of a method call.
- */
- QMF_EXTERN void authAccept(AgentEvent&);
-@@ -156,8 +165,14 @@
-
- /**
- * Raise an event to be sent into the QMF network.
-+ *
-+ * @param data - A data object that contains the event contents.
-+ * @param severity - Explicit severity (from qmf/SchemaTypes.h). If omitted, the severity is set to
-+ * the default severity for the data's schema. If the data has no schema, the severity defaults
-+ * to SEV_NOTICE.
- */
-- QMF_EXTERN void raiseEvent(const Data&);
-+ QMF_EXTERN void raiseEvent(const Data& data);
-+ QMF_EXTERN void raiseEvent(const Data& data, int severity);
-
- #ifndef SWIG
- private:
-Index: cpp/include/qmf/DataAddr.h
-===================================================================
---- cpp/include/qmf/DataAddr.h (revision 1056407)
-+++ cpp/include/qmf/DataAddr.h (working copy)
-@@ -44,6 +44,7 @@
- QMF_EXTERN bool operator==(const DataAddr&);
- QMF_EXTERN bool operator<(const DataAddr&);
-
-+ QMF_EXTERN DataAddr(const qpid::types::Variant::Map&);
- QMF_EXTERN DataAddr(const std::string& name, const std::string& agentName, uint32_t agentEpoch=0);
- QMF_EXTERN const std::string& getName() const;
- QMF_EXTERN const std::string& getAgentName() const;
-Index: cpp/include/qmf/ConsoleEvent.h
-===================================================================
---- cpp/include/qmf/ConsoleEvent.h (revision 1056407)
-+++ cpp/include/qmf/ConsoleEvent.h (working copy)
-@@ -46,8 +46,10 @@
- CONSOLE_QUERY_RESPONSE = 7,
- CONSOLE_METHOD_RESPONSE = 8,
- CONSOLE_EXCEPTION = 9,
-- CONSOLE_SUBSCRIBE_UPDATE = 10,
-- CONSOLE_THREAD_FAILED = 11
-+ CONSOLE_SUBSCRIBE_ADD = 10,
-+ CONSOLE_SUBSCRIBE_UPDATE = 11,
-+ CONSOLE_SUBSCRIBE_DEL = 12,
-+ CONSOLE_THREAD_FAILED = 13
- };
-
- enum AgentDelReason {
-@@ -72,6 +74,8 @@
- QMF_EXTERN Data getData(uint32_t) const;
- QMF_EXTERN bool isFinal() const;
- QMF_EXTERN const qpid::types::Variant::Map& getArguments() const;
-+ QMF_EXTERN int getSeverity() const;
-+ QMF_EXTERN uint64_t getTimestamp() const;
-
- #ifndef SWIG
- private:
-Index: cpp/include/qmf/ConsoleSession.h
-===================================================================
---- cpp/include/qmf/ConsoleSession.h (revision 1056407)
-+++ cpp/include/qmf/ConsoleSession.h (working copy)
-@@ -24,6 +24,7 @@
- #include <qmf/ImportExport.h>
- #include "qmf/Handle.h"
- #include "qmf/Agent.h"
-+#include "qmf/Subscription.h"
- #include "qpid/messaging/Duration.h"
- #include "qpid/messaging/Connection.h"
- #include <string>
-@@ -56,6 +57,10 @@
- * domain:NAME - QMF Domain to join [default: "default"]
- * max-agent-age:N - Maximum time, in minutes, that we will tolerate not hearing from
- * an agent before deleting it [default: 5]
-+ * listen-on-direct:{True,False} - If True: Listen on legacy direct-exchange address for backward compatibility [default]
-+ * If False: Listen only on the routable direct address
-+ * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network
-+ * - If False: Operate more flexibly with regard to use of messaging facilities [default]
- */
- QMF_EXTERN ConsoleSession(qpid::messaging::Connection&, const std::string& options="");
- QMF_EXTERN void setDomain(const std::string&);
-@@ -67,6 +72,16 @@
- QMF_EXTERN Agent getAgent(uint32_t) const;
- QMF_EXTERN Agent getConnectedBrokerAgent() const;
-
-+ /**
-+ * Create a subscription that involves a subset of the known agents. The set of known agents is defined by
-+ * the session's agent-filter (see setAgentFilter). The agentFilter argument to the subscribe method is used
-+ * to further refine the set of agents. If agentFilter is the empty string (i.e. match-all) the subscription
-+ * will involve all known agents. If agentFilter is non-empty, it will be applied only to the set of known
-+ * agents. A subscription cannot be created that involves an agent not known by the session.
-+ */
-+ QMF_EXTERN Subscription subscribe(const Query&, const std::string& agentFilter = "", const std::string& options = "");
-+ QMF_EXTERN Subscription subscribe(const std::string&, const std::string& agentFilter = "", const std::string& options = "");
-+
- #ifndef SWIG
- private:
- friend class qmf::PrivateImplRef<ConsoleSession>;
-Index: cpp/include/qmf/Data.h
-===================================================================
---- cpp/include/qmf/Data.h (revision 1056407)
-+++ cpp/include/qmf/Data.h (working copy)
-@@ -34,6 +34,7 @@
- #endif
-
- class DataImpl;
-+ class Schema;
- class SchemaId;
- class DataAddr;
- class Agent;
-@@ -45,8 +46,7 @@
- QMF_EXTERN Data& operator=(const Data&);
- QMF_EXTERN ~Data();
-
-- QMF_EXTERN Data(const SchemaId&);
-- QMF_EXTERN void setSchema(const SchemaId&);
-+ QMF_EXTERN Data(const Schema&);
- QMF_EXTERN void setAddr(const DataAddr&);
- QMF_EXTERN void setProperty(const std::string&, const qpid::types::Variant&);
- QMF_EXTERN void overwriteProperties(const qpid::types::Variant::Map&);
-Index: cpp/include/qmf/Subscription.h
-===================================================================
---- cpp/include/qmf/Subscription.h (revision 0)
-+++ cpp/include/qmf/Subscription.h (revision 0)
-@@ -0,0 +1,82 @@
-+#ifndef QMF_SUBSCRIPTION_H
-+#define QMF_SUBSCRIPTION_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 <qmf/ImportExport.h>
-+#include "qmf/Handle.h"
-+#include "qpid/types/Variant.h"
-+#include <string>
-+
-+namespace qmf {
-+
-+#ifndef SWIG
-+ template <class> class PrivateImplRef;
-+#endif
-+
-+ class SubscriptionImpl;
-+ class Data;
-+
-+ class Subscription : public qmf::Handle<SubscriptionImpl> {
-+ public:
-+ QMF_EXTERN Subscription(SubscriptionImpl* impl = 0);
-+ QMF_EXTERN Subscription(const Subscription&);
-+ QMF_EXTERN Subscription& operator=(const Subscription&);
-+ QMF_EXTERN ~Subscription();
-+
-+ /**
-+ * Construction: A subscription is created by calling ConsoleSession::subscribe.
-+ */
-+
-+ /**
-+ * Cancel subscriptions to all subscribed agents. After this is called, the subscription
-+ * shall be inactive.
-+ */
-+ QMF_EXTERN void cancel();
-+
-+ /**
-+ * Check to see if this subscription is active. It is active if it has a live subscription
-+ * on at least one agent. If it is not active, there is nothing that can be done to make it
-+ * active, it can only be deleted.
-+ */
-+ QMF_EXTERN bool isActive() const;
-+
-+ /**
-+ * lock and unlock should be used to bracket a traversal of the data set. After lock is called,
-+ * the subscription will not change its set of available data objects. Between calls to getDataCount
-+ * and getData, no data objects will be added or removed. After unlock is called, the set of data
-+ * will catch up to any activity that occurred while the lock was in effect.
-+ */
-+ QMF_EXTERN void lock();
-+ QMF_EXTERN void unlock();
-+ QMF_EXTERN uint32_t getDataCount() const;
-+ QMF_EXTERN Data getData(uint32_t) const;
-+
-+#ifndef SWIG
-+ private:
-+ friend class qmf::PrivateImplRef<Subscription>;
-+ friend class SubscriptionImplAccess;
-+#endif
-+ };
-+
-+}
-+
-+#endif
-Index: cpp/include/qpid/management/Manageable.h
-===================================================================
---- cpp/include/qpid/management/Manageable.h (revision 1056407)
-+++ cpp/include/qpid/management/Manageable.h (working copy)
-@@ -63,6 +63,11 @@
- // method being called and must be down-cast to the appropriate sub class
- // before use.
- virtual status_t ManagementMethod(uint32_t methodId, Args& args, std::string& text);
-+
-+ // This optional method can be overridden to allow the agent application to
-+ // authorize method invocations. Return true iff the authenticated user identified
-+ // in userId us authorized to execute the method.
-+ virtual bool AuthorizeMethod(uint32_t methodId, Args& args, const std::string& userId);
- };
-
- inline Manageable::~Manageable(void) {}
-Index: cpp/include/qpid/management/ManagementObject.h
-===================================================================
---- cpp/include/qpid/management/ManagementObject.h (revision 1056407)
-+++ cpp/include/qpid/management/ManagementObject.h (working copy)
-@@ -175,7 +175,8 @@
- virtual void mapDecodeValues(const types::Variant::Map& map) = 0;
- virtual void doMethod(std::string& methodName,
- const types::Variant::Map& inMap,
-- types::Variant::Map& outMap) = 0;
-+ types::Variant::Map& outMap,
-+ const std::string& userId) = 0;
- QPID_COMMON_EXTERN void writeTimestamps(types::Variant::Map& map) const;
- QPID_COMMON_EXTERN void readTimestamps(const types::Variant::Map& buf);
-
-@@ -187,7 +188,7 @@
- virtual void readProperties(const std::string&) {}
- virtual void writeProperties(std::string&) const {}
- virtual void writeStatistics(std::string&, bool = false) {}
-- virtual void doMethod(std::string&, const std::string&, std::string&) {}
-+ virtual void doMethod(std::string&, const std::string&, std::string&, const std::string&) {}
-
- QPID_COMMON_EXTERN virtual void setReference(ObjectId objectId);
-
-Index: cpp/managementgen/Makefile.am
-===================================================================
---- cpp/managementgen/Makefile.am (revision 1056407)
-+++ cpp/managementgen/Makefile.am (working copy)
-@@ -31,6 +31,8 @@
- qmfgen/templates/Makefile.mk \
- qmfgen/templates/Package.cpp \
- qmfgen/templates/Package.h \
-+ qmfgen/templates/V2Package.cpp \
-+ qmfgen/templates/V2Package.h \
- qmfgen/management-types.xml
-
- EXTRA_DIST = $(nobase_qmfpython_DATA) CMakeLists.txt
-Index: cpp/managementgen/qmf-gen
-===================================================================
---- cpp/managementgen/qmf-gen (revision 1056407)
-+++ cpp/managementgen/qmf-gen (working copy)
-@@ -47,12 +47,15 @@
- help="Generate makefile for Qpid broker")
- parser.add_option("-b", "--broker-plugin", dest="brokerplugin", default=False, action="store_true",
- help="Generate code for use in a qpid broker plugin")
-+parser.add_option("-2", "--v2-style", dest="v2_style", default=False, action="store_true",
-+ help="Generate code for use with the QMFv2 Agent API")
-
- (opts, args) = parser.parse_args()
-
- typefile = opts.typefile
- templatedir = opts.templatedir
- outdir = opts.outputdir
-+v2_style = opts.v2_style
- gen = Generator(outdir, templatedir)
-
- if len(args) == 0:
-@@ -70,15 +73,20 @@
- for schemafile in args:
- package = SchemaPackage(typefile, schemafile, opts)
-
-- gen.setPackage (package.packageName)
-- gen.makeClassFiles ("Class.h", package, vars=vargs)
-- gen.makeClassFiles ("Class.cpp", package, vars=vargs)
-- gen.makeMethodFiles ("Args.h", package, vars=vargs)
-- gen.makeEventFiles ("Event.h", package, vars=vargs)
-- gen.makeEventFiles ("Event.cpp", package, vars=vargs)
-- gen.makePackageFile ("Package.h", package, vars=vargs)
-- gen.makePackageFile ("Package.cpp", package, vars=vargs)
-+ gen.setPackage(package.packageName)
-
-+ if v2_style:
-+ gen.makeV2PackageFile("V2Package.h", package, vars=vargs)
-+ gen.makeV2PackageFile("V2Package.cpp", package, vars=vargs)
-+ else:
-+ gen.makeClassFiles ("Class.h", package, vars=vargs)
-+ gen.makeClassFiles ("Class.cpp", package, vars=vargs)
-+ gen.makeMethodFiles ("Args.h", package, vars=vargs)
-+ gen.makeEventFiles ("Event.h", package, vars=vargs)
-+ gen.makeEventFiles ("Event.cpp", package, vars=vargs)
-+ gen.makePackageFile ("Package.h", package, vars=vargs)
-+ gen.makePackageFile ("Package.cpp", package, vars=vargs)
-+
- if opts.makefile != None:
- args = {}
- args["qpidbroker"] = opts.qpidbroker
-Index: cpp/managementgen/qmfgen/generate.py
-===================================================================
---- cpp/managementgen/qmfgen/generate.py (revision 1056407)
-+++ cpp/managementgen/qmfgen/generate.py (working copy)
-@@ -346,6 +346,14 @@
- path = self.packagePath + "Package" + extension
- return path
-
-+ def targetV2PackageFile (self, schema, templateFile):
-+ dot = templateFile.find(".")
-+ if dot == -1:
-+ raise ValueError ("Invalid template file name %s" % templateFile)
-+ extension = templateFile[dot:len (templateFile)]
-+ path = self.packagePath + "QmfPackage" + extension
-+ return path
-+
- def targetClassFile (self, _class, templateFile):
- dot = templateFile.find(".")
- if dot == -1:
-@@ -448,6 +456,17 @@
- stream = template.expand (schema)
- self.writeIfChanged (stream, target, force)
-
-+ def makeV2PackageFile (self, templateFile, schema, force=False, vars=None):
-+ """ Generate a QMFv2 package definition file """
-+ template = Template (self.input + templateFile, self)
-+ if vars:
-+ for arg in vars:
-+ self.setVariable(arg, vars[arg])
-+ self.templateFiles.append (templateFile)
-+ target = self.targetV2PackageFile (schema, templateFile)
-+ stream = template.expand (schema)
-+ self.writeIfChanged (stream, target, force)
-+
- def makeSingleFile (self, templateFile, target, force=False, vars=None):
- """ Generate a single expanded template """
- dot = templateFile.find(".")
-Index: cpp/managementgen/qmfgen/schema.py
-===================================================================
---- cpp/managementgen/qmfgen/schema.py (revision 1056407)
-+++ cpp/managementgen/qmfgen/schema.py (working copy)
-@@ -1228,12 +1228,12 @@
- inArgCount = inArgCount + 1
-
- if methodCount == 0:
-- stream.write ("string&, const string&, string& outStr")
-+ stream.write ("string&, const string&, string& outStr, const string&")
- else:
- if inArgCount == 0:
-- stream.write ("string& methodName, const string&, string& outStr")
-+ stream.write ("string& methodName, const string&, string& outStr, const string& userId")
- else:
-- stream.write ("string& methodName, const string& inStr, string& outStr")
-+ stream.write ("string& methodName, const string& inStr, string& outStr, const string& userId")
-
-
- def genDoMapMethodArgs (self, stream, variables):
-@@ -1248,16 +1248,16 @@
- if methodCount == 0:
- stream.write ("string&," +
- " const ::qpid::types::Variant::Map&," +
-- " ::qpid::types::Variant::Map& outMap")
-+ " ::qpid::types::Variant::Map& outMap, const string&")
- else:
- if inArgCount == 0:
- stream.write ("string& methodName," +
- " const ::qpid::types::Variant::Map&," +
-- " ::qpid::types::Variant::Map& outMap")
-+ " ::qpid::types::Variant::Map& outMap, const string& userId")
- else:
- stream.write ("string& methodName," +
- " const ::qpid::types::Variant::Map& inMap," +
-- " ::qpid::types::Variant::Map& outMap")
-+ " ::qpid::types::Variant::Map& outMap, const string& userId")
-
- def genHiLoStatResets (self, stream, variables):
- for inst in self.statistics:
-@@ -1367,8 +1367,13 @@
- arg.dir.lower () + "_" +\
- arg.name, "inBuf") + ";\n")
-
-- stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
-+ stream.write (" bool allow = coreObject->AuthorizeMethod(METHOD_" +\
-+ method.getName().upper() + ", ioArgs, userId);\n")
-+ stream.write (" if (allow)\n")
-+ stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
- method.getName().upper() + ", ioArgs, text);\n")
-+ stream.write (" else\n")
-+ stream.write (" status = Manageable::STATUS_FORBIDDEN;\n")
- stream.write (" outBuf.putLong (status);\n")
- stream.write (" outBuf.putMediumString(::qpid::management::Manageable::StatusText (status, text));\n")
- for arg in method.args:
-@@ -1402,8 +1407,13 @@
- arg.name,
- "inMap")
-
-- stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
-+ stream.write (" bool allow = coreObject->AuthorizeMethod(METHOD_" +\
-+ method.getName().upper() + ", ioArgs, userId);\n")
-+ stream.write (" if (allow)\n")
-+ stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
- method.getName().upper() + ", ioArgs, text);\n")
-+ stream.write (" else\n")
-+ stream.write (" status = Manageable::STATUS_FORBIDDEN;\n")
- stream.write (" outMap[\"_status_code\"] = (uint32_t) status;\n")
- stream.write (" outMap[\"_status_text\"] = ::qpid::management::Manageable::StatusText(status, text);\n")
- for arg in method.args:
-@@ -1473,6 +1483,9 @@
- for method in self.methods:
- method.genSchemaMap(stream, variables)
-
-+ def genName (self, stream, variables):
-+ stream.write (self.name)
-+
- def genNameCap (self, stream, variables):
- stream.write (capitalize(self.name))
-
-@@ -1637,6 +1650,9 @@
- up = "_".join(self.packageName.split("."))
- stream.write (up.upper())
-
-+ def genPackageName (self, stream, variables):
-+ stream.write(self.packageName)
-+
- def genNamePackageLower (self, stream, variables):
- stream.write (self.packageName.lower ())
-
-@@ -1660,7 +1676,140 @@
- _event.genNameCap(stream, variables)
- stream.write("::registerSelf(agent);\n")
-
-+ def genV2ClassMembers(self, stream, variables):
-+ for _class in self.classes:
-+ stream.write(" ::qmf::Schema data_%s;\n" % _class.name)
-+ for _event in self.events:
-+ stream.write(" ::qmf::Schema event_%s;\n" % _event.name)
-
-+ def genV2ClassDefines(self, stream, variables):
-+ for _class in self.classes:
-+ stream.write("\n //\n // Data: %s\n //\n" % _class.name)
-+ stream.write(" data_%s = qmf::Schema(SCHEMA_TYPE_DATA, package, \"%s\");\n" % (_class.name, _class.name))
-+
-+ for prop in _class.properties:
-+ typeName, subType = self.qmfv2Type(prop.type)
-+ access = self.qmfv2Access(prop.access)
-+ stream.write(" {\n")
-+ stream.write(" qmf::SchemaProperty prop(\"%s\", %s);\n" % (prop.name, typeName))
-+ if subType:
-+ stream.write(" prop.setSubtype(\"%s\");\n" % subType)
-+ stream.write(" prop.setAccess(%s);\n" % access)
-+ if prop.isIndex == 1:
-+ stream.write(" prop.setIndex(true);\n")
-+ if prop.isOptional == 1:
-+ stream.write(" prop.setOptional(true);\n")
-+ if prop.unit:
-+ stream.write(" prop.setUnit(\"%s\");\n" % prop.unit)
-+ if prop.desc:
-+ stream.write(" prop.setDesc(\"%s\");\n" % prop.desc)
-+ stream.write(" data_%s.addProperty(prop);\n" % _class.name)
-+ stream.write(" }\n\n")
-+
-+ for stat in _class.statistics:
-+ typeName, subType = self.qmfv2Type(stat.type)
-+ stream.write(" {\n")
-+ stream.write(" qmf::SchemaProperty prop(\"%s\", %s);\n" % (stat.name, typeName))
-+ if subType:
-+ stream.write(" prop.setSubtype(\"%s\");\n" % subType)
-+ if stat.unit:
-+ stream.write(" prop.setUnit(\"%s\");\n" % stat.unit)
-+ if stat.desc:
-+ stream.write(" prop.setDesc(\"%s\");\n" % stat.desc)
-+ stream.write(" data_%s.addProperty(prop);\n" % _class.name)
-+ stream.write(" }\n\n")
-+
-+ for method in _class.methods:
-+ stream.write(" {\n")
-+ stream.write(" qmf::SchemaMethod method(\"%s\");\n" % method.name)
-+ if method.desc:
-+ stream.write(" method.setDesc(\"%s\");\n" % method.desc)
-+
-+ for arg in method.args:
-+ typeName, subType = self.qmfv2Type(arg.type)
-+ stream.write(" {\n")
-+ stream.write(" qmf::SchemaProperty arg(\"%s\", %s);\n" % (arg.name, typeName))
-+ if subType:
-+ stream.write(" arg.setSubtype(\"%s\");\n" % subType)
-+ if stat.unit:
-+ stream.write(" arg.setUnit(\"%s\");\n" % arg.unit)
-+ if stat.desc:
-+ stream.write(" arg.setDesc(\"%s\");\n" % arg.desc)
-+ stream.write(" arg.setDirection(%s);\n" % self.qmfv2Dir(arg.dir))
-+ stream.write(" method.addArgument(arg);\n")
-+ stream.write(" }\n\n")
-+
-+ stream.write(" data_%s.addMethod(method);\n" % _class.name)
-+ stream.write(" }\n\n")
-+
-+ stream.write(" session.registerSchema(data_%s);\n" % _class.name)
-+
-+ for _event in self.events:
-+ stream.write("\n //\n // Event: %s\n //\n" % _event.name)
-+ stream.write(" event_%s = qmf::Schema(SCHEMA_TYPE_EVENT, package, \"%s\");\n" % (_event.name, _event.name))
-+ stream.write(" event_%s.setDefaultSeverity(%s);\n" % (_event.name, self.qmfv2Severity(_event.sev)))
-+ for prop in _event.args:
-+ typeName, subType = self.qmfv2Type(prop.type)
-+ stream.write(" {\n")
-+ stream.write(" qmf::SchemaProperty prop(\"%s\", %s);\n" % (prop.name, typeName))
-+ if subType:
-+ stream.write(" prop.setSubtype(\"%s\");\n" % subType)
-+ if prop.unit:
-+ stream.write(" prop.setUnit(\"%s\");\n" % prop.unit)
-+ if prop.desc:
-+ stream.write(" prop.setDesc(\"%s\");\n" % prop.desc)
-+ stream.write(" event_%s.addProperty(prop);\n" % _event.name)
-+ stream.write(" }\n\n")
-+
-+ stream.write(" session.registerSchema(event_%s);\n" % _event.name)
-+
-+
-+ def qmfv2Type(self, typecode):
-+ base = typecode.type.base
-+ if base == "REF" : return ("qmf::SCHEMA_DATA_MAP", "reference")
-+ if base == "U8" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "U16" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "U32" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "U64" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "S8" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "S16" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "S32" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "S64" : return ("qmf::SCHEMA_DATA_INT", None)
-+ if base == "BOOL" : return ("qmf::SCHEMA_DATA_BOOL", None)
-+ if base == "SSTR" : return ("qmf::SCHEMA_DATA_STRING", None)
-+ if base == "LSTR" : return ("qmf::SCHEMA_DATA_STRING", None)
-+ if base == "ABSTIME" : return ("qmf::SCHEMA_DATA_INT", "abstime")
-+ if base == "DELTATIME" : return ("qmf::SCHEMA_DATA_INT", "deltatime")
-+ if base == "FLOAT" : return ("qmf::SCHEMA_DATA_FLOAT", None)
-+ if base == "DOUBLE" : return ("qmf::SCHEMA_DATA_FLOAT", None)
-+ if base == "UUID" : return ("qmf::SCHEMA_DATA_UUID", None)
-+ if base == "FTABLE" : return ("qmf::SCHEMA_DATA_MAP", None)
-+ if base == "LIST" : return ("qmf::SCHEMA_DATA_LIST", None)
-+ raise ValueError("Unknown base type %s" % base)
-+
-+ def qmfv2Access(self, code):
-+ if code == "RC": return "qmf::ACCESS_READ_CREATE"
-+ if code == "RO": return "qmf::ACCESS_READ_ONLY"
-+ if code == "RW": return "qmf::ACCESS_READ_WRITE"
-+ raise ValueError("Unknown access type %s" % code)
-+
-+ def qmfv2Dir(self, code):
-+ if code == "I" : return "qmf::DIR_IN"
-+ if code == "O" : return "qmf::DIR_OUT"
-+ if code == "IO": return "qmf::DIR_IN_OUT"
-+ raise ValueError("Unknown direction type %s" % code)
-+
-+ def qmfv2Severity(self, code):
-+ if code == 0 : return "qmf::SEV_EMERG"
-+ if code == 1 : return "qmf::SEV_ALERT"
-+ if code == 2 : return "qmf::SEV_CRIT"
-+ if code == 3 : return "qmf::SEV_ERROR"
-+ if code == 4 : return "qmf::SEV_WARN"
-+ if code == 5 : return "qmf::SEV_NOTICE"
-+ if code == 6 : return "qmf::SEV_INFORM"
-+ if code == 7 : return "qmf::SEV_DEBUG"
-+ raise ValueError("Out of Range Severity %d" % code)
-+
- #=====================================================================================
- # Utility Functions
- #=====================================================================================
-Index: cpp/managementgen/qmfgen/templates/V2Package.cpp
-===================================================================
---- cpp/managementgen/qmfgen/templates/V2Package.cpp (revision 0)
-+++ cpp/managementgen/qmfgen/templates/V2Package.cpp (revision 0)
-@@ -0,0 +1,37 @@
-+/*MGEN:commentPrefix=//*/
-+//
-+// Licensed to the Apache Software Foundation (ASF) under one
-+// or more contributor license agreements. See the NOTICE file
-+// distributed with this work for additional information
-+// regarding copyright ownership. The ASF licenses this file
-+// to you under the Apache License, Version 2.0 (the
-+// "License"); you may not use this file except in compliance
-+// with the License. You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing,
-+// software distributed under the License is distributed on an
-+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-+// KIND, either express or implied. See the License for the
-+// specific language governing permissions and limitations
-+// under the License.
-+//
-+
-+/*MGEN:Root.Disclaimer*/
-+
-+#include "QmfPackage.h"
-+#include <qmf/Schema.h>
-+#include <qmf/SchemaProperty.h>
-+#include <qmf/SchemaMethod.h>
-+#include <string>
-+
-+using namespace std;
-+using namespace qmf::/*MGEN:Schema.Namespace*/;
-+
-+void PackageDefinition::configure(::qmf::AgentSession& session)
-+{
-+ string package("/*MGEN:Schema.PackageName*/");
-+/*MGEN:Schema.V2ClassDefines*/
-+}
-+
-Index: cpp/managementgen/qmfgen/templates/V2Package.h
-===================================================================
---- cpp/managementgen/qmfgen/templates/V2Package.h (revision 0)
-+++ cpp/managementgen/qmfgen/templates/V2Package.h (revision 0)
-@@ -0,0 +1,46 @@
-+/*MGEN:commentPrefix=//*/
-+#ifndef _QMF_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
-+#define _QMF_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
-+
-+//
-+// Licensed to the Apache Software Foundation (ASF) under one
-+// or more contributor license agreements. See the NOTICE file
-+// distributed with this work for additional information
-+// regarding copyright ownership. The ASF licenses this file
-+// to you under the Apache License, Version 2.0 (the
-+// "License"); you may not use this file except in compliance
-+// with the License. You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing,
-+// software distributed under the License is distributed on an
-+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-+// KIND, either express or implied. See the License for the
-+// specific language governing permissions and limitations
-+// under the License.
-+//
-+
-+/*MGEN:Root.Disclaimer*/
-+
-+#include <qmf/AgentSession.h>
-+#include <qmf/Schema.h>
-+#include <qmf/Data.h>
-+#include <qmf/DataAddr.h>
-+
-+namespace qmf {
-+/*MGEN:Class.OpenNamespaces*/
-+
-+class PackageDefinition
-+{
-+ public:
-+ ~PackageDefinition() {}
-+ void configure(::qmf::AgentSession& session);
-+
-+/*MGEN:Schema.V2ClassMembers*/
-+};
-+
-+}/*MGEN:Class.CloseNamespaces*/
-+
-+
-+#endif /*!_QMF_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_*/
-Index: cpp/managementgen/qmfgen/templates/Class.h
-===================================================================
---- cpp/managementgen/qmfgen/templates/Class.h (revision 1056407)
-+++ cpp/managementgen/qmfgen/templates/Class.h (working copy)
-@@ -79,7 +79,8 @@
- void mapDecodeValues(const ::qpid::types::Variant::Map& map);
- void doMethod(std::string& methodName,
- const ::qpid::types::Variant::Map& inMap,
-- ::qpid::types::Variant::Map& outMap);
-+ ::qpid::types::Variant::Map& outMap,
-+ const std::string& userId);
- std::string getKey() const;
- /*MGEN:IF(Root.GenQMFv1)*/
- uint32_t writePropertiesSize() const;
-@@ -88,7 +89,8 @@
- void writeStatistics(std::string& buf, bool skipHeaders = false);
- void doMethod(std::string& methodName,
- const std::string& inBuf,
-- std::string& outBuf);
-+ std::string& outBuf,
-+ const std::string& userId);
- /*MGEN:ENDIF*/
-
- writeSchemaCall_t getWriteSchemaCall() { return writeSchema; }
-Index: tools/src/py/qmf-tool
-===================================================================
---- tools/src/py/qmf-tool (revision 0)
-+++ tools/src/py/qmf-tool (revision 0)
-@@ -0,0 +1,684 @@
-+#!/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 os
-+import optparse
-+import sys
-+import socket
-+from cmd import Cmd
-+from shlex import split
-+from threading import Lock
-+from time import strftime, gmtime
-+from qpid.disp import Display
-+import cqpid
-+import qmf2
-+
-+class Mcli(Cmd):
-+ """ Management Command Interpreter """
-+
-+ def __init__(self, dataObject, dispObject):
-+ Cmd.__init__(self)
-+ self.dataObject = dataObject
-+ self.dispObject = dispObject
-+ self.dataObject.setCli(self)
-+ self.prompt = "qmf: "
-+
-+ def emptyline(self):
-+ pass
-+
-+ def setPromptMessage(self, p=None):
-+ if p == None:
-+ self.prompt = "qmf: "
-+ else:
-+ self.prompt = "qmf[%s]: " % p
-+
-+ def do_help(self, data):
-+ print "Management Tool for QMF"
-+ print
-+ print "Agent Commands:"
-+ print " set filter <filter-string> - Filter the list of agents"
-+ print " show filter - Show the agent filter currently in effect"
-+ print " list agents - Print a list of the known Agents"
-+ print " show agent <item-number> - Print detailed information about an Agent"
-+ print " set default <item-number> - Set the default agent for operations"
-+ print
-+ print "Schema Commands:"
-+ print " list packages - Print a list of packages supported by the default agent"
-+ print " list classes [<package-name>] - Print all classes supported byt the default agent"
-+ print " show class <class-name> [<package-name>] - Show details of a class"
-+ print
-+ print "Data Commands:"
-+ print " query <class-name> [<package-name>] [<predicate>] - Query for data from the agent"
-+ print " list - List accumulated query results"
-+ print " clear - Clear accumulated query results"
-+ print " show <id> - Show details from a data object"
-+ print " call <id> <method> [<args>] - Call a method on a data object"
-+ print
-+ print "General Commands:"
-+ print " set time-format short - Select short timestamp format (default)"
-+ print " set time-format long - Select long timestamp format"
-+ print " quit or ^D - Exit the program"
-+ print
-+
-+ def complete_set(self, text, line, begidx, endidx):
-+ """ Command completion for the 'set' command """
-+ tokens = split(line[:begidx])
-+ if len(tokens) == 1:
-+ return [i for i in ('filter ', 'default ', 'time-format ') if i.startswith(text)]
-+ if len(tokens) == 2 and tokens[1] == 'time-format':
-+ return [i for i in ('long', 'short') if i.startswith(text)]
-+ return []
-+
-+ def do_set(self, data):
-+ tokens = split(data)
-+ try:
-+ if tokens[0] == "time-format":
-+ self.dispObject.do_setTimeFormat(tokens[1])
-+ else:
-+ self.dataObject.do_set(data)
-+ except Exception, e:
-+ print "Exception in set command:", e
-+
-+ def complete_list(self, text, line, begidx, endidx):
-+ tokens = split(line[:begidx])
-+ if len(tokens) == 1:
-+ return [i for i in ('agents', 'packages', 'classes ') if i.startswith(text)]
-+ return []
-+
-+ def do_list(self, data):
-+ try:
-+ self.dataObject.do_list(data)
-+ except Exception, e:
-+ print "Exception in list command:", e
-+
-+ def complete_show(self, text, line, begidx, endidx):
-+ tokens = split(line[:begidx])
-+ if len(tokens) == 1:
-+ return [i for i in ('filter', 'agent ', 'class ') if i.startswith(text)]
-+ return []
-+
-+ def do_show(self, data):
-+ try:
-+ self.dataObject.do_show(data)
-+ except Exception, e:
-+ print "Exception in show command:", e
-+
-+ def complete_query(self, text, line, begidx, endidx):
-+ return []
-+
-+ def do_query(self, data):
-+ try:
-+ self.dataObject.do_query(data)
-+ except Exception, e:
-+ if e.message.__class__ == qmf2.Data:
-+ e = e.message.getProperties()
-+ print "Exception in query command:", e
-+
-+ def do_call(self, data):
-+ try:
-+ self.dataObject.do_call(data)
-+ except Exception, e:
-+ if e.message.__class__ == qmf2.Data:
-+ e = e.message.getProperties()
-+ print "Exception in call command:", e
-+
-+ def do_clear(self, data):
-+ try:
-+ self.dataObject.do_clear(data)
-+ except Exception, e:
-+ print "Exception in clear command:", e
-+
-+ def do_EOF(self, data):
-+ print "quit"
-+ try:
-+ self.dataObject.do_exit()
-+ except:
-+ pass
-+ return True
-+
-+ def do_quit(self, data):
-+ try:
-+ self.dataObject.do_exit()
-+ except:
-+ pass
-+ return True
-+
-+ def postcmd(self, stop, line):
-+ return stop
-+
-+ def postloop(self):
-+ print "Exiting..."
-+ self.dataObject.close()
-+
-+
-+#======================================================================================================
-+# QmfData
-+#======================================================================================================
-+class QmfData:
-+ """
-+ """
-+ def __init__(self, disp, url):
-+ self.disp = disp
-+ self.url = url
-+ self.agent_filter = '[]'
-+ self.connection = cqpid.Connection(self.url)
-+ self.connection.open()
-+ self.session = qmf2.ConsoleSession(self.connection)
-+ self.session.setAgentFilter(self.agent_filter)
-+ self.session.open()
-+ self.lock = Lock()
-+ self.cli = None
-+ self.agents = {} # Map of number => agent object
-+ self.deleted_agents = {} # Map of number => agent object
-+ self.agent_numbers = {} # Map of agent name => number
-+ self.next_number = 1
-+ self.focus_agent = None
-+ self.data_list = {}
-+ self.next_data_index = 1
-+
-+ #=======================
-+ # Methods to support CLI
-+ #=======================
-+ def setCli(self, cli):
-+ self.cli = cli
-+
-+ def close(self):
-+ try:
-+ self.session.close()
-+ self.connection.close()
-+ except:
-+ pass # we're shutting down - ignore any errors
-+
-+ def do_list(self, data):
-+ tokens = data.split()
-+ if len(tokens) == 0:
-+ self.listData()
-+ elif tokens[0] == 'agents' or tokens[0] == 'agent':
-+ self.listAgents()
-+ elif tokens[0] == 'packages' or tokens[0] == 'package':
-+ self.listPackages()
-+ elif tokens[0] == 'classes' or tokens[0] == 'class':
-+ self.listClasses(tokens[1:])
-+
-+ def do_set(self, data):
-+ tokens = split(data)
-+ if len(tokens) == 0:
-+ print "What do you want to set? type 'help' for more information."
-+ return
-+ if tokens[0] == 'filter':
-+ if len(tokens) == 2:
-+ self.setAgentFilter(tokens[1])
-+ elif tokens[0] == 'default':
-+ if len(tokens) == 2:
-+ self.updateAgents()
-+ number = int(tokens[1])
-+ self.focus_agent = self.agents[number]
-+ print "Default Agent: %s" % self.focus_agent.getName()
-+
-+ def do_show(self, data):
-+ tokens = split(data)
-+ if len(tokens) == 0:
-+ print "What do you want to show? Type 'help' for more information."
-+ return
-+
-+ if tokens[0] == 'agent':
-+ self.showAgent(tokens[1:])
-+ return
-+
-+ if tokens[0] == 'filter':
-+ print self.agent_filter
-+ return
-+
-+ if tokens[0] == "default":
-+ if not self.focus_agent:
-+ self.updateAgents()
-+ if self.focus_agent:
-+ print "Default Agent: %s" % self.focus_agent.getName()
-+ else:
-+ print "Default Agent not set"
-+ return
-+
-+ if tokens[0] == "class":
-+ self.showClass(tokens[1:])
-+ return
-+
-+ if tokens[0].isdigit():
-+ self.showData(tokens[0])
-+ return
-+
-+ print "What do you want to show? Type 'help' for more information."
-+ return
-+
-+ def do_query(self, data):
-+ tokens = split(data)
-+ if len(tokens) == 0:
-+ print "Class name not specified."
-+ return
-+ cname = tokens[0]
-+ pname = None
-+ pred = None
-+ if len(tokens) >= 2:
-+ if tokens[1][0] == '[':
-+ pred = tokens[1]
-+ else:
-+ pname = tokens[1]
-+ if len(tokens) >= 3:
-+ pred = tokens[2]
-+ query = "{class:'%s'" % cname
-+ if pname:
-+ query += ",package:'%s'" % pname
-+ if pred:
-+ query += ",where:%s" % pred
-+ query += "}"
-+ if not self.focus_agent:
-+ self.updateAgents()
-+ d_list = self.focus_agent.query(query)
-+ local_data_list = {}
-+ for d in d_list:
-+ local_data_list[self.next_data_index] = d
-+ self.next_data_index += 1
-+ rows = []
-+ for index,val in local_data_list.items():
-+ rows.append((index, val.getAddr().getName()))
-+ self.data_list[index] = val
-+ self.disp.table("Data Objects Returned: %d:" % len(d_list), ("Number", "Data Address"), rows)
-+
-+ def do_call(self, data):
-+ tokens = split(data)
-+ if len(tokens) < 2:
-+ print "Data ID and method-name not specified."
-+ return
-+ idx = int(tokens[0])
-+ methodName = tokens[1]
-+ args = []
-+ for arg in tokens[2:]:
-+ ##
-+ ## If the argument is a map, list, boolean, integer, or floating (one decimal point),
-+ ## run it through the Python evaluator so it is converted to the correct type.
-+ ##
-+ ## TODO: use a regex for this instead of this convoluted logic
-+ if arg[0] == '{' or arg[0] == '[' or arg == "True" or arg == "False" or \
-+ ((arg.count('.') < 2 and (arg.count('-') == 0 or \
-+ (arg.count('-') == 1 and arg[0] == '-')) and \
-+ arg.replace('.','').replace('-','').isdigit())):
-+ args.append(eval(arg))
-+ else:
-+ args.append(arg)
-+
-+ if not idx in self.data_list:
-+ print "Unknown data index, run 'query' to get a list of data indices"
-+ return
-+
-+ data = self.data_list[idx]
-+ data._getSchema()
-+ result = data._invoke(methodName, args, {})
-+ rows = []
-+ for k,v in result.items():
-+ rows.append((k,v))
-+ self.disp.table("Output Parameters:", ("Name", "Value"), rows)
-+
-+ def do_clear(self, data):
-+ self.data_list = {}
-+ self.next_data_index = 1
-+ print "Accumulated query results cleared"
-+
-+ def do_exit(self):
-+ pass
-+
-+ #====================
-+ # Sub-Command Methods
-+ #====================
-+ def setAgentFilter(self, filt):
-+ self.agent_filter = filt
-+ self.session.setAgentFilter(filt)
-+
-+ def updateAgents(self):
-+ agents = self.session.getAgents()
-+ number_list = []
-+ for agent in agents:
-+ if agent.getName() not in self.agent_numbers:
-+ number = self.next_number
-+ number_list.append(number)
-+ self.next_number += 1
-+ self.agent_numbers[agent.getName()] = number
-+ self.agents[number] = agent
-+ else:
-+ ## Track seen agents so we can clean out deleted ones
-+ number = self.agent_numbers[agent.getName()]
-+ number_list.append(number)
-+ if number in self.deleted_agents:
-+ self.agents[number] = self.deleted_agents.pop(number)
-+ deleted = []
-+ for number in self.agents:
-+ if number not in number_list:
-+ deleted.append(number)
-+ for number in deleted:
-+ self.deleted_agents[number] = self.agents.pop(number)
-+ if not self.focus_agent:
-+ self.focus_agent = self.session.getConnectedBrokerAgent()
-+
-+ def listAgents(self):
-+ self.updateAgents()
-+ rows = []
-+ for number in self.agents:
-+ agent = self.agents[number]
-+ if self.focus_agent and agent.getName() == self.focus_agent.getName():
-+ d = '*'
-+ else:
-+ d = ''
-+ rows.append((d, number, agent.getVendor(), agent.getProduct(), agent.getInstance(), agent.getEpoch()))
-+ self.disp.table("QMF Agents:", ("", "Id", "Vendor", "Product", "Instance", "Epoch"), rows)
-+
-+ def listPackages(self):
-+ if not self.focus_agent:
-+ raise "Default Agent not set - use 'set default'"
-+ self.focus_agent.loadSchemaInfo()
-+ packages = self.focus_agent.getPackages()
-+ for p in packages:
-+ print " %s" % p
-+
-+ def getClasses(self, tokens):
-+ if not self.focus_agent:
-+ raise "Default Agent not set - use 'set default'"
-+ return
-+ self.focus_agent.loadSchemaInfo()
-+ if len(tokens) == 1:
-+ classes = self.focus_agent.getSchemaIds(tokens[0]);
-+ else:
-+ packages = self.focus_agent.getPackages()
-+ classes = []
-+ for p in packages:
-+ classes.extend(self.focus_agent.getSchemaIds(p))
-+ return classes
-+
-+ def listClasses(self, tokens):
-+ classes = self.getClasses(tokens)
-+ rows = []
-+ for c in classes:
-+ rows.append((c.getPackageName(), c.getName(), self.classTypeName(c.getType())))
-+ self.disp.table("Classes:", ("Package", "Class", "Type"), rows)
-+
-+ def showClass(self, tokens):
-+ if len(tokens) < 1:
-+ return
-+ classes = self.getClasses([])
-+ c = tokens[0]
-+ p = None
-+ if len(tokens) == 2:
-+ p = tokens[1]
-+ schema = None
-+ sid = None
-+ for cls in classes:
-+ if c == cls.getName():
-+ if not p or p == cls.getPackageName():
-+ schema = self.focus_agent.getSchema(cls)
-+ sid = cls
-+ break
-+ if not sid:
-+ return
-+ print "Class: %s:%s (%s) - %s" % \
-+ (sid.getPackageName(), sid.getName(), self.classTypeName(sid.getType()), schema.getDesc())
-+ print " hash: %r" % sid.getHash()
-+ props = schema.getProperties()
-+ methods = schema.getMethods()
-+ rows = []
-+ for prop in props:
-+ name = prop.getName()
-+ dtype = self.typeName(prop.getType())
-+ if len(prop.getSubtype()) > 0:
-+ dtype += "(%s)" % prop.getSubtype()
-+ access = self.accessName(prop.getAccess())
-+ idx = self.yes_blank(prop.isIndex())
-+ opt = self.yes_blank(prop.isOptional())
-+ unit = prop.getUnit()
-+ desc = prop.getDesc()
-+ rows.append((name, dtype, idx, access, opt, unit, desc))
-+ self.disp.table("Properties:", ("Name", "Type", "Index", "Access", "Optional", "Unit", "Description"), rows)
-+ if len(methods) > 0:
-+ for meth in methods:
-+ name = meth.getName()
-+ desc = meth.getDesc()
-+ if len(desc) > 0:
-+ desc = " - " + desc
-+ args = meth.getArguments()
-+ rows = []
-+ for prop in args:
-+ aname = prop.getName()
-+ dtype = self.typeName(prop.getType())
-+ if len(prop.getSubtype()) > 0:
-+ dtype += "(%s)" % prop.getSubtype()
-+ unit = prop.getUnit()
-+ adesc = prop.getDesc()
-+ io = self.dirName(prop.getDirection())
-+ rows.append((aname, dtype, io, unit, adesc))
-+ print
-+ print " Method: %s%s" % (name, desc)
-+ self.disp.table("Arguments:", ("Name", "Type", "Dir", "Unit", "Description"), rows)
-+
-+ def showAgent(self, tokens):
-+ self.updateAgents()
-+ for token in tokens:
-+ number = int(token)
-+ agent = self.agents[number]
-+ print
-+ print " =================================================================================="
-+ print " Agent Id: %d" % number
-+ print " Agent Name: %s" % agent.getName()
-+ print " Epoch: %d" % agent.getEpoch()
-+ print " Attributes:"
-+ attrs = agent.getAttributes()
-+ keys = attrs.keys()
-+ keys.sort()
-+ pairs = []
-+ for key in keys:
-+ if key == '_timestamp' or key == '_schema_updated':
-+ val = disp.timestamp(attrs[key])
-+ else:
-+ val = attrs[key]
-+ pairs.append((key, val))
-+ self.printAlignedPairs(pairs)
-+ agent.loadSchemaInfo()
-+ print " Packages:"
-+ packages = agent.getPackages()
-+ for package in packages:
-+ print " %s" % package
-+
-+ def showData(self, idx):
-+ num = int(idx)
-+ if not num in self.data_list:
-+ print "Data ID not known, run 'query' first to get data"
-+ return
-+ data = self.data_list[num]
-+ props = data.getProperties()
-+ rows = []
-+ for k,v in props.items():
-+ rows.append((k, v))
-+ self.disp.table("Properties:", ("Name", "Value"), rows)
-+
-+ def listData(self):
-+ if len(self.data_list) == 0:
-+ print "No Query Results - Use the 'query' command"
-+ return
-+ rows = []
-+ for index,val in self.data_list.items():
-+ rows.append((index, val.getAgent().getName(), val.getAddr().getName()))
-+ self.disp.table("Accumulated Query Results:", ('Number', 'Agent', 'Data Address'), rows)
-+
-+ def printAlignedPairs(self, rows, indent=8):
-+ maxlen = 0
-+ for first, second in rows:
-+ if len(first) > maxlen:
-+ maxlen = len(first)
-+ maxlen += indent
-+ for first, second in rows:
-+ for i in range(maxlen - len(first)):
-+ print "",
-+ print "%s : %s" % (first, second)
-+
-+ def classTypeName(self, code):
-+ if code == qmf2.SCHEMA_TYPE_DATA: return "Data"
-+ if code == qmf2.SCHEMA_TYPE_EVENT: return "Event"
-+ return "Unknown"
-+
-+ def typeName (self, typecode):
-+ """ Convert type-codes to printable strings """
-+ if typecode == qmf2.SCHEMA_DATA_VOID: return "void"
-+ elif typecode == qmf2.SCHEMA_DATA_BOOL: return "bool"
-+ elif typecode == qmf2.SCHEMA_DATA_INT: return "int"
-+ elif typecode == qmf2.SCHEMA_DATA_FLOAT: return "float"
-+ elif typecode == qmf2.SCHEMA_DATA_STRING: return "string"
-+ elif typecode == qmf2.SCHEMA_DATA_MAP: return "map"
-+ elif typecode == qmf2.SCHEMA_DATA_LIST: return "list"
-+ elif typecode == qmf2.SCHEMA_DATA_UUID: return "uuid"
-+ else:
-+ raise ValueError ("Invalid type code: %s" % str(typecode))
-+
-+ def valueByType(self, typecode, val):
-+ if typecode == 1: return "%d" % val
-+ elif typecode == 2: return "%d" % val
-+ elif typecode == 3: return "%d" % val
-+ elif typecode == 4: return "%d" % val
-+ elif typecode == 6: return val
-+ elif typecode == 7: return val
-+ elif typecode == 8: return strftime("%c", gmtime(val / 1000000000))
-+ elif typecode == 9:
-+ if val < 0: val = 0
-+ sec = val / 1000000000
-+ min = sec / 60
-+ hour = min / 60
-+ day = hour / 24
-+ result = ""
-+ if day > 0:
-+ result = "%dd " % day
-+ if hour > 0 or result != "":
-+ result += "%dh " % (hour % 24)
-+ if min > 0 or result != "":
-+ result += "%dm " % (min % 60)
-+ result += "%ds" % (sec % 60)
-+ return result
-+
-+ elif typecode == 10: return str(self.idRegistry.displayId(val))
-+ elif typecode == 11:
-+ if val:
-+ return "True"
-+ else:
-+ return "False"
-+
-+ elif typecode == 12: return "%f" % val
-+ elif typecode == 13: return "%f" % val
-+ elif typecode == 14: return "%r" % val
-+ elif typecode == 15: return "%r" % val
-+ elif typecode == 16: return "%d" % val
-+ elif typecode == 17: return "%d" % val
-+ elif typecode == 18: return "%d" % val
-+ elif typecode == 19: return "%d" % val
-+ elif typecode == 20: return "%r" % val
-+ elif typecode == 21: return "%r" % val
-+ elif typecode == 22: return "%r" % val
-+ else:
-+ raise ValueError ("Invalid type code: %s" % str(typecode))
-+
-+ def accessName (self, code):
-+ """ Convert element access codes to printable strings """
-+ if code == qmf2.ACCESS_READ_CREATE: return "ReadCreate"
-+ elif code == qmf2.ACCESS_READ_WRITE: return "ReadWrite"
-+ elif code == qmf2.ACCESS_READ_ONLY: return "ReadOnly"
-+ else:
-+ raise ValueError ("Invalid access code: %s" % str(code))
-+
-+ def dirName(self, io):
-+ if io == qmf2.DIR_IN: return "in"
-+ elif io == qmf2.DIR_OUT: return "out"
-+ elif io == qmf2.DIR_IN_OUT: return "in_out"
-+ else:
-+ raise ValueError("Invalid direction code: %r" % io)
-+
-+ def notNone (self, text):
-+ if text == None:
-+ return ""
-+ else:
-+ return text
-+
-+ def yes_blank(self, val):
-+ if val:
-+ return "Y"
-+ return ""
-+
-+ def objectIndex(self, obj):
-+ if obj._objectId.isV2:
-+ return obj._objectId.getObject()
-+ result = ""
-+ first = True
-+ props = obj.getProperties()
-+ for prop in props:
-+ if prop[0].index:
-+ if not first:
-+ result += "."
-+ result += self.valueByType(prop[0].type, prop[1])
-+ first = None
-+ return result
-+
-+def Usage():
-+ print "Usage: qpid-tool [[<username>/<password>@]<target-host>[:<tcp-port>]]"
-+ print
-+
-+#=========================================================
-+# Main Program
-+#=========================================================
-+
-+# Get host name and port if specified on the command line
-+cargs = sys.argv[1:]
-+_host = "localhost"
-+
-+if len(cargs) > 0:
-+ _host = cargs[0]
-+
-+if _host[0] == '-':
-+ Usage()
-+ if _host != '-h' and _host != "--help":
-+ print "qpid-tool: error: no such option:", _host
-+ sys.exit(1)
-+
-+disp = Display()
-+
-+# Attempt to make a connection to the target broker
-+try:
-+ data = QmfData(disp, _host)
-+except Exception, e:
-+ if str(e).find("Exchange not found") != -1:
-+ print "Management not enabled on broker: Use '-m yes' option on broker startup."
-+ else:
-+ print "Failed: %s - %s" % (e.__class__.__name__, e)
-+ sys.exit(1)
-+
-+# Instantiate the CLI interpreter and launch it.
-+cli = Mcli(data, disp)
-+print("Management Tool for QMF")
-+try:
-+ cli.cmdloop()
-+except KeyboardInterrupt:
-+ print
-+ print "Exiting..."
-+except Exception, e:
-+ print "Failed: %s - %s" % (e.__class__.__name__, e)
-+
-+# alway attempt to cleanup broker resources
-+data.close()
-
-Property changes on: tools/src/py/qmf-tool
-___________________________________________________________________
-Added: svn:executable
- + *
-
-Index: tools/setup.py
-===================================================================
---- tools/setup.py (revision 1056407)
-+++ tools/setup.py (working copy)
-@@ -23,7 +23,8 @@
- version="0.8",
- author="Apache Qpid",
- author_email="dev at qpid.apache.org",
-- scripts=["src/py/qpid-cluster",
-+ scripts=["src/py/qmf-tool",
-+ "src/py/qpid-cluster",
- "src/py/qpid-cluster-store",
- "src/py/qpid-config",
- "src/py/qpid-printevents",
-Index: extras/qmf/src/py/qmf/console.py
-===================================================================
---- extras/qmf/src/py/qmf/console.py (revision 1056413)
-+++ extras/qmf/src/py/qmf/console.py (working copy)
-@@ -53,6 +53,10 @@
- """ Invoked when a connection is established to a broker """
- pass
-
-+ def brokerConnectionFailed(self, broker):
-+ """ Invoked when a connection to a broker fails """
-+ pass
-+
- def brokerDisconnected(self, broker):
- """ Invoked when the connection to a broker is lost """
- pass
-@@ -376,7 +380,8 @@
- dp.routing_key = self.getV2RoutingKey()
- mp = self._broker.amqpSession.message_properties()
- mp.content_type = "amqp/map"
-- mp.user_id = self._broker.authUser
-+ if self._broker.saslUser:
-+ mp.user_id = self._broker.saslUser
- mp.correlation_id = str(seq)
- mp.app_id = "qmf2"
- mp.reply_to = self._broker.amqpSession.reply_to("qmf.default.direct", self._broker.v2_direct_queue)
-@@ -1206,11 +1211,11 @@
- try:
- agentName = ah["qmf.agent"]
- values = content["_values"]
-- timestamp = values["timestamp"]
-- interval = values["heartbeat_interval"]
-+ timestamp = values["_timestamp"]
-+ interval = values["_heartbeat_interval"]
- epoch = 0
-- if 'epoch' in values:
-- epoch = values['epoch']
-+ if '_epoch' in values:
-+ epoch = values['_epoch']
- except Exception,e:
- return
-
-@@ -1239,7 +1244,7 @@
- agent.touch()
- if self.rcvHeartbeats and self.console and agent:
- self._heartbeatCallback(agent, timestamp)
-- agent.update_schema_timestamp(values.get("schema_timestamp", 0))
-+ agent.update_schema_timestamp(values.get("_schema_updated", 0))
-
-
- def _v2HandleAgentLocateRsp(self, broker, mp, ah, content):
-@@ -1488,7 +1493,8 @@
- dp.routing_key = objectId.getV2RoutingKey()
- mp = broker.amqpSession.message_properties()
- mp.content_type = "amqp/map"
-- mp.user_id = broker.authUser
-+ if broker.saslUser:
-+ mp.user_id = broker.saslUser
- mp.correlation_id = str(seq)
- mp.app_id = "qmf2"
- mp.reply_to = broker.amqpSession.reply_to("qmf.default.direct", broker.v2_direct_queue)
-@@ -2227,9 +2233,12 @@
- self.port = port
- self.mechanisms = authMechs
- self.ssl = ssl
-+ if connTimeout is not None:
-+ connTimeout = float(connTimeout)
- self.connTimeout = connTimeout
- self.authUser = authUser
- self.authPass = authPass
-+ self.saslUser = None
- self.cv = Condition()
- self.seqToAgentMap = {}
- self.error = None
-@@ -2403,6 +2412,11 @@
- self.conn.start()
- sock.settimeout(oldTimeout)
- self.conn.aborted = oldAborted
-+ uid = self.conn.user_id
-+ if uid.__class__ == tuple and len(uid) == 2:
-+ self.saslUser = uid[1]
-+ else:
-+ self.saslUser = None
-
- # prevent topic queues from filling up (and causing the agents to
- # disconnect) by discarding the oldest queued messages when full.
-@@ -2508,6 +2522,8 @@
- except Exception, e:
- self.error = "Exception during connection setup: %s - %s" % (e.__class__.__name__, e)
- self.conn_exc = e
-+ if self.session.console:
-+ self.session.console.brokerConnectionFailed(self)
- return False # connection failed
-
- def _updateAgent(self, obj):
-@@ -2571,7 +2587,7 @@
- for agent in to_notify:
- self.session._delAgentCallback(agent)
-
-- def _v2SendAgentLocate(self, predicate={}):
-+ def _v2SendAgentLocate(self, predicate=[]):
- """
- Broadcast an agent-locate request to cause all agents in the domain to tell us who they are.
- """
-@@ -2579,13 +2595,14 @@
- dp = self.amqpSession.delivery_properties()
- dp.routing_key = "console.request.agent_locate"
- mp = self.amqpSession.message_properties()
-- mp.content_type = "amqp/map"
-- mp.user_id = self.authUser
-+ mp.content_type = "amqp/list"
-+ if self.saslUser:
-+ mp.user_id = self.saslUser
- mp.app_id = "qmf2"
- mp.reply_to = self.amqpSession.reply_to("qmf.default.direct", self.v2_direct_queue)
- mp.application_headers = {'qmf.opcode':'_agent_locate_request'}
- sendCodec = Codec()
-- sendCodec.write_map(predicate)
-+ sendCodec.write_list(predicate)
- msg = Message(dp, mp, sendCodec.encoded)
- self._send(msg, "qmf.default.topic")
-
-@@ -2622,7 +2639,8 @@
- dp.ttl = ttl
- mp = self.amqpSession.message_properties()
- mp.content_type = "x-application/qmf"
-- mp.user_id = self.authUser
-+ if self.saslUser:
-+ mp.user_id = self.saslUser
- mp.reply_to = self.amqpSession.reply_to("amq.direct", self.replyName)
- return Message(dp, mp, body)
-
-@@ -2853,7 +2871,7 @@
- content = None
- else:
- content = None
--
-+
- if content != None:
- ##
- ## Directly handle agent heartbeats and agent locate responses as these are broker-scope (they are
-@@ -3366,6 +3384,9 @@
- Handle a QMFv2 data indication from the agent. Note: called from context
- of the Broker thread.
- """
-+ if content.__class__ != list:
-+ return
-+
- if mp.correlation_id:
- try:
- self.lock.acquire()
-@@ -3382,8 +3403,6 @@
- if "qmf.content" in ah:
- kind = ah["qmf.content"]
- if kind == "_data":
-- if content.__class__ != list:
-- return
- for omap in content:
- context.addV2QueryResult(omap)
- context.processV2Data()
-@@ -3391,14 +3410,15 @@
- context.signal()
-
- elif kind == "_event":
-- event = Event(self, v2Map=content)
-- if event.classKey is None or event.schema:
-- # schema optional or present
-- context.doEvent(event)
-- else:
-- # schema not optional and not present
-- if context.addPendingEvent(event):
-- self._v2SendSchemaRequest(event.classKey)
-+ for omap in content:
-+ event = Event(self, v2Map=omap)
-+ if event.classKey is None or event.schema:
-+ # schema optional or present
-+ context.doEvent(event)
-+ else:
-+ # schema not optional and not present
-+ if context.addPendingEvent(event):
-+ self._v2SendSchemaRequest(event.classKey)
-
- elif kind == "_schema_id":
- for sid in content:
-@@ -3533,7 +3553,8 @@
- dp.routing_key = self.getV2RoutingKey()
- mp = self.broker.amqpSession.message_properties()
- mp.content_type = "amqp/map"
-- mp.user_id = self.broker.authUser
-+ if self.broker.saslUser:
-+ mp.user_id = self.broker.saslUser
- mp.correlation_id = str(sequence)
- mp.app_id = "qmf2"
- mp.reply_to = self.broker.amqpSession.reply_to("qmf.default.direct", self.broker.v2_direct_queue)
-@@ -3976,6 +3997,9 @@
- def brokerConnected(self, broker):
- print "brokerConnected:", broker
-
-+ def brokerConnectionFailed(self, broker):
-+ print "brokerConnectionFailed:", broker
-+
- def brokerDisconnected(self, broker):
- print "brokerDisconnected:", broker
-
-Index: extras/qmf/src/py/qmf2/common.py
-===================================================================
---- extras/qmf/src/py/qmf2/common.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/common.py (working copy)
-@@ -1,1738 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import time
--from logging import getLogger
--from threading import Lock
--from threading import Condition
--try:
-- import hashlib
-- _md5Obj = hashlib.md5
--except ImportError:
-- import md5
-- _md5Obj = md5.new
--
--log = getLogger("qmf")
--log_query = getLogger("qmf.query")
--
--
--##
--## Constants
--##
--
--QMF_APP_ID="qmf2"
--
--
--class ContentType(object):
-- """ Values for the 'qmf.content' message header
-- """
-- schema_package = "_schema_package"
-- schema_id = "_schema_id"
-- schema_class = "_schema_class"
-- object_id = "_object_id"
-- data = "_data"
-- event = "_event"
--
--
--class OpCode(object):
-- """ Values for the 'qmf.opcode' message header.
-- """
-- noop = "_noop"
--
-- # codes sent by a console and processed by the agent
-- agent_locate_req = "_agent_locate_request"
-- subscribe_req = "_subscribe_request"
-- subscribe_cancel_ind = "_subscribe_cancel_indication"
-- subscribe_refresh_ind = "_subscribe_refresh_indication"
-- query_req = "_query_request"
-- method_req = "_method_request"
--
--
-- # codes sent by the agent to a console
-- agent_locate_rsp = "_agent_locate_response"
-- agent_heartbeat_ind = "_agent_heartbeat_indication"
-- query_rsp = "_query_response"
-- subscribe_rsp = "_subscribe_response"
-- data_ind = "_data_indication"
-- method_rsp = "_method_response"
--
--
--
--def timedelta_to_secs(td):
-- """
-- Convert a time delta to a time interval in seconds (float)
-- """
-- return td.days * 86400 + td.seconds + td.microseconds/1000000.0
--
--
--##==============================================================================
--## Async Event Model
--##==============================================================================
--
--
--class Notifier(object):
-- """
-- Virtual base class that defines a call back which alerts the application that
-- a QMF Console notification is pending.
-- """
-- def indication(self):
-- """
-- Called when one or more items are ready for the application to process.
-- This method may be called by an internal QMF library thread. Its purpose is to
-- indicate that the application should process pending work items.
-- """
-- raise Exception("The indication method must be overridden by the application!")
--
--
--
--class WorkItem(object):
-- """
-- Describes an event that has arrived for the application to process. The
-- Notifier is invoked when one or more of these WorkItems become available
-- for processing.
-- """
-- # Enumeration of the types of WorkItems produced on the Console
-- AGENT_ADDED=1
-- AGENT_DELETED=2
-- NEW_PACKAGE=3
-- NEW_CLASS=4
-- OBJECT_UPDATE=5
-- EVENT_RECEIVED=7
-- AGENT_HEARTBEAT=8
-- QUERY_COMPLETE=9
-- METHOD_RESPONSE=10
-- SUBSCRIBE_RESPONSE=11
-- SUBSCRIBE_INDICATION=12
-- RESUBSCRIBE_RESPONSE=13
-- # Enumeration of the types of WorkItems produced on the Agent
-- METHOD_CALL=1000
-- QUERY=1001
-- SUBSCRIBE_REQUEST=1002
-- RESUBSCRIBE_REQUEST=1003
-- UNSUBSCRIBE_REQUEST=1004
--
-- def __init__(self, kind, handle, _params=None):
-- """
-- Used by the Console to create a work item.
--
-- @type kind: int
-- @param kind: work item type
-- """
-- self._kind = kind
-- self._handle = handle
-- self._params = _params
--
-- def get_type(self):
-- return self._kind
--
-- def get_handle(self):
-- return self._handle
--
-- def get_params(self):
-- return self._params
--
--
--
--##==============================================================================
--## Addressing
--##==============================================================================
--
--class QmfAddress(object):
-- """
-- Address format: "qmf.<domain>.[topic|direct]/<subject>"
-- TBD
-- """
--
-- TYPE_DIRECT = "direct"
-- TYPE_TOPIC = "topic"
--
-- ADDRESS_FMT = "qmf.%s.%s/%s"
-- DEFAULT_DOMAIN = "default"
--
-- # Directly-addressed messages:
-- # agent's direct address: "qmf.<domain>.direct/<agent-name>
-- # console's direct address: "qmf.<domain>.direct/<console-name>
--
-- # Well-known Topic Addresses:
-- # "qmf.<domain>.topic/<subject>
-- # Where <subject> has the following format:
-- # "console.ind#" - indications sent from consoles
-- # "agent.ind#" - indications sent from agents
-- #
-- # The following "well known" subjects are defined:
-- #
-- # console.ind.locate[.<agent-name>] - agent discovery request
-- # agent.ind.heartbeat[.<agent-name>"] - agent heartbeats
-- # agent.ind.event[.<severity>.<agent-name>] - events
-- # agent.ind.schema[TBD] - schema updates
-- #
-- SUBJECT_AGENT_IND="agent.ind"
-- SUBJECT_AGENT_HEARTBEAT = "agent.ind.heartbeat"
-- SUBJECT_AGENT_EVENT="agent.ind.event"
-- SUBJECT_AGENT_SCHEMA="agent.ind.schema"
--
-- SUBJECT_CONSOLE_IND="console.ind"
-- SUBJECT_CONSOLE_LOCATE_AGENT="console.ind.locate"
--
--
--
-- def __init__(self, subject, domain, type_):
-- if '/' in domain or '.' in domain:
-- raise Exception("domain string must not contain '/' or '.'"
-- " characters.")
--
-- self._subject = subject
-- self._domain = domain
-- self._type = type_
--
-- def _direct(cls, subject, _domain=None):
-- if _domain is None:
-- _domain = QmfAddress.DEFAULT_DOMAIN
-- return cls(subject, _domain, type_=QmfAddress.TYPE_DIRECT)
-- direct = classmethod(_direct)
--
-- def _topic(cls, subject, _domain=None):
-- if _domain is None:
-- _domain = QmfAddress.DEFAULT_DOMAIN
-- return cls(subject, _domain, type_=QmfAddress.TYPE_TOPIC)
-- topic = classmethod(_topic)
--
-- def __from_string(cls, address):
-- node,subject = address.split('/',1)
-- qmf,domain,type_ = node.split('.',2)
--
-- if qmf != "qmf" or (type_ != QmfAddress.TYPE_DIRECT and
-- type_ != QmfAddress.TYPE_TOPIC):
-- raise ValueError("invalid QmfAddress format: %s" % address)
--
-- return cls(subject, domain, type_)
-- from_string = classmethod(__from_string)
--
-- def get_address(self):
-- """
-- Return the QMF address as a string, suitable for use with the AMQP
-- messaging API.
-- """
-- return str(self)
--
-- def get_node(self):
-- """
-- Return the 'node' portion of the address.
-- """
-- return self.get_address().split('/',1)[0]
--
-- def get_subject(self):
-- """
-- Return the 'subject' portion of the address.
-- """
-- return self.get_address().split('/',1)[1]
--
-- def get_domain(self):
-- return self._domain
--
-- def is_direct(self):
-- return self._type == self.TYPE_DIRECT
--
-- def __repr__(self):
-- return QmfAddress.ADDRESS_FMT % (self._domain, self._type, self._subject)
--
--
--
--
--class AgentName(object):
-- """
-- Uniquely identifies a management agent within the management domain.
-- """
-- _separator = ":"
--
-- def __init__(self, vendor, product, name, _str=None):
-- """
-- Note: this object must be immutable, as it is used to index into a dictionary
-- """
-- if _str is not None:
-- # construct from string representation
-- if _str.count(AgentName._separator) < 2:
-- raise TypeError("AgentName string format must be 'vendor.product.name'")
-- self._vendor, self._product, self._name = _str.split(AgentName._separator)
-- else:
-- self._vendor = vendor
-- self._product = product
-- self._name = name
--
--
-- def _from_str(cls, str_):
-- return cls(None, None, None, str_=str_)
-- from_str = classmethod(_from_str)
--
-- def vendor(self):
-- return self._vendor
--
-- def product(self):
-- return self._product
--
-- def name(self):
-- return self._name
--
-- def __cmp__(self, other):
-- if not isinstance(other, AgentName) :
-- raise TypeError("Invalid types for compare")
-- # return 1
-- me = str(self)
-- them = str(other)
--
-- if me < them:
-- return -1
-- if me > them:
-- return 1
-- return 0
--
-- def __hash__(self):
-- return (self._vendor, self._product, self._name).__hash__()
--
-- def __repr__(self):
-- return self._vendor + AgentName._separator + \
-- self._product + AgentName._separator + \
-- self._name
--
--
--
--##==============================================================================
--## DATA MODEL
--##==============================================================================
--
--
--class _mapEncoder(object):
-- """
-- virtual base class for all objects that support being converted to a map
-- """
--
-- def map_encode(self):
-- raise Exception("The map_encode method my be overridden.")
--
--
--class QmfData(_mapEncoder):
-- """
-- Base class representing management data.
--
-- Map format:
-- map["_values"] = map of unordered "name"=<value> pairs (optional)
-- map["_subtype"] = map of unordered "name"="subtype string" pairs (optional)
-- map["_tag"] = application-specific tag for this instance (optional)
-- """
-- KEY_VALUES = "_values"
-- KEY_SUBTYPES = "_subtypes"
-- KEY_TAG="_tag"
-- KEY_OBJECT_ID = "_object_id"
-- KEY_SCHEMA_ID = "_schema_id"
-- KEY_UPDATE_TS = "_update_ts"
-- KEY_CREATE_TS = "_create_ts"
-- KEY_DELETE_TS = "_delete_ts"
--
-- def __init__(self,
-- _values={}, _subtypes={}, _tag=None,
-- _object_id=None, _schema_id=None,
-- _ctime = 0, _utime = 0, _dtime = 0,
-- _map=None, _const=False):
-- """
-- @type _values: dict
-- @param _values: dictionary of initial name=value pairs for object's
-- named data.
-- @type _subtypes: dict
-- @param _subtype: dictionary of subtype strings for each of the object's
-- named data.
-- @type _desc: string
-- @param _desc: Human-readable description of this data object.
-- @type _const: boolean
-- @param _const: if true, this object cannot be modified
-- """
-- if _map is not None:
-- # construct from map
-- _tag = _map.get(self.KEY_TAG, _tag)
-- _values = _map.get(self.KEY_VALUES, _values)
-- _subtypes = _map.get(self.KEY_SUBTYPES, _subtypes)
-- _object_id = _map.get(self.KEY_OBJECT_ID, _object_id)
-- sid = _map.get(self.KEY_SCHEMA_ID)
-- if sid:
-- _schema_id = SchemaClassId.from_map(sid)
-- _ctime = long(_map.get(self.KEY_CREATE_TS, _ctime))
-- _utime = long(_map.get(self.KEY_UPDATE_TS, _utime))
-- _dtime = long(_map.get(self.KEY_DELETE_TS, _dtime))
--
-- self._values = _values.copy()
-- self._subtypes = _subtypes.copy()
-- self._tag = _tag
-- self._ctime = _ctime
-- self._utime = _utime
-- self._dtime = _dtime
-- self._const = _const
-- self._schema_id = _schema_id
-- self._object_id = str(_object_id)
--
--
-- def __create(cls, values, _subtypes={}, _tag=None, _object_id=None,
-- _schema_id=None, _const=False):
-- # timestamp in millisec since epoch UTC
-- ctime = long(time.time() * 1000)
-- return cls(_values=values, _subtypes=_subtypes, _tag=_tag,
-- _ctime=ctime, _utime=ctime,
-- _object_id=_object_id, _schema_id=_schema_id, _const=_const)
-- create = classmethod(__create)
--
-- def __from_map(cls, map_, _const=False):
-- return cls(_map=map_, _const=_const)
-- from_map = classmethod(__from_map)
--
-- def is_managed(self):
-- return self._object_id is not None
--
-- def is_described(self):
-- return self._schema_id is not None
--
-- def get_tag(self):
-- return self._tag
--
-- def get_value(self, name):
-- """
-- Will throw an AttributeError exception if the named value does not exist.
-- """
-- # meta-properties first:
-- if name == SchemaClassId.KEY_PACKAGE:
-- if self._schema_id:
-- return self._schema_id.get_package_name()
-- return None
-- if name == SchemaClassId.KEY_CLASS:
-- if self._schema_id:
-- return self._schema_id.get_class_name()
-- return None
-- if name == SchemaClassId.KEY_TYPE:
-- if self._schema_id:
-- return self._schema_id.get_type()
-- return None
-- if name == SchemaClassId.KEY_HASH:
-- if self._schema_id:
-- return self._schema_id.get_hash_string()
-- return None
-- if name == self.KEY_SCHEMA_ID:
-- return self._schema_id
-- if name == self.KEY_OBJECT_ID:
-- return self._object_id
-- if name == self.KEY_TAG:
-- return self._tag
-- if name == self.KEY_UPDATE_TS:
-- return self._utime
-- if name == self.KEY_CREATE_TS:
-- return self._ctime
-- if name == self.KEY_DELETE_TS:
-- return self._dtime
--
-- try:
-- return self._values[name]
-- except KeyError:
-- raise AttributeError("no value named '%s' in this object" % name)
--
-- def has_value(self, name):
--
-- if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS,
-- SchemaClassId.KEY_TYPE, SchemaClassId.KEY_HASH,
-- self.KEY_SCHEMA_ID]:
-- return self._schema_id is not None
-- if name in [self.KEY_UPDATE_TS, self.KEY_CREATE_TS,
-- self.KEY_DELETE_TS]:
-- return True
-- if name == self.KEY_OBJECT_ID:
-- return self._object_id is not None
-- if name == self.KEY_TAG:
-- return self._tag is not None
--
-- return name in self._values
--
-- def set_value(self, _name, _value, _subType=None):
-- if self._const:
-- raise Exception("cannot modify constant data object")
-- self._values[_name] = _value
-- if _subType:
-- self._subtypes[_name] = _subType
-- return _value
--
-- def get_subtype(self, _name):
-- return self._subtypes.get(_name)
--
-- def get_schema_class_id(self):
-- """
-- @rtype: class SchemaClassId
-- @returns: the identifier of the Schema that describes the structure of the data.
-- """
-- return self._schema_id
--
-- def get_object_id(self):
-- """
-- Get the instance's identification string.
-- @rtype: str
-- @returns: the identification string, or None if not assigned and id.
-- """
-- return self._object_id
--
-- def map_encode(self):
-- _map = {}
-- if self._tag:
-- _map[self.KEY_TAG] = self._tag
--
-- # data in the _values map may require recursive map_encode()
-- vmap = {}
-- for name,val in self._values.iteritems():
-- if isinstance(val, _mapEncoder):
-- vmap[name] = val.map_encode()
-- else:
-- # otherwise, just toss in the native type...
-- vmap[name] = val
--
-- _map[self.KEY_VALUES] = vmap
-- # subtypes are never complex, so safe to just copy
-- _map[self.KEY_SUBTYPES] = self._subtypes.copy()
-- if self._object_id:
-- _map[self.KEY_OBJECT_ID] = self._object_id
-- if self._schema_id:
-- _map[self.KEY_SCHEMA_ID] = self._schema_id.map_encode()
-- return _map
--
-- def __repr__(self):
-- return "QmfData=<<" + str(self.map_encode()) + ">>"
--
--
-- def __setattr__(self, _name, _value):
-- # ignore private data members
-- if _name[0] == '_':
-- return super(QmfData, self).__setattr__(_name, _value)
-- if _name in self._values:
-- return self.set_value(_name, _value)
-- return super(QmfData, self).__setattr__(_name, _value)
--
-- def __getattr__(self, _name):
-- if _name != "_values" and _name in self._values:
-- return self._values[_name]
-- raise AttributeError("no value named '%s' in this object" % _name)
--
-- def __getitem__(self, _name):
-- return self.__getattr__(_name)
--
-- def __setitem__(self, _name, _value):
-- return self.__setattr__(_name, _value)
--
--
--
--class QmfEvent(QmfData):
-- """
-- A QMF Event is a type of described data that is not managed. Events are
-- notifications that are sent by Agents. An event notifies a Console of a
-- change in some aspect of the system under managment.
-- """
-- KEY_TIMESTAMP = "_timestamp"
-- KEY_SEVERITY = "_severity"
--
-- SEV_EMERG = "emerg"
-- SEV_ALERT = "alert"
-- SEV_CRIT = "crit"
-- SEV_ERR = "err"
-- SEV_WARNING = "warning"
-- SEV_NOTICE = "notice"
-- SEV_INFO = "info"
-- SEV_DEBUG = "debug"
--
-- def __init__(self, _timestamp=None, _sev=SEV_NOTICE, _values={},
-- _subtypes={}, _tag=None,
-- _map=None,
-- _schema_id=None, _const=True):
-- """
-- @type _map: dict
-- @param _map: if not None, construct instance from map representation.
-- @type _timestamp: int
-- @param _timestamp: moment in time when event occurred, expressed
-- as milliseconds since Midnight, Jan 1, 1970 UTC.
-- @type _agentId: class AgentId
-- @param _agentId: Identifies agent issuing this event.
-- @type _schema: class Schema
-- @param _schema:
-- @type _schemaId: class SchemaClassId (event)
-- @param _schemaId: identi
-- """
--
-- if _map is not None:
-- # construct from map
-- super(QmfEvent, self).__init__(_map=_map, _const=_const,
-- _object_id="_event")
-- _timestamp = _map.get(self.KEY_TIMESTAMP, _timestamp)
-- _sev = _map.get(self.KEY_SEVERITY, _sev)
-- else:
-- super(QmfEvent, self).__init__(_object_id="_event",
-- _values=_values,
-- _subtypes=_subtypes, _tag=_tag,
-- _schema_id=_schema_id,
-- _const=_const)
-- if _timestamp is None:
-- raise TypeError("QmfEvent: a valid timestamp is required.")
--
-- try:
-- self._timestamp = long(_timestamp)
-- except:
-- raise TypeError("QmfEvent: a numeric timestamp is required.")
--
-- self._severity = _sev
--
-- def _create(cls, timestamp, severity, values,
-- _subtypes={}, _tag=None, _schema_id=None, _const=False):
-- return cls(_timestamp=timestamp, _sev=severity, _values=values,
-- _subtypes=_subtypes, _tag=_tag, _schema_id=_schema_id, _const=_const)
-- create = classmethod(_create)
--
-- def _from_map(cls, map_, _const=False):
-- return cls(_map=map_, _const=_const)
-- from_map = classmethod(_from_map)
--
-- def get_timestamp(self):
-- return self._timestamp
--
-- def get_severity(self):
-- return self._severity
--
-- def map_encode(self):
-- _map = super(QmfEvent, self).map_encode()
-- _map[self.KEY_TIMESTAMP] = self._timestamp
-- _map[self.KEY_SEVERITY] = self._severity
-- return _map
--
--
--
--##==============================================================================
--## QUERY
--##==============================================================================
--
--
--
--class QmfQuery(_mapEncoder):
--
-- KEY_TARGET="what"
-- KEY_PREDICATE="where"
-- KEY_ID="id"
--
-- ### Query Types
-- ID=1
-- PREDICATE=2
--
-- #### Query Targets ####
-- TARGET_PACKAGES="schema_package"
-- # (returns just package names)
-- # allowed predicate key(s):
-- #
-- # SchemaClassId.KEY_PACKAGE
--
-- TARGET_SCHEMA_ID="schema_id"
-- TARGET_SCHEMA="schema"
-- # allowed id: value:
-- # SchemaClassId
-- #
-- # allowed predicate key(s):
-- # SchemaClassId.KEY_PACKAGE
-- # SchemaClassId.KEY_CLASS
-- # SchemaClassId.KEY_TYPE
-- # SchemaClassId.KEY_HASH
-- # SchemaClass.KEY_SCHEMA_ID
-- # name of property (exist test only)
-- # name of method (exist test only)
--
-- TARGET_AGENT="agent"
-- # allowed id: value:
-- # string name of agent
-- # allowed predicate keys(s):
-- #
-- KEY_AGENT_NAME="_name"
--
-- TARGET_OBJECT_ID="object_id"
-- TARGET_OBJECT="object"
-- # If object is described by a schema, the value of the target map must
-- # include a "_schema_id": {map encoded schema id} value.
-- #
-- # allowed id: value:
-- # object_id string
-- #
-- # allowed predicate keys(s):
-- #
-- # QmfData.KEY_OBJECT_ID
-- # QmfData.KEY_UPDATE_TS
-- # QmfData.KEY_CREATE_TS
-- # QmfData.KEY_DELETE_TS
-- # <name of data value>
--
-- # supported predicate operators
--
-- # evaluation operators
-- QUOTE="quote"
-- UNQUOTE="unquote"
-- # boolean operators
-- EQ="eq"
-- NE="ne"
-- LT="lt"
-- LE="le"
-- GT="gt"
-- GE="ge"
-- RE_MATCH="re_match"
-- EXISTS="exists"
-- TRUE="true"
-- FALSE="false"
-- # logic operators
-- AND="and"
-- OR="or"
-- NOT="not"
--
-- _valid_targets = [TARGET_PACKAGES, TARGET_OBJECT_ID, TARGET_SCHEMA, TARGET_SCHEMA_ID,
-- TARGET_OBJECT, TARGET_AGENT]
-- _valid_bool_ops = [EQ, NE, LT, GT, LE, GE, EXISTS, RE_MATCH, TRUE, FALSE]
-- _valid_logic_ops = [AND, OR, NOT]
-- _valid_eval_ops = [QUOTE, UNQUOTE]
--
-- def __init__(self, _target=None, _target_params=None, _predicate=None,
-- _id=None, _map=None):
-- """
-- """
-- if _map is not None:
-- target_map = _map.get(self.KEY_TARGET)
-- if not target_map:
-- raise TypeError("QmfQuery requires a target map")
--
-- _target = None
-- for key in target_map.iterkeys():
-- if key in self._valid_targets:
-- _target = key
-- break
-- if _target is None:
-- raise TypeError("Invalid QmfQuery target: '%s'" %
-- str(target_map))
--
-- # convert target params from map format
-- _target_params = target_map.get(_target)
-- if _target_params:
-- if not isinstance(_target_params, type({})):
-- raise TypeError("target params must be a map: '%s'" %
-- str(_target_params))
-- t_params = {}
-- for name,value in _target_params.iteritems():
-- if name == QmfData.KEY_SCHEMA_ID:
-- t_params[name] = SchemaClassId.from_map(value)
-- else:
-- t_params[name] = value
-- _target_params = t_params
--
-- _id = _map.get(self.KEY_ID)
-- if _id is not None:
-- # Convert identifier to native type if necessary
-- if _target == self.TARGET_SCHEMA:
-- _id = SchemaClassId.from_map(_id)
-- else:
-- _predicate = _map.get(self.KEY_PREDICATE, _predicate)
--
-- self._target = _target
-- if not self._target:
-- raise TypeError("QmfQuery requires a target value")
-- self._target_params = _target_params
-- self._predicate = _predicate
-- self._id = _id
--
-- # constructors
-- def _create_wildcard(cls, target, _target_params=None):
-- return cls(_target=target, _target_params=_target_params)
-- create_wildcard = classmethod(_create_wildcard)
--
-- def _create_wildcard_object_id(cls, schema_id):
-- """
-- Create a wildcard to match all object_ids for a given schema.
-- """
-- if not isinstance(schema_id, SchemaClassId):
-- raise TypeError("class SchemaClassId expected")
-- params = {QmfData.KEY_SCHEMA_ID: schema_id}
-- return cls(_target=QmfQuery.TARGET_OBJECT_ID,
-- _target_params=params)
-- create_wildcard_object_id = classmethod(_create_wildcard_object_id)
--
-- def _create_wildcard_object(cls, schema_id):
-- """
-- Create a wildcard to match all objects for a given schema.
-- """
-- if not isinstance(schema_id, SchemaClassId):
-- raise TypeError("class SchemaClassId expected")
-- params = {QmfData.KEY_SCHEMA_ID: schema_id}
-- return cls(_target=QmfQuery.TARGET_OBJECT,
-- _target_params=params)
-- create_wildcard_object = classmethod(_create_wildcard_object)
--
-- def _create_predicate(cls, target, predicate, _target_params=None):
-- return cls(_target=target, _target_params=_target_params,
-- _predicate=predicate)
-- create_predicate = classmethod(_create_predicate)
--
-- def _create_id(cls, target, ident, _target_params=None):
-- return cls(_target=target, _target_params=_target_params, _id=ident)
-- create_id = classmethod(_create_id)
--
-- def _create_id_object(cls, object_id, _schema_id=None):
-- """
-- Create a ID Query for an object (schema optional).
-- """
-- if _schema_id is not None:
-- if not isinstance(_schema_id, SchemaClassId):
-- raise TypeError("class SchemaClassId expected")
-- params = {QmfData.KEY_SCHEMA_ID: _schema_id}
-- else:
-- params = None
-- return cls(_target=QmfQuery.TARGET_OBJECT,
-- _id=object_id,
-- _target_params=params)
-- create_id_object = classmethod(_create_id_object)
--
-- def _create_id_object_id(cls, object_id, _schema_id=None):
-- """
-- Create a ID Query for object_ids (schema optional).
-- """
-- if _schema_id is not None:
-- if not isinstance(_schema_id, SchemaClassId):
-- raise TypeError("class SchemaClassId expected")
-- params = {QmfData.KEY_SCHEMA_ID: _schema_id}
-- else:
-- params = None
-- return cls(_target=QmfQuery.TARGET_OBJECT_ID,
-- _id=object_id,
-- _target_params=params)
-- create_id_object_id = classmethod(_create_id_object_id)
--
-- def _from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(_from_map)
-- # end constructors
--
-- def get_target(self):
-- return self._target
--
-- def get_target_param(self):
-- return self._target_params
--
-- def get_selector(self):
-- if self._id:
-- return QmfQuery.ID
-- else:
-- return QmfQuery.PREDICATE
--
-- def get_id(self):
-- return self._id
--
-- def get_predicate(self):
-- """
-- """
-- return self._predicate
--
-- def evaluate(self, qmfData):
-- """
-- """
-- if self._id:
-- if self._target == self.TARGET_SCHEMA:
-- return (qmfData.has_value(qmfData.KEY_SCHEMA_ID) and
-- qmfData.get_value(qmfData.KEY_SCHEMA_ID) == self._id)
-- elif self._target == self.TARGET_OBJECT:
-- return (qmfData.has_value(qmfData.KEY_OBJECT_ID) and
-- qmfData.get_value(qmfData.KEY_OBJECT_ID) == self._id)
-- elif self._target == self.TARGET_AGENT:
-- return (qmfData.has_value(self.KEY_AGENT_NAME) and
-- qmfData.get_value(self.KEY_AGENT_NAME) == self._id)
--
-- raise Exception("Unsupported query target '%s'" % str(self._target))
--
-- if self._predicate:
-- return self._eval_pred(self._predicate, qmfData)
-- # no predicate and no id - always match
-- return True
--
-- def map_encode(self):
-- t_params = {}
-- if self._target_params:
-- for name,value in self._target_params.iteritems():
-- if isinstance(value, _mapEncoder):
-- t_params[name] = value.map_encode()
-- else:
-- t_params[name] = value
-- if t_params:
-- _map = {self.KEY_TARGET: {self._target: t_params}}
-- else:
-- _map = {self.KEY_TARGET: {self._target: None}}
--
-- if self._id is not None:
-- if isinstance(self._id, _mapEncoder):
-- _map[self.KEY_ID] = self._id.map_encode()
-- else:
-- _map[self.KEY_ID] = self._id
-- elif self._predicate is not None:
-- _map[self.KEY_PREDICATE] = self._predicate
-- return _map
--
-- def _eval_pred(self, pred, qmfData):
-- """
-- Evaluate the predicate expression against a QmfData object.
-- """
-- if not isinstance(qmfData, QmfData):
-- raise TypeError("Query expects to evaluate QmfData types.")
--
-- if not isinstance(pred, type([])):
-- log.warning("Invalid type for predicate expression: '%s'" % str(pred))
-- return False
--
-- # empty predicate - match all???
-- if len(pred) == 0:
-- return True
--
-- oper = pred[0]
-- if oper == QmfQuery.TRUE:
-- log_query.debug("query evaluate TRUE")
-- return True
--
-- if oper == QmfQuery.FALSE:
-- log_query.debug("query evaluate FALSE")
-- return False
--
-- if oper == QmfQuery.AND:
-- log_query.debug("query evaluate AND: '%s'" % str(pred))
-- for exp in pred[1:]:
-- if not self._eval_pred(exp, qmfData):
-- log_query.debug("---> False")
-- return False
-- log_query.debug("---> True")
-- return True
--
-- if oper == QmfQuery.OR:
-- log_query.debug("query evaluate OR: [%s]" % str(pred))
-- for exp in pred[1:]:
-- if self._eval_pred(exp, qmfData):
-- log_query.debug("---> True")
-- return True
-- log_query.debug("---> False")
-- return False
--
-- if oper == QmfQuery.NOT:
-- log_query.debug("query evaluate NOT: [%s]" % str(pred))
-- for exp in pred[1:]:
-- if self._eval_pred(exp, qmfData):
-- log_query.debug("---> False")
-- return False
-- log_query.debug("---> True")
-- return True
--
-- if oper == QmfQuery.EXISTS:
-- if len(pred) != 2:
-- log.warning("Malformed query: 'exists' operator"
-- " - bad arguments '%s'" % str(pred))
-- return False
-- ### Q: Should we assume "quote", or should it be explicit?
-- ### "foo" or ["quote" "foo"]
-- ### my guess is "explicit"
-- log_query.debug("query evaluate EXISTS: [%s]" % str(pred))
-- try:
-- arg = self._fetch_pred_arg(pred[1], qmfData)
-- except AttributeError:
-- log.warning("query parameter not found: '%s'" % str(pred))
-- return False
-- v = qmfData.has_value(arg)
-- log_query.debug("---> %s" % str(v))
-- return v
--
-- # binary operators
-- if oper in [QmfQuery.EQ, QmfQuery.NE, QmfQuery.LT,
-- QmfQuery.LE, QmfQuery.GT, QmfQuery.GE,
-- QmfQuery.RE_MATCH]:
-- if len(pred) != 3:
-- log.warning("Malformed query: '%s' operator"
-- " - requires 2 arguments '%s'" %
-- (oper, str(pred)))
-- return False
-- # @todo: support regular expression match
-- log_query.debug("query evaluate binary op: [%s]" % str(pred))
-- try:
-- arg1 = self._fetch_pred_arg(pred[1], qmfData)
-- arg2 = self._fetch_pred_arg(pred[2], qmfData)
-- except AttributeError:
-- log.warning("query parameter not found: '%s'" % str(pred))
-- return False
-- log_query.debug("query evaluate %s: %s, %s" % (oper, str(arg1), str(arg2)))
-- v = False
-- try:
-- if oper == QmfQuery.EQ: v = arg1 == arg2
-- elif oper == QmfQuery.NE: v = arg1 != arg2
-- elif oper == QmfQuery.LT: v = arg1 < arg2
-- elif oper == QmfQuery.LE: v = arg1 <= arg2
-- elif oper == QmfQuery.GT: v = arg1 > arg2
-- elif oper == QmfQuery.GE: v = arg1 >= arg2
-- except TypeError:
-- log.warning("query comparison failed: '%s'" % str(pred))
-- log_query.debug("---> %s" % str(v))
-- return v
--
-- log.warning("Unrecognized query operator: [%s]" % str(pred[0]))
-- return False
--
-- def _fetch_pred_arg(self, arg, qmfData):
-- """
-- Determine the value of a predicate argument by evaluating quoted
-- arguments.
-- """
-- if isinstance(arg, basestring):
-- return qmfData.get_value(arg)
-- if isinstance(arg, type([])) and len(arg) == 2:
-- if arg[0] == QmfQuery.QUOTE:
-- return arg[1]
-- if arg[0] == QmfQuery.UNQUOTE:
-- return qmfData.get_value(arg[1])
-- return arg
--
-- def __repr__(self):
-- return "QmfQuery=<<" + str(self.map_encode()) + ">>"
--
--
--
--
--
--##==============================================================================
--## SCHEMA
--##==============================================================================
--
--
--# Argument typecodes, access, and direction qualifiers
--
--class qmfTypes(object):
-- TYPE_UINT8 = 1
-- TYPE_UINT16 = 2
-- TYPE_UINT32 = 3
-- TYPE_UINT64 = 4
--
-- TYPE_SSTR = 6
-- TYPE_LSTR = 7
--
-- TYPE_ABSTIME = 8
-- TYPE_DELTATIME = 9
--
-- TYPE_REF = 10
--
-- TYPE_BOOL = 11
--
-- TYPE_FLOAT = 12
-- TYPE_DOUBLE = 13
--
-- TYPE_UUID = 14
--
-- TYPE_MAP = 15
--
-- TYPE_INT8 = 16
-- TYPE_INT16 = 17
-- TYPE_INT32 = 18
-- TYPE_INT64 = 19
--
-- TYPE_OBJECT = 20
--
-- TYPE_LIST = 21
--
-- TYPE_ARRAY = 22
--
--# New subtypes:
--# integer (for time, duration, signed/unsigned)
--# double (float)
--# bool
--# string
--# map (ref, qmfdata)
--# list
--# uuid
--
--
--class qmfAccess(object):
-- READ_CREATE = 1
-- READ_WRITE = 2
-- READ_ONLY = 3
--
--
--class qmfDirection(object):
-- DIR_IN = 1
-- DIR_OUT = 2
-- DIR_IN_OUT = 3
--
--
--
--def _to_bool( param ):
-- """
-- Helper routine to convert human-readable representations of
-- boolean values to python bool types.
-- """
-- _false_strings = ["off", "no", "false", "0", "none"]
-- _true_strings = ["on", "yes", "true", "1"]
-- if type(param) == str:
-- lparam = param.lower()
-- if lparam in _false_strings:
-- return False
-- if lparam in _true_strings:
-- return True
-- raise TypeError("unrecognized boolean string: '%s'" % param )
-- else:
-- return bool(param)
--
--
--
--class SchemaClassId(_mapEncoder):
-- """
-- Unique identifier for an instance of a SchemaClass.
--
-- Map format:
-- map["package_name"] = str, name of associated package
-- map["class_name"] = str, name of associated class
-- map["type"] = str, "data"|"event", default: "data"
-- optional:
-- map["hash_str"] = str, hash value in standard format or None
-- if hash is unknown.
-- """
-- KEY_PACKAGE="_package_name"
-- KEY_CLASS="_class_name"
-- KEY_TYPE="_type"
-- KEY_HASH="_hash_str"
--
-- TYPE_DATA = "_data"
-- TYPE_EVENT = "_event"
--
-- _valid_types=[TYPE_DATA, TYPE_EVENT]
-- _schemaHashStrFormat = "%08x-%08x-%08x-%08x"
-- _schemaHashStrDefault = "00000000-00000000-00000000-00000000"
--
-- def __init__(self, pname=None, cname=None, stype=TYPE_DATA, hstr=None,
-- _map=None):
-- """
-- @type pname: str
-- @param pname: the name of the class's package
-- @type cname: str
-- @param cname: name of the class
-- @type stype: str
-- @param stype: schema type [data | event]
-- @type hstr: str
-- @param hstr: the hash value in '%08x-%08x-%08x-%08x' format
-- """
-- if _map is not None:
-- # construct from map
-- pname = _map.get(self.KEY_PACKAGE, pname)
-- cname = _map.get(self.KEY_CLASS, cname)
-- stype = _map.get(self.KEY_TYPE, stype)
-- hstr = _map.get(self.KEY_HASH, hstr)
--
-- self._pname = pname
-- self._cname = cname
-- if stype not in SchemaClassId._valid_types:
-- raise TypeError("Invalid SchemaClassId type: '%s'" % stype)
-- self._type = stype
-- self._hstr = hstr
-- if self._hstr:
-- try:
-- # sanity check the format of the hash string
-- hexValues = hstr.split("-")
-- h0 = int(hexValues[0], 16)
-- h1 = int(hexValues[1], 16)
-- h2 = int(hexValues[2], 16)
-- h3 = int(hexValues[3], 16)
-- except:
-- raise Exception("Invalid SchemaClassId format: bad hash string: '%s':"
-- % hstr)
-- # constructor
-- def _create(cls, pname, cname, stype=TYPE_DATA, hstr=None):
-- return cls(pname=pname, cname=cname, stype=stype, hstr=hstr)
-- create = classmethod(_create)
--
-- # map constructor
-- def _from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(_from_map)
--
-- def get_package_name(self):
-- """
-- Access the package name in the SchemaClassId.
--
-- @rtype: str
-- """
-- return self._pname
--
--
-- def get_class_name(self):
-- """
-- Access the class name in the SchemaClassId
--
-- @rtype: str
-- """
-- return self._cname
--
--
-- def get_hash_string(self):
-- """
-- Access the schema's hash as a string value
--
-- @rtype: str
-- """
-- return self._hstr
--
--
-- def get_type(self):
-- """
-- Returns the type code associated with this Schema
--
-- @rtype: str
-- """
-- return self._type
--
-- def map_encode(self):
-- _map = {}
-- _map[self.KEY_PACKAGE] = self._pname
-- _map[self.KEY_CLASS] = self._cname
-- _map[self.KEY_TYPE] = self._type
-- if self._hstr: _map[self.KEY_HASH] = self._hstr
-- return _map
--
-- def __repr__(self):
-- hstr = self.get_hash_string()
-- if not hstr:
-- hstr = SchemaClassId._schemaHashStrDefault
-- return self._pname + ":" + self._cname + ":" + self._type + "(" + hstr + ")"
--
--
-- def __cmp__(self, other):
-- if isinstance(other, dict):
-- other = SchemaClassId.from_map(other)
-- if not isinstance(other, SchemaClassId):
-- raise TypeError("Invalid types for compare")
-- # return 1
-- me = str(self)
-- them = str(other)
-- if me < them:
-- return -1
-- if me > them:
-- return 1
-- return 0
--
--
-- def __hash__(self):
-- return (self._pname, self._cname, self._hstr).__hash__()
--
--
--
--class SchemaProperty(_mapEncoder):
-- """
-- Describes the structure of a Property data object.
-- Map format:
-- map["amqp_type"] = int, AMQP type code indicating property's data type
--
-- optional:
-- map["access"] = str, access allowed to this property, default "RO"
-- map["index"] = bool, True if this property is an index value, default False
-- map["optional"] = bool, True if this property is optional, default False
-- map["unit"] = str, describes units used
-- map["min"] = int, minimum allowed value
-- map["max"] = int, maximun allowed value
-- map["maxlen"] = int, if string type, this is the maximum length in bytes
-- required to represent the longest instance of this string.
-- map["desc"] = str, human-readable description of this argument
-- map["reference"] = str, ???
-- map["parent_ref"] = bool, true if this property references an object in
-- which this object is in a child-parent relationship. Default False
-- map["continuous"] = bool, true if the value potentially changes too fast to
-- be directly monitorable. Example: fast changing statistic or random
-- number. Subscriptions to objects containing continuous data will publish
-- only on an interval basis, rather than every time the data changes. Default
-- False.
-- """
-- __hash__ = None
-- _access_strings = ["RO","RW","RC"]
-- _dir_strings = ["I", "O", "IO"]
-- def __init__(self, _type_code=None, _map=None, kwargs={}):
-- if _map is not None:
-- # construct from map
-- _type_code = _map.get("amqp_type", _type_code)
-- kwargs = _map
-- if not _type_code:
-- raise TypeError("SchemaProperty: amqp_type is a mandatory"
-- " parameter")
--
-- self._type = _type_code
-- self._access = "RO"
-- self._isIndex = False
-- self._isOptional = False
-- self._unit = None
-- self._min = None
-- self._max = None
-- self._maxlen = None
-- self._desc = None
-- self._reference = None
-- self._isParentRef = False
-- self._dir = None
-- self._default = None
-- self._is_continuous = False
--
-- for key, value in kwargs.items():
-- if key == "access":
-- value = str(value).upper()
-- if value not in self._access_strings:
-- raise TypeError("invalid value for access parameter: '%s':" % value )
-- self._access = value
-- elif key == "index" : self._isIndex = _to_bool(value)
-- elif key == "optional": self._isOptional = _to_bool(value)
-- elif key == "unit" : self._unit = value
-- elif key == "min" : self._min = value
-- elif key == "max" : self._max = value
-- elif key == "maxlen" : self._maxlen = value
-- elif key == "desc" : self._desc = value
-- elif key == "reference" : self._reference = value
-- elif key == "parent_ref" : self._isParentRef = _to_bool(value)
-- elif key == "parent_ref" : self._isParentRef = _to_bool(value)
-- elif key == "continuous" : self._is_continuous = _to_bool(value)
-- elif key == "dir":
-- value = str(value).upper()
-- if value not in self._dir_strings:
-- raise TypeError("invalid value for direction parameter: '%s'" % value)
-- self._dir = value
-- elif key == "default" : self._default = value
--
-- # constructor
-- def _create(cls, type_code, **kwargs):
-- return cls(_type_code=type_code, kwargs=kwargs)
-- create = classmethod(_create)
--
-- # map constructor
-- def _from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(_from_map)
--
-- def get_type(self): return self._type
--
-- def get_access(self): return self._access
--
-- def is_optional(self): return self._isOptional
--
-- def is_index(self): return self._isIndex
--
-- def get_unit(self): return self._unit
--
-- def get_min(self): return self._min
--
-- def get_max(self): return self._max
--
-- def get_max_len(self): return self._maxlen
--
-- def get_desc(self): return self._desc
--
-- def get_reference(self): return self._reference
--
-- def is_parent_ref(self): return self._isParentRef
--
-- def get_direction(self): return self._dir
--
-- def get_default(self): return self._default
--
-- def is_continuous(self): return self._is_continuous
--
-- def map_encode(self):
-- """
-- Return the map encoding of this schema.
-- """
-- _map = {}
-- _map["amqp_type"] = self._type
-- _map["access"] = self._access
-- _map["index"] = self._isIndex
-- _map["optional"] = self._isOptional
-- if self._unit: _map["unit"] = self._unit
-- if self._min: _map["min"] = self._min
-- if self._max: _map["max"] = self._max
-- if self._maxlen: _map["maxlen"] = self._maxlen
-- if self._desc: _map["desc"] = self._desc
-- if self._reference: _map["reference"] = self._reference
-- _map["parent_ref"] = self._isParentRef
-- if self._dir: _map["dir"] = self._dir
-- if self._default: _map["default"] = self._default
-- if self._is_continuous: _map["continuous"] = self._is_continuous
-- return _map
--
-- def __repr__(self):
-- return "SchemaProperty=<<" + str(self.map_encode()) + ">>"
--
-- def _update_hash(self, hasher):
-- """
-- Update the given hash object with a hash computed over this schema.
-- """
-- hasher.update(str(self._type))
-- hasher.update(str(self._isIndex))
-- hasher.update(str(self._isOptional))
-- hasher.update(str(self._is_continuous))
-- if self._access: hasher.update(self._access)
-- if self._unit: hasher.update(self._unit)
-- if self._desc: hasher.update(self._desc)
-- if self._dir: hasher.update(self._dir)
-- if self._default: hasher.update(self._default)
--
--
--class SchemaMethod(_mapEncoder):
-- """
-- The SchemaMethod class describes the method's structure, and contains a
-- SchemaProperty class for each argument declared by the method.
--
-- Map format:
-- map["arguments"] = map of "name"=<SchemaProperty> pairs.
-- map["desc"] = str, description of the method
-- """
-- KEY_NAME="_name"
-- KEY_ARGUMENTS="_arguments"
-- KEY_DESC="_desc"
-- KEY_ERROR="_error"
-- def __init__(self, _args={}, _desc=None, _map=None):
-- """
-- Construct a SchemaMethod.
--
-- @type args: map of "name"=<SchemaProperty> objects
-- @param args: describes the arguments accepted by the method
-- @type _desc: str
-- @param _desc: Human-readable description of the schema
-- """
-- if _map is not None:
-- _desc = _map.get(self.KEY_DESC)
-- margs = _map.get(self.KEY_ARGUMENTS)
-- if margs:
-- # margs are in map format - covert to SchemaProperty
-- tmp_args = {}
-- for name,val in margs.iteritems():
-- tmp_args[name] = SchemaProperty.from_map(val)
-- _args=tmp_args
--
-- self._arguments = _args.copy()
-- self._desc = _desc
--
-- # map constructor
-- def _from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(_from_map)
--
-- def get_desc(self): return self._desc
--
-- def get_arg_count(self): return len(self._arguments)
--
-- def get_arguments(self): return self._arguments.copy()
--
-- def get_argument(self, name): return self._arguments.get(name)
--
-- def add_argument(self, name, schema):
-- """
-- Add an argument to the list of arguments passed to this method.
-- Used by an agent for dynamically creating method schema.
--
-- @type name: string
-- @param name: name of new argument
-- @type schema: SchemaProperty
-- @param schema: SchemaProperty to add to this method
-- """
-- if not isinstance(schema, SchemaProperty):
-- raise TypeError("argument must be a SchemaProperty class")
-- # "Input" argument, by default
-- if schema._dir is None:
-- schema._dir = "I"
-- self._arguments[name] = schema
--
-- def map_encode(self):
-- """
-- Return the map encoding of this schema.
-- """
-- _map = {}
-- _args = {}
-- for name,val in self._arguments.iteritems():
-- _args[name] = val.map_encode()
-- _map[self.KEY_ARGUMENTS] = _args
-- if self._desc: _map[self.KEY_DESC] = self._desc
-- return _map
--
-- def __repr__(self):
-- result = "SchemaMethod=<<args=("
-- first = True
-- for name,arg in self._arguments.iteritems():
-- if first:
-- first = False
-- else:
-- result += ", "
-- result += name
-- result += ")>>"
-- return result
--
-- def _update_hash(self, hasher):
-- """
-- Update the given hash object with a hash computed over this schema.
-- """
-- for name,val in self._arguments.iteritems():
-- hasher.update(name)
-- val._update_hash(hasher)
-- if self._desc: hasher.update(self._desc)
--
--
--
--class SchemaClass(QmfData):
-- """
-- Base class for Data and Event Schema classes.
--
-- Map format:
-- map(QmfData), plus:
-- map["_schema_id"] = map representation of a SchemaClassId instance
-- map["_primary_key_names"] = order list of primary key names
-- """
-- KEY_PRIMARY_KEY_NAMES="_primary_key_names"
-- KEY_DESC = "_desc"
--
-- SUBTYPE_PROPERTY="qmfProperty"
-- SUBTYPE_METHOD="qmfMethod"
--
-- def __init__(self, _classId=None, _desc=None, _map=None):
-- """
-- Schema Class constructor.
--
-- @type classId: class SchemaClassId
-- @param classId: Identifier for this SchemaClass
-- @type _desc: str
-- @param _desc: Human-readable description of the schema
-- """
-- if _map is not None:
-- super(SchemaClass, self).__init__(_map=_map)
--
-- # decode each value based on its type
-- for name,value in self._values.iteritems():
-- if self._subtypes.get(name) == self.SUBTYPE_METHOD:
-- self._values[name] = SchemaMethod.from_map(value)
-- else:
-- self._values[name] = SchemaProperty.from_map(value)
-- cid = _map.get(self.KEY_SCHEMA_ID)
-- if cid:
-- _classId = SchemaClassId.from_map(cid)
-- self._object_id_names = _map.get(self.KEY_PRIMARY_KEY_NAMES,[])
-- _desc = _map.get(self.KEY_DESC)
-- else:
-- if _classId is None:
-- raise Exception("A class identifier must be supplied.")
-- super(SchemaClass, self).__init__(_object_id=str(_classId))
-- self._object_id_names = []
--
-- self._classId = _classId
-- self._desc = _desc
--
-- def get_class_id(self):
-- if not self._classId.get_hash_string():
-- self.generate_hash()
-- return self._classId
--
-- def get_desc(self): return self._desc
--
-- def generate_hash(self):
-- """
-- generate an md5 hash over the body of the schema,
-- and return a string representation of the hash
-- in format "%08x-%08x-%08x-%08x"
-- """
-- md5Hash = _md5Obj()
-- md5Hash.update(self._classId.get_package_name())
-- md5Hash.update(self._classId.get_class_name())
-- md5Hash.update(self._classId.get_type())
-- for name,x in self._values.iteritems():
-- md5Hash.update(name)
-- x._update_hash( md5Hash )
-- for name,value in self._subtypes.iteritems():
-- md5Hash.update(name)
-- md5Hash.update(value)
-- idx = 0
-- for name in self._object_id_names:
-- md5Hash.update(str(idx) + name)
-- idx += 1
-- hstr = md5Hash.hexdigest()[0:8] + "-" +\
-- md5Hash.hexdigest()[8:16] + "-" +\
-- md5Hash.hexdigest()[16:24] + "-" +\
-- md5Hash.hexdigest()[24:32]
-- # update classId with new hash value
-- self._classId._hstr = hstr
-- return hstr
--
--
-- def get_property_count(self):
-- count = 0
-- for value in self._subtypes.itervalues():
-- if value == self.SUBTYPE_PROPERTY:
-- count += 1
-- return count
--
-- def get_properties(self):
-- props = {}
-- for name,value in self._subtypes.iteritems():
-- if value == self.SUBTYPE_PROPERTY:
-- props[name] = self._values.get(name)
-- return props
--
-- def get_property(self, name):
-- if self._subtypes.get(name) == self.SUBTYPE_PROPERTY:
-- return self._values.get(name)
-- return None
--
-- def add_property(self, name, prop):
-- self.set_value(name, prop, self.SUBTYPE_PROPERTY)
-- # need to re-generate schema hash
-- self._classId._hstr = None
--
-- def get_value(self, name):
-- # check for meta-properties first
-- if name == SchemaClassId.KEY_PACKAGE:
-- return self._classId.get_package_name()
-- if name == SchemaClassId.KEY_CLASS:
-- return self._classId.get_class_name()
-- if name == SchemaClassId.KEY_TYPE:
-- return self._classId.get_type()
-- if name == SchemaClassId.KEY_HASH:
-- return self.get_class_id().get_hash_string()
-- if name == self.KEY_SCHEMA_ID:
-- return self.get_class_id()
-- if name == self.KEY_PRIMARY_KEY_NAMES:
-- return self._object_id_names[:]
-- return super(SchemaClass, self).get_value(name)
--
-- def has_value(self, name):
-- if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS, SchemaClassId.KEY_TYPE,
-- SchemaClassId.KEY_HASH, self.KEY_SCHEMA_ID, self.KEY_PRIMARY_KEY_NAMES]:
-- return True
-- super(SchemaClass, self).has_value(name)
--
-- def map_encode(self):
-- """
-- Return the map encoding of this schema.
-- """
-- _map = super(SchemaClass,self).map_encode()
-- _map[self.KEY_SCHEMA_ID] = self.get_class_id().map_encode()
-- if self._object_id_names:
-- _map[self.KEY_PRIMARY_KEY_NAMES] = self._object_id_names[:]
-- if self._desc:
-- _map[self.KEY_DESC] = self._desc
-- return _map
--
-- def __repr__(self):
-- return str(self.get_class_id())
--
--
--
--class SchemaObjectClass(SchemaClass):
-- """
-- A schema class that describes a data object. The data object is composed
-- of zero or more properties and methods. An instance of the SchemaObjectClass
-- can be identified using a key generated by concantenating the values of
-- all properties named in the primary key list.
--
-- Map format:
-- map(SchemaClass)
-- """
-- def __init__(self, _classId=None, _desc=None,
-- _props={}, _methods={}, _object_id_names=[],
-- _map=None):
-- """
-- @type pname: str
-- @param pname: name of package this schema belongs to
-- @type cname: str
-- @param cname: class name for this schema
-- @type desc: str
-- @param desc: Human-readable description of the schema
-- @type _hash: str
-- @param _methods: hash computed on the body of this schema, if known
-- @type _props: map of 'name':<SchemaProperty> objects
-- @param _props: all properties provided by this schema
-- @type _pkey: list of strings
-- @param _pkey: names of each property to be used for constructing the primary key
-- @type _methods: map of 'name':<SchemaMethod> objects
-- @param _methods: all methods provided by this schema
-- """
-- if _map is not None:
-- super(SchemaObjectClass,self).__init__(_map=_map)
-- else:
-- super(SchemaObjectClass, self).__init__(_classId=_classId, _desc=_desc)
-- self._object_id_names = _object_id_names
-- for name,value in _props.iteritems():
-- self.set_value(name, value, self.SUBTYPE_PROPERTY)
-- for name,value in _methods.iteritems():
-- self.set_value(name, value, self.SUBTYPE_METHOD)
--
-- if self._classId.get_type() != SchemaClassId.TYPE_DATA:
-- raise TypeError("Invalid ClassId type for data schema: %s" % self._classId)
--
-- # map constructor
-- def __from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(__from_map)
--
-- def get_id_names(self):
-- return self._object_id_names[:]
--
-- def get_method_count(self):
-- count = 0
-- for value in self._subtypes.itervalues():
-- if value == self.SUBTYPE_METHOD:
-- count += 1
-- return count
--
-- def get_methods(self):
-- meths = {}
-- for name,value in self._subtypes.iteritems():
-- if value == self.SUBTYPE_METHOD:
-- meths[name] = self._values.get(name)
-- return meths
--
-- def get_method(self, name):
-- if self._subtypes.get(name) == self.SUBTYPE_METHOD:
-- return self._values.get(name)
-- return None
--
-- def add_method(self, name, method):
-- self.set_value(name, method, self.SUBTYPE_METHOD)
-- # need to re-generate schema hash
-- self._classId._hstr = None
--
--
--
--
--class SchemaEventClass(SchemaClass):
-- """
-- A schema class that describes an event. The event is composed
-- of zero or more properties.
--
-- Map format:
-- map["schema_id"] = map, SchemaClassId map for this object.
-- map["desc"] = string description of this schema
-- map["properties"] = map of "name":SchemaProperty values.
-- """
-- def __init__(self, _classId=None, _desc=None, _props={},
-- _map=None):
-- if _map is not None:
-- super(SchemaEventClass,self).__init__(_map=_map)
-- else:
-- super(SchemaEventClass, self).__init__(_classId=_classId,
-- _desc=_desc)
-- for name,value in _props.iteritems():
-- self.set_value(name, value, self.SUBTYPE_PROPERTY)
--
-- if self._classId.get_type() != SchemaClassId.TYPE_EVENT:
-- raise TypeError("Invalid ClassId type for event schema: %s" %
-- self._classId)
--
-- # map constructor
-- def __from_map(cls, map_):
-- return cls(_map=map_)
-- from_map = classmethod(__from_map)
--
-Index: extras/qmf/src/py/qmf2/tests/multi_response.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/multi_response.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/multi_response.py (working copy)
-@@ -1,280 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--# note: objects, schema per agent must each be > max objs
--_SCHEMAS_PER_AGENT=7
--_OBJS_PER_AGENT=19
--_MAX_OBJS_PER_MSG=3
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.schema_count = _SCHEMAS_PER_AGENT
-- self.obj_count = _OBJS_PER_AGENT
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat,
-- max_msg_size=_MAX_OBJS_PER_MSG)
--
-- # Dynamically construct a management database
-- for i in range(self.schema_count):
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage",
-- "MyClass-" + str(i)),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- self.agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- for j in range(self.obj_count):
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":j,
-- "index2": "name-" + str(j),
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.agent_count = 2
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent indication interval
-- self.agent_heartbeat = 1
-- self.agents = []
-- for a in range(self.agent_count):
-- agent = _agentApp("agent-" + str(a),
-- self.broker,
-- self.agent_heartbeat)
-- agent.start_app()
-- self.agents.append(agent)
--
-- def tearDown(self):
-- for agent in self.agents:
-- if agent is not None:
-- agent.stop_app()
--
-- def test_all_schema_id(self):
-- # create console
-- # find agents
-- # synchronous query for all schemas_ids
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3)
-- self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name())
--
-- # get a list of all schema_ids
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT)
-- for sid in sid_list:
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "MyPackage")
-- self.assertTrue(sid.get_class_name().split('-')[0] == "MyClass")
--
-- self.console.destroy(10)
--
--
-- def test_all_schema(self):
-- # create console
-- # find agents
-- # synchronous query for all schemas
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3)
-- self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name())
--
-- # get a list of all schema_ids
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA)
-- schema_list = self.console.do_query(agent, query)
-- self.assertTrue(schema_list and
-- len(schema_list) == _SCHEMAS_PER_AGENT)
-- for schema in schema_list:
-- self.assertTrue(isinstance(schema, SchemaObjectClass))
--
-- self.console.destroy(10)
--
--
-- def test_all_object_id(self):
-- # create console
-- # find agents
-- # synchronous query for all object_ids by schema_id
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3)
-- self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name())
--
-- # get a list of all schema_ids
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT)
-- for sid in sid_list:
-- query = QmfQuery.create_wildcard_object_id(sid)
-- oid_list = self.console.do_query(agent, query)
-- self.assertTrue(oid_list and
-- len(oid_list) == _OBJS_PER_AGENT)
-- for oid in oid_list:
-- self.assertTrue(isinstance(oid, basestring))
--
-- self.console.destroy(10)
--
--
-- def test_all_objects(self):
-- # create console
-- # find agents
-- # synchronous query for all objects by schema_id
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3)
-- self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name())
--
-- # get a list of all schema_ids
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT)
-- for sid in sid_list:
-- query = QmfQuery.create_wildcard_object(sid)
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(obj_list and
-- len(obj_list) == _OBJS_PER_AGENT)
-- for obj in obj_list:
-- self.assertTrue(isinstance(obj,
-- qmf2.console.QmfConsoleData))
--
-- self.console.destroy(10)
-Index: extras/qmf/src/py/qmf2/tests/obj_gets.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/obj_gets.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/obj_gets.py (working copy)
-@@ -1,581 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--import datetime
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Management Database
-- # - two different schema packages,
-- # - two classes within one schema package
-- # - multiple objects per schema package+class
-- # - two "undescribed" objects
--
-- # "package1/class1"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class1"),
-- _desc="A test data schema - one",
-- _object_id_names=["key"] )
--
-- _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "count1", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "count2", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p1c1_key1"},
-- _schema=_schema)
-- _obj.set_value("count1", 0)
-- _obj.set_value("count2", 0)
-- self.agent.add_object( _obj )
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p1c1_key2"},
-- _schema=_schema )
-- _obj.set_value("count1", 9)
-- _obj.set_value("count2", 10)
-- self.agent.add_object( _obj )
--
-- # "package1/class2"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class2"),
-- _desc="A test data schema - two",
-- _object_id_names=["name"] )
-- # add properties
-- _schema.add_property( "name", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "string1", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"name":"p1c2_name1"},
-- _schema=_schema )
-- _obj.set_value("string1", "a data string")
-- self.agent.add_object( _obj )
--
--
-- # "package2/class1"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package2", "class1"),
-- _desc="A test data schema - second package",
-- _object_id_names=["key"] )
--
-- _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "counter", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p2c1_key1"},
-- _schema=_schema )
-- _obj.set_value("counter", 0)
-- self.agent.add_object( _obj )
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p2c1_key2"},
-- _schema=_schema )
-- _obj.set_value("counter", 2112)
-- self.agent.add_object( _obj )
--
--
-- # add two "unstructured" objects to the Agent
--
-- _obj = QmfAgentData(self.agent, _object_id="undesc-1")
-- _obj.set_value("field1", "a value")
-- _obj.set_value("field2", 2)
-- _obj.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj.set_value("field4", ["a", "list", "value"])
-- self.agent.add_object(_obj)
--
--
-- _obj = QmfAgentData(self.agent, _object_id="undesc-2")
-- _obj.set_value("key-1", "a value")
-- _obj.set_value("key-2", 2)
-- self.agent.add_object(_obj)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--class BaseTest(unittest.TestCase):
-- agent_count = 5
--
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- self.agents = []
-- for i in range(self.agent_count):
-- agent = _agentApp("agent-" + str(i), self.broker, 1)
-- agent.start_app()
-- self.agents.append(agent)
-- #print("!!!! STARTING TEST: %s" % datetime.datetime.utcnow())
--
-- def tearDown(self):
-- #print("!!!! STOPPING TEST: %s" % datetime.datetime.utcnow())
-- for agent in self.agents:
-- if agent is not None:
-- agent.stop_app()
--
--
-- def test_all_agents(self):
-- # create console
-- # find all agents
-- # synchronous query for all objects by id
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # console has discovered all agents, now query all undesc-2 objects
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_object_id="undesc-2", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_object_id() == "undesc-2")
--
-- # now query all objects from schema "package1"
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package1", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == (self.agent_count * 3))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
--
-- # now query all objects from schema "package2"
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package2", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == (self.agent_count * 2))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
--
-- # now query all objects from schema "package1/class2"
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package1", _cname="class2",
-- _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2")
--
-- # given the schema identifier from the last query, repeat using the
-- # specific schema id
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- schema_id = objs[0].get_schema_class_id()
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_schema_id=schema_id, _timeout=5)
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id() == schema_id)
--
--
-- self.console.destroy(10)
--
--
--
-- def test_agent_subset(self):
-- # create console
-- # find all agents
-- # synchronous query for all objects by id
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- agent_list = []
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
-- agent_list.append(agent)
--
-- # Only use a subset of the agents:
-- agent_list = agent_list[:len(agent_list)/2]
--
-- # console has discovered all agents, now query all undesc-2 objects
-- objs = self.console.get_objects(_object_id="undesc-2",
-- _agents=agent_list, _timeout=5)
-- self.assertTrue(len(objs) == len(agent_list))
-- for obj in objs:
-- self.assertTrue(obj.get_object_id() == "undesc-2")
--
-- # now query all objects from schema "package1"
-- objs = self.console.get_objects(_pname="package1",
-- _agents=agent_list,
-- _timeout=5)
-- self.assertTrue(len(objs) == (len(agent_list) * 3))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
--
-- # now query all objects from schema "package2"
-- objs = self.console.get_objects(_pname="package2",
-- _agents=agent_list,
-- _timeout=5)
-- self.assertTrue(len(objs) == (len(agent_list) * 2))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
--
-- # now query all objects from schema "package1/class2"
-- objs = self.console.get_objects(_pname="package1", _cname="class2",
-- _agents=agent_list,
-- _timeout=5)
-- self.assertTrue(len(objs) == len(agent_list))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2")
--
-- # given the schema identifier from the last query, repeat using the
-- # specific schema id
-- schema_id = objs[0].get_schema_class_id()
-- objs = self.console.get_objects(_schema_id=schema_id,
-- _agents=agent_list,
-- _timeout=5)
-- self.assertTrue(len(objs) == len(agent_list))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id() == schema_id)
--
--
-- self.console.destroy(10)
--
--
--
-- def test_single_agent(self):
-- # create console
-- # find all agents
-- # synchronous query for all objects by id
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- agent_list = []
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
-- agent_list.append(agent)
--
-- # Only use one agent
-- agent = agent_list[0]
--
-- # console has discovered all agents, now query all undesc-2 objects
-- objs = self.console.get_objects(_object_id="undesc-2",
-- _agents=agent, _timeout=5)
-- self.assertTrue(len(objs) == 1)
-- for obj in objs:
-- self.assertTrue(obj.get_object_id() == "undesc-2")
--
-- # now query all objects from schema "package1"
-- objs = self.console.get_objects(_pname="package1",
-- _agents=agent,
-- _timeout=5)
-- self.assertTrue(len(objs) == 3)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
--
-- # now query all objects from schema "package2"
-- objs = self.console.get_objects(_pname="package2",
-- _agents=agent,
-- _timeout=5)
-- self.assertTrue(len(objs) == 2)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
--
-- # now query all objects from schema "package1/class2"
-- objs = self.console.get_objects(_pname="package1", _cname="class2",
-- _agents=agent,
-- _timeout=5)
-- self.assertTrue(len(objs) == 1)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2")
--
-- # given the schema identifier from the last query, repeat using the
-- # specific schema id
-- schema_id = objs[0].get_schema_class_id()
-- objs = self.console.get_objects(_schema_id=schema_id,
-- _agents=agent,
-- _timeout=5)
-- self.assertTrue(len(objs) == 1)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id() == schema_id)
--
--
-- self.console.destroy(10)
--
--
--
-- def test_all_objs_by_oid(self):
-- # create console
-- # find all agents
-- # synchronous query for all described objects by:
-- # oid & schema_id
-- # oid & package name
-- # oid & package and class name
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # now query all objects from schema "package1"
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package1",
-- _object_id="p1c1_key1", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
-- self.assertTrue(obj.get_object_id() == "p1c1_key1")
-- # mooch the schema for a later test
-- schema_id_p1c1 = objs[0].get_schema_class_id()
--
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package1",
-- _object_id="p1c2_name1", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2")
-- self.assertTrue(obj.get_object_id() == "p1c2_name1")
--
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package2", _cname="class1",
-- _object_id="p2c1_key1", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
-- self.assertTrue(obj.get_object_id() == "p2c1_key1")
--
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_schema_id=schema_id_p1c1,
-- _object_id="p1c1_key2", _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
-- self.assertTrue(obj.get_object_id() == "p1c1_key2")
--
-- # this should return all "undescribed" objects
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(len(objs) == (self.agent_count * 2))
-- for obj in objs:
-- self.assertTrue(obj.get_object_id() == "undesc-1" or
-- obj.get_object_id() == "undesc-2")
--
-- # these should fail
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_schema_id=schema_id_p1c1,
-- _object_id="does not exist",
-- _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(objs == None)
--
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package2",
-- _object_id="does not exist",
-- _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(objs == None)
--
-- #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow())
-- objs = self.console.get_objects(_pname="package3",
-- _object_id="does not exist",
-- _timeout=5)
-- #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow())
-- self.assertTrue(objs == None)
--
-- self.console.destroy(10)
--
--
-- def test_wildcard_schema_id(self):
-- # create console
-- # find all agents
-- # synchronous query for all described objects by:
-- # oid & wildcard schema_id
-- # wildcard schema_id
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- wild_schema_id = SchemaClassId("package1", "class1")
-- objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5)
-- self.assertTrue(len(objs) == (self.agent_count * 2))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
--
-- wild_schema_id = SchemaClassId("package1", "class2")
-- objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5)
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2")
-- self.assertTrue(obj.get_object_id() == "p1c2_name1")
--
-- wild_schema_id = SchemaClassId("package2", "class1")
-- objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5)
-- self.assertTrue(len(objs) == (self.agent_count * 2))
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
--
-- wild_schema_id = SchemaClassId("package1", "class1")
-- objs = self.console.get_objects(_schema_id=wild_schema_id,
-- _object_id="p1c1_key2", _timeout=5)
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
-- self.assertTrue(obj.get_object_id() == "p1c1_key2")
--
-- # should fail
-- objs = self.console.get_objects(_schema_id=wild_schema_id,
-- _object_id="does not exist",
-- _timeout=5)
-- self.assertTrue(objs == None)
--
-- wild_schema_id = SchemaClassId("package2", "class1")
-- objs = self.console.get_objects(_schema_id=wild_schema_id,
-- _object_id="p2c1_key2", _timeout=5)
-- self.assertTrue(len(objs) == self.agent_count)
-- for obj in objs:
-- self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2")
-- self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1")
-- self.assertTrue(obj.get_object_id() == "p2c1_key2")
--
-- # should fail
-- wild_schema_id = SchemaClassId("package1", "bad-class")
-- objs = self.console.get_objects(_schema_id=wild_schema_id,
-- _object_id="p1c1_key2", _timeout=5)
-- self.assertTrue(objs == None)
--
-- self.console.destroy(10)
--
-Index: extras/qmf/src/py/qmf2/tests/agent_test.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/agent_test.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/agent_test.py (working copy)
-@@ -1,167 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import logging
--import time
--import unittest
--from threading import Semaphore
--
--
--from qpid.messaging import *
--from qmf2.common import (qmfTypes, SchemaProperty, SchemaObjectClass, QmfData,
-- QmfEvent, SchemaMethod, Notifier, SchemaClassId,
-- WorkItem)
--from qmf2.agent import (Agent, QmfAgentData)
--
--
--
--class ExampleNotifier(Notifier):
-- def __init__(self):
-- self._sema4 = Semaphore(0) # locked
--
-- def indication(self):
-- self._sema4.release()
--
-- def waitForWork(self):
-- print("Waiting for event...")
-- self._sema4.acquire()
-- print("...event present")
--
--
--
--
--class QmfTest(unittest.TestCase):
-- def test_begin(self):
-- print("!!! being test")
--
-- def test_end(self):
-- print("!!! end test")
--
--
--#
--# An example agent application
--#
--
--
--if __name__ == '__main__':
-- _notifier = ExampleNotifier()
-- _agent = Agent( "qmf.testAgent", _notifier=_notifier )
--
-- # Dynamically construct a class schema
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- _agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- _obj1 = QmfAgentData( _agent, _schema=_schema )
-- _obj1.set_value("index1", 100)
-- _obj1.set_value("index2", "a name" )
-- _obj1.set_value("set_string", "UNSET")
-- _obj1.set_value("set_int", 0)
-- _obj1.set_value("query_count", 0)
-- _obj1.set_value("method_call_count", 0)
-- _agent.add_object( _obj1 )
--
-- _agent.add_object( QmfAgentData( _agent, _schema=_schema,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- # add an "unstructured" object to the Agent
-- _obj2 = QmfAgentData(_agent, _object_id="01545")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 2)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _agent.add_object(_obj2)
--
--
-- ## Now connect to the broker
--
-- _c = Connection("localhost")
-- _c.connect()
-- _agent.setConnection(_c)
--
-- _error_data = QmfData.create({"code": -1, "description": "You made a boo-boo."})
--
-- _done = False
-- while not _done:
-- # try:
-- _notifier.waitForWork()
--
-- _wi = _agent.get_next_workitem(timeout=0)
-- while _wi:
--
-- if _wi.get_type() == WorkItem.METHOD_CALL:
-- mc = _wi.get_params()
--
-- if mc.get_name() == "set_meth":
-- print("!!! Calling 'set_meth' on Object_id = %s" % mc.get_object_id())
-- print("!!! args='%s'" % str(mc.get_args()))
-- print("!!! userid=%s" % str(mc.get_user_id()))
-- print("!!! handle=%s" % _wi.get_handle())
-- _agent.method_response(_wi.get_handle(),
-- {"rc1": 100, "rc2": "Success"})
-- else:
-- print("!!! Unknown Method name = %s" % mc.get_name())
-- _agent.method_response(_wi.get_handle(), _error=_error_data)
-- else:
-- print("TBD: work item %d:%s" % (_wi.get_type(), str(_wi.get_params())))
--
-- _agent.release_workitem(_wi)
-- _wi = _agent.get_next_workitem(timeout=0)
-- # except:
-- # print( "shutting down...")
-- # _done = True
--
-- print( "Removing connection... TBD!!!" )
-- #_myConsole.remove_connection( _c, 10 )
--
-- print( "Destroying agent... TBD!!!" )
-- #_myConsole.destroy( 10 )
--
-- print( "******** agent test done ********" )
--
--
--
-Index: extras/qmf/src/py/qmf2/tests/async_method.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/async_method.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/async_method.py (working copy)
-@@ -1,353 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData, WorkItem)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent, MethodCallParams)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Dynamically construct a management database
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- # the input value of cookie is returned in the response
-- _meth.add_argument( "cookie", SchemaProperty(qmfTypes.TYPE_LSTR,
-- kwargs={"dir":"IO"}))
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- self.agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- _obj1 = QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":100, "index2":"a name"})
-- _obj1.set_value("set_string", "UNSET")
-- _obj1.set_value("set_int", 0)
-- _obj1.set_value("query_count", 0)
-- _obj1.set_value("method_call_count", 0)
-- self.agent.add_object( _obj1 )
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- # add an "unstructured" object to the Agent
-- _obj2 = QmfAgentData(self.agent, _object_id="01545")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 2)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- self.agent.add_object(_obj2)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- # Agent application main processing loop
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- if wi.get_type() == WorkItem.METHOD_CALL:
-- mc = wi.get_params()
-- if not isinstance(mc, MethodCallParams):
-- raise Exception("Unexpected method call parameters")
--
-- if mc.get_name() == "set_meth":
-- obj = self.agent.get_object(mc.get_object_id(),
-- mc.get_schema_id())
-- if obj is None:
-- error_info = QmfData.create({"code": -2,
-- "description":
-- "Bad Object Id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- obj.inc_value("method_call_count")
-- out_args = {"code" : 0}
-- if "cookie" in mc.get_args():
-- out_args["cookie"] = mc.get_args()["cookie"]
-- if "arg_int" in mc.get_args():
-- obj.set_value("set_int", mc.get_args()["arg_int"])
-- if "arg_str" in mc.get_args():
-- obj.set_value("set_string", mc.get_args()["arg_str"])
-- self.agent.method_response(wi.get_handle(),
-- out_args)
-- elif mc.get_name() == "a_method":
-- obj = self.agent.get_object(mc.get_object_id(),
-- mc.get_schema_id())
-- if obj is None:
-- error_info = QmfData.create({"code": -3,
-- "description":
-- "Unknown object id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- elif obj.get_object_id() != "01545":
-- error_info = QmfData.create( {"code": -4,
-- "description":
-- "Unexpected id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- args = mc.get_args()
-- if ("arg1" in args and args["arg1"] == 1 and
-- "arg2" in args and args["arg2"] == "Now set!"
-- and "arg3" in args and args["arg3"] == 1966):
-- out_args = {"code" : 0}
-- if "cookie" in mc.get_args():
-- out_args["cookie"] = mc.get_args()["cookie"]
-- self.agent.method_response(wi.get_handle(),
-- out_args)
-- else:
-- error_info = QmfData.create(
-- {"code": -5,
-- "description":
-- "Bad Args."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- error_info = QmfData.create( {"code": -1,
-- "description":
-- "Unknown method call."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(), _error=error_info)
--
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent heartbeat interval
-- self.agent_heartbeat = 1
-- self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_described_obj(self):
-- # create console
-- # find agents
-- # synchronous query for all objects in schema
-- # method call on each object
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- i_count = 0
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
--
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == 1)
-- for sid in sid_list:
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- _target_params=t_params)
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 2)
-- for obj in obj_list:
-- cookie = "cookie-" + str(i_count)
-- i_count += 1
-- mr = obj.invoke_method( "set_meth",
-- {"arg_int": -99,
-- "arg_str": "Now set!",
-- "cookie": cookie},
-- _reply_handle=cookie,
-- _timeout=3)
-- self.assertTrue(mr)
--
-- # done, now wait for async responses
--
-- r_count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.METHOD_RESPONSE)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, qmf2.console.MethodResult))
-- self.assertTrue(reply.succeeded())
-- self.assertTrue(reply.get_argument("cookie") == wi.get_handle())
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(r_count == i_count)
--
-- self.console.destroy(10)
--
--
-- def test_managed_obj(self):
-- # create console
-- # find agents
-- # synchronous query for a managed object
-- # method call on each object
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- i_count = 0
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "01545")
-- obj_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(obj_list, type([])))
-- self.assertTrue(len(obj_list) == 1)
-- obj = obj_list[0]
--
-- cookie = "cookie-" + str(i_count)
-- i_count += 1
-- mr = obj.invoke_method("a_method",
-- {"arg1": 1,
-- "arg2": "Now set!",
-- "arg3": 1966,
-- "cookie": cookie},
-- _reply_handle=cookie,
-- _timeout=3)
-- self.assertTrue(mr)
--
-- # done, now wait for async responses
--
-- r_count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.METHOD_RESPONSE)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, qmf2.console.MethodResult))
-- self.assertTrue(reply.succeeded())
-- self.assertTrue(reply.get_argument("cookie") == wi.get_handle())
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(r_count == i_count)
--
-- self.console.destroy(10)
-Index: extras/qmf/src/py/qmf2/tests/__init__.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/__init__.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/__init__.py (working copy)
-@@ -1,30 +0,0 @@
--# Do not delete - marks this directory as a python package.
--
--#
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT 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 agent_discovery
--import basic_query
--import basic_method
--import obj_gets
--import events
--import multi_response
--import async_query
--import async_method
--import subscriptions
-Index: extras/qmf/src/py/qmf2/tests/basic_method.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/basic_method.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/basic_method.py (working copy)
-@@ -1,391 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData, WorkItem)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent, MethodCallParams)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Dynamically construct a management database
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- self.agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- _obj1 = QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":100, "index2":"a name"})
-- _obj1.set_value("set_string", "UNSET")
-- _obj1.set_value("set_int", 0)
-- _obj1.set_value("query_count", 0)
-- _obj1.set_value("method_call_count", 0)
-- self.agent.add_object( _obj1 )
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- # add an "unstructured" object to the Agent
-- _obj2 = QmfAgentData(self.agent, _object_id="01545")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 2)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- self.agent.add_object(_obj2)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- # Agent application main processing loop
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- if wi.get_type() == WorkItem.METHOD_CALL:
-- mc = wi.get_params()
-- if not isinstance(mc, MethodCallParams):
-- raise Exception("Unexpected method call parameters")
--
-- if mc.get_name() == "set_meth":
-- obj = self.agent.get_object(mc.get_object_id(),
-- mc.get_schema_id())
-- if obj is None:
-- error_info = QmfData.create({"code": -2,
-- "description":
-- "Bad Object Id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- obj.inc_value("method_call_count")
-- if "arg_int" in mc.get_args():
-- obj.set_value("set_int", mc.get_args()["arg_int"])
-- if "arg_str" in mc.get_args():
-- obj.set_value("set_string", mc.get_args()["arg_str"])
-- self.agent.method_response(wi.get_handle(),
-- {"code" : 0})
-- elif mc.get_name() == "a_method":
-- obj = self.agent.get_object(mc.get_object_id(),
-- mc.get_schema_id())
-- if obj is None:
-- error_info = QmfData.create({"code": -3,
-- "description":
-- "Unknown object id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- elif obj.get_object_id() != "01545":
-- error_info = QmfData.create( {"code": -4,
-- "description":
-- "Unexpected id."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- args = mc.get_args()
-- if ("arg1" in args and args["arg1"] == 1 and
-- "arg2" in args and args["arg2"] == "Now set!"
-- and "arg3" in args and args["arg3"] == 1966):
-- self.agent.method_response(wi.get_handle(),
-- {"code" : 0})
-- else:
-- error_info = QmfData.create(
-- {"code": -5,
-- "description":
-- "Bad Args."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(),
-- _error=error_info)
-- else:
-- error_info = QmfData.create( {"code": -1,
-- "description":
-- "Unknown method call."},
-- _object_id="_error")
-- self.agent.method_response(wi.get_handle(), _error=error_info)
--
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent heartbeat interval
-- self.agent_heartbeat = 1
-- self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_described_obj(self):
-- # create console
-- # find agents
-- # synchronous query for all objects in schema
-- # method call on each object
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
--
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == 1)
-- for sid in sid_list:
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- _target_params=t_params)
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 2)
-- for obj in obj_list:
-- mr = obj.invoke_method( "set_meth", {"arg_int": -99,
-- "arg_str": "Now set!"},
-- _timeout=3)
-- self.assertTrue(isinstance(mr, qmf2.console.MethodResult))
-- self.assertTrue(mr.succeeded())
-- self.assertTrue(mr.get_argument("code") == 0)
--
-- self.assertTrue(obj.get_value("method_call_count") == 0)
-- self.assertTrue(obj.get_value("set_string") == "UNSET")
-- self.assertTrue(obj.get_value("set_int") == 0)
--
-- obj.refresh()
--
-- self.assertTrue(obj.get_value("method_call_count") == 1)
-- self.assertTrue(obj.get_value("set_string") == "Now set!")
-- self.assertTrue(obj.get_value("set_int") == -99)
--
-- self.console.destroy(10)
--
--
-- def test_bad_method_schema(self):
-- # create console
-- # find agents
-- # synchronous query for all objects with schema
-- # invalid method call on each object
-- # - should throw a ValueError - NOT YET.
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
--
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == 1)
-- for sid in sid_list:
--
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT,
-- [QmfQuery.TRUE],
-- _target_params=t_params)
--
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 2)
-- for obj in obj_list:
-- mr = obj.invoke_method("unknown_method",
-- {"arg1": -99, "arg2": "Now set!"},
-- _timeout=3)
-- # self.failUnlessRaises(ValueError,
-- # obj.invoke_method,
-- # "unknown_meth",
-- # {"arg1": -99, "arg2": "Now set!"},
-- # _timeout=3)
-- self.assertTrue(isinstance(mr, qmf2.console.MethodResult))
-- self.assertFalse(mr.succeeded())
-- self.assertTrue(isinstance(mr.get_exception(), QmfData))
--
-- self.console.destroy(10)
--
-- def test_bad_method_no_schema(self):
-- # create console
-- # find agents
-- # synchronous query for all objects with no schema
-- # invalid method call on each object
-- # - should throw a ValueError
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT)
--
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 1)
-- for obj in obj_list:
-- self.assertTrue(obj.get_schema_class_id() == None)
-- mr = obj.invoke_method("unknown_meth",
-- {"arg1": -99, "arg2": "Now set!"},
-- _timeout=3)
-- self.assertTrue(isinstance(mr, qmf2.console.MethodResult))
-- self.assertFalse(mr.succeeded())
-- self.assertTrue(isinstance(mr.get_exception(), QmfData))
--
-- self.console.destroy(10)
--
-- def test_managed_obj(self):
-- # create console
-- # find agents
-- # synchronous query for a managed object
-- # method call on each object
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "01545")
-- obj_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(obj_list, type([])))
-- self.assertTrue(len(obj_list) == 1)
-- obj = obj_list[0]
--
-- mr = obj.invoke_method("a_method",
-- {"arg1": 1,
-- "arg2": "Now set!",
-- "arg3": 1966},
-- _timeout=3)
-- self.assertTrue(isinstance(mr, qmf2.console.MethodResult))
-- self.assertTrue(mr.succeeded())
-- self.assertTrue(mr.get_argument("code") == 0)
-- # @todo refresh and verify changes
--
-- self.console.destroy(10)
-Index: extras/qmf/src/py/qmf2/tests/console_test.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/console_test.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/console_test.py (working copy)
-@@ -1,175 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import logging
--import time
--from threading import Semaphore
--
--
--from qpid.messaging import *
--from qmf2.common import (Notifier, QmfQuery, QmfQueryPredicate, MsgKey,
-- SchemaClassId, SchemaClass, QmfData)
--from qmf2.console import Console
--
--
--class ExampleNotifier(Notifier):
-- def __init__(self):
-- self._sema4 = Semaphore(0) # locked
--
-- def indication(self):
-- self._sema4.release()
--
-- def waitForWork(self):
-- print("Waiting for event...")
-- self._sema4.acquire()
-- print("...event present")
--
--
--logging.getLogger().setLevel(logging.INFO)
--
--print( "Starting Connection" )
--_c = Connection("localhost")
--_c.connect()
--
--print( "Starting Console" )
--
--_notifier = ExampleNotifier()
--_myConsole = Console(notifier=_notifier)
--_myConsole.addConnection( _c )
--
--# Allow discovery only for the agent named "qmf.testAgent"
--# @todo: replace "manual" query construction with
--# a formal class-based Query API
--_query = QmfQuery.create_predicate(QmfQuery.TARGET_AGENT,
-- QmfQueryPredicate({QmfQuery.CMP_EQ:
-- [QmfQuery.KEY_AGENT_NAME,
-- "qmf.testAgent"]}))
--_myConsole.enable_agent_discovery(_query)
--
--_done = False
--while not _done:
--# try:
-- _notifier.waitForWork()
--
-- _wi = _myConsole.get_next_workitem(timeout=0)
-- while _wi:
-- print("!!! work item received %d:%s" % (_wi.get_type(),
-- str(_wi.get_params())))
--
--
-- if _wi.get_type() == _wi.AGENT_ADDED:
-- _agent = _wi.get_params().get("agent")
-- if not _agent:
-- print("!!!! AGENT IN REPLY IS NULL !!! ")
--
-- _query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID)
-- oid_list = _myConsole.doQuery(_agent, _query)
--
-- print("!!!************************** REPLY=%s" % oid_list)
--
-- for oid in oid_list:
-- _query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT,
-- oid)
-- obj_list = _myConsole.doQuery(_agent, _query)
--
-- print("!!!************************** REPLY=%s" % obj_list)
--
-- if obj_list is None:
-- obj_list={}
--
-- for obj in obj_list:
-- resp = obj.invoke_method( "set_meth",
-- {"arg_int": -11,
-- "arg_str": "are we not goons?"},
-- None,
-- 3)
-- if resp is None:
-- print("!!!*** NO RESPONSE FROM METHOD????")
-- else:
-- print("!!! method succeeded()=%s" % resp.succeeded())
-- print("!!! method exception()=%s" % resp.get_exception())
-- print("!!! method get args() = %s" % resp.get_arguments())
--
-- if not obj.is_described():
-- resp = obj.invoke_method( "bad method",
-- {"arg_int": -11,
-- "arg_str": "are we not goons?"},
-- None,
-- 3)
-- if resp is None:
-- print("!!!*** NO RESPONSE FROM METHOD????")
-- else:
-- print("!!! method succeeded()=%s" % resp.succeeded())
-- print("!!! method exception()=%s" % resp.get_exception())
-- print("!!! method get args() = %s" % resp.get_arguments())
--
--
-- #---------------------------------
-- #_query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "99another name")
--
-- #obj_list = _myConsole.doQuery(_agent, _query)
--
-- #---------------------------------
--
-- # _query = QmfQuery.create_wildcard(QmfQuery.TARGET_PACKAGES)
--
-- # package_list = _myConsole.doQuery(_agent, _query)
--
-- # for pname in package_list:
-- # print("!!! Querying for schema from package: %s" % pname)
-- # _query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID,
-- # QmfQueryPredicate(
-- # {QmfQuery.CMP_EQ: [SchemaClassId.KEY_PACKAGE, pname]}))
--
-- # schema_id_list = _myConsole.doQuery(_agent, _query)
-- # for sid in schema_id_list:
-- # _query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA,
-- # QmfQueryPredicate(
-- # {QmfQuery.CMP_EQ: [SchemaClass.KEY_SCHEMA_ID,
-- # sid.map_encode()]}))
--
-- # schema_list = _myConsole.doQuery(_agent, _query)
-- # for schema in schema_list:
-- # sid = schema.get_class_id()
-- # _query = QmfQuery.create_predicate(
-- # QmfQuery.TARGET_OBJECT_ID,
-- # QmfQueryPredicate({QmfQuery.CMP_EQ:
-- # [QmfData.KEY_SCHEMA_ID,
-- # sid.map_encode()]}))
--
-- # oid_list = _myConsole.doQuery(_agent, _query)
-- # for oid in oid_list:
-- # _query = QmfQuery.create_id(
-- # QmfQuery.TARGET_OBJECT, oid)
-- # _reply = _myConsole.doQuery(_agent, _query)
--
-- # print("!!!************************** REPLY=%s" % _reply)
--
--
-- _myConsole.release_workitem(_wi)
-- _wi = _myConsole.get_next_workitem(timeout=0)
--# except:
--# logging.info( "shutting down..." )
--# _done = True
--
--print( "Removing connection" )
--_myConsole.removeConnection( _c, 10 )
--
--print( "Destroying console:" )
--_myConsole.destroy( 10 )
--
--print( "******** console test done ********" )
-Index: extras/qmf/src/py/qmf2/tests/async_query.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/async_query.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/async_query.py (working copy)
-@@ -1,444 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData, WorkItem)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Dynamically construct a management database
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- self.agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- _obj1 = QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":100, "index2":"a name"})
-- _obj1.set_value("set_string", "UNSET")
-- _obj1.set_value("set_int", 0)
-- _obj1.set_value("query_count", 0)
-- _obj1.set_value("method_call_count", 0)
-- self.agent.add_object( _obj1 )
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":50,
-- "index2": "my name",
-- "set_string": "SET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
--
-- # add an "unstructured" object to the Agent
-- _obj2 = QmfAgentData(self.agent, _object_id="01545")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 2)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 50)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01546")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 3)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 51)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01544")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 4)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 49)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01543")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 4)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 48)
-- self.agent.add_object(_obj2)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent indication interval
-- self.agent_heartbeat = 1
-- self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_all_schema_ids(self):
-- # create console
-- # find agents
-- # asynchronous query for all schema ids
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # send queries
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- rc = self.console.do_query(agent, query,
-- _reply_handle=aname)
-- self.assertTrue(rc)
--
-- # done. Now wait for async responses
--
-- count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- count += 1
-- self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE)
-- self.assertTrue(wi.get_handle() == "agent1" or
-- wi.get_handle() == "agent2")
-- reply = wi.get_params()
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], SchemaClassId))
-- self.assertTrue(reply[0].get_package_name() == "MyPackage")
-- self.assertTrue(reply[0].get_class_name() == "MyClass")
-- self.console.release_workitem(wi)
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(count == 2)
-- self.console.destroy(10)
--
--
--
-- def test_undescribed_objs(self):
-- # create console
-- # find agents
-- # asynchronous query for all non-schema objects
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # send queries
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT)
-- rc = self.console.do_query(agent, query, _reply_handle=aname)
-- self.assertTrue(rc)
--
-- # done. Now wait for async responses
--
-- count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- count += 1
-- self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE)
-- self.assertTrue(wi.get_handle() == "agent1" or
-- wi.get_handle() == "agent2")
-- reply = wi.get_params()
-- self.assertTrue(len(reply) == 4)
-- self.assertTrue(isinstance(reply[0], qmf2.console.QmfConsoleData))
-- self.assertFalse(reply[0].is_described()) # no schema
-- self.console.release_workitem(wi)
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(count == 2)
-- self.console.destroy(10)
--
--
--
-- def test_described_objs(self):
-- # create console
-- # find agents
-- # asynchronous query for all schema-based objects
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- #
-- t_params = {QmfData.KEY_SCHEMA_ID: SchemaClassId("MyPackage", "MyClass")}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, t_params)
-- #
-- rc = self.console.do_query(agent, query, _reply_handle=aname)
-- self.assertTrue(rc)
--
-- # done. Now wait for async responses
--
-- count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- count += 1
-- self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE)
-- self.assertTrue(wi.get_handle() == "agent1" or
-- wi.get_handle() == "agent2")
-- reply = wi.get_params()
-- self.assertTrue(len(reply) == 3)
-- self.assertTrue(isinstance(reply[0], qmf2.console.QmfConsoleData))
-- self.assertTrue(reply[0].is_described()) # has schema
-- self.console.release_workitem(wi)
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(count == 2)
-- # @todo test if the console has learned the corresponding schemas....
-- self.console.destroy(10)
--
--
--
-- def test_all_schemas(self):
-- # create console
-- # find agents
-- # asynchronous query for all schemas
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # test internal state using non-api calls:
-- # no schemas present yet
-- self.assertTrue(len(self.console._schema_cache) == 0)
-- # end test
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # send queries
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA)
-- rc = self.console.do_query(agent, query, _reply_handle=aname)
-- self.assertTrue(rc)
--
-- # done. Now wait for async responses
--
-- count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- count += 1
-- self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE)
-- self.assertTrue(wi.get_handle() == "agent1" or
-- wi.get_handle() == "agent2")
-- reply = wi.get_params()
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], qmf2.common.SchemaObjectClass))
-- self.assertTrue(reply[0].get_class_id().get_package_name() == "MyPackage")
-- self.assertTrue(reply[0].get_class_id().get_class_name() == "MyClass")
-- self.console.release_workitem(wi)
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(count == 2)
--
-- # test internal state using non-api calls:
-- # schema has been learned
-- self.assertTrue(len(self.console._schema_cache) == 1)
-- # end test
--
-- self.console.destroy(10)
--
--
--
-- def test_query_expiration(self):
-- # create console
-- # find agents
-- # kill the agents
-- # send async query
-- # wait for & verify expiration
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=30)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # find the agents
-- agents = []
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
-- agents.append(agent)
--
-- # now nuke the agents from orbit. It's the only way to be sure.
--
-- self.agent1.stop_app()
-- self.agent1 = None
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- # now send queries to agents that no longer exist
-- for agent in agents:
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA)
-- rc = self.console.do_query(agent, query,
-- _reply_handle=agent.get_name(),
-- _timeout=2)
-- self.assertTrue(rc)
--
-- # done. Now wait for async responses due to timeouts
--
-- count = 0
-- while self.notifier.wait_for_work(3):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- count += 1
-- self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE)
-- self.assertTrue(wi.get_handle() == "agent1" or
-- wi.get_handle() == "agent2")
-- reply = wi.get_params()
-- self.assertTrue(len(reply) == 0) # empty
--
-- self.console.release_workitem(wi)
-- wi = self.console.get_next_workitem(timeout=0)
--
-- self.assertTrue(count == 2)
-- self.console.destroy(10)
-Index: extras/qmf/src/py/qmf2/tests/events.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/events.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/events.py (working copy)
-@@ -1,202 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import time
--import datetime
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qpid.harness import Skipped
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData, SchemaEventClass,
-- QmfEvent)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.timeout = 3
-- self.broker_url = broker_url
-- self.notifier = _testNotifier()
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Dynamically construct a management database
--
-- _schema = SchemaEventClass(_classId=SchemaClassId("MyPackage",
-- "MyClass",
-- stype=SchemaClassId.TYPE_EVENT),
-- _desc="A test event schema")
-- # add properties
-- _schema.add_property( "prop-1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "prop-2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # Add schema to Agent
-- self.schema = _schema
-- self.agent.register_object_class(_schema)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
-- # time.sleep(1)
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(self.timeout)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- conn = qpid.messaging.Connection(self.broker_url)
-- try:
-- conn.open()
-- except qpid.messaging.ConnectError, e:
-- raise Skipped(e)
--
-- self.agent.set_connection(conn)
-- self.ready.set()
--
-- counter = 1
-- while self.running:
-- # post an event every second
-- event = QmfEvent.create(long(time.time() * 1000),
-- QmfEvent.SEV_WARNING,
-- {"prop-1": counter,
-- "prop-2": str(datetime.datetime.utcnow())},
-- _schema_id=self.schema.get_class_id())
-- counter += 1
-- self.agent.raise_event(event)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
-- self.notifier.wait_for_work(1)
--
-- self.agent.remove_connection(self.timeout)
-- self.agent.destroy(self.timeout)
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent indication interval
-- self.agent1 = _agentApp("agent1", self.broker, 1)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, 1)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_get_events(self):
-- # create console
-- # find agents
--
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- try:
-- self.conn.open()
-- except qpid.messaging.ConnectError, e:
-- raise Skipped(e)
--
-- self.console.add_connection(self.conn)
--
-- # find the agents
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # now wait for events
-- agent1_events = agent2_events = 0
-- wi = self.console.get_next_workitem(timeout=4)
-- while wi:
-- if wi.get_type() == wi.EVENT_RECEIVED:
-- event = wi.get_params().get("event")
-- self.assertTrue(isinstance(event, QmfEvent))
-- self.assertTrue(event.get_severity() == QmfEvent.SEV_WARNING)
-- self.assertTrue(event.get_value("prop-1") > 0)
--
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_events += 1
-- elif agent.get_name() == "agent2":
-- agent2_events += 1
-- else:
-- self.fail("Unexpected agent name received: %s" %
-- agent.get_name())
-- if agent1_events and agent2_events:
-- break;
--
-- wi = self.console.get_next_workitem(timeout=4)
--
-- self.assertTrue(agent1_events > 0 and agent2_events > 0)
--
-- self.console.destroy(10)
--
--
--
--
-Index: extras/qmf/src/py/qmf2/tests/agent_discovery.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/agent_discovery.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/agent_discovery.py (working copy)
-@@ -1,464 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--import time
--from threading import Thread, Event
--
--import qpid.messaging
--import qmf2.common
--import qmf2.console
--import qmf2.agent
--
--
--class _testNotifier(qmf2.common.Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.timeout = 3
-- self.broker_url = broker_url
-- self.notifier = _testNotifier()
-- self.agent = qmf2.agent.Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
-- # No database needed for this test
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # Connect the agent to the broker,
-- # broker_url = "user/passwd at hostname:port"
--
-- conn = qpid.messaging.Connection(self.broker_url)
-- conn.open()
-- self.agent.set_connection(conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- # done, cleanup agent
-- self.agent.remove_connection(self.timeout)
-- self.agent.destroy(self.timeout)
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent indication interval
-- self.agent_heartbeat = 1
-- self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_discover_all(self):
-- """
-- create console
-- enable agent discovery
-- wait
-- expect agent add for agent1 and agent2
-- """
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
-- self.console.enable_agent_discovery()
--
-- agent1_found = agent2_found = False
-- wi = self.console.get_next_workitem(timeout=3)
-- while wi and not (agent1_found and agent2_found):
-- if wi.get_type() == wi.AGENT_ADDED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = True
-- elif agent.get_name() == "agent2":
-- agent2_found = True
-- else:
-- self.fail("Unexpected agent name received: %s" %
-- agent.get_name())
-- if agent1_found and agent2_found:
-- break;
--
-- wi = self.console.get_next_workitem(timeout=3)
--
-- self.assertTrue(agent1_found and agent2_found, "All agents not discovered")
--
-- self.console.destroy(10)
--
--
-- def test_discover_one(self):
-- """
-- create console
-- enable agent discovery, filter for agent1 only
-- wait until timeout
-- expect agent add for agent1 only
-- """
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- query = qmf2.common.QmfQuery.create_predicate(
-- qmf2.common.QmfQuery.TARGET_AGENT,
-- [qmf2.common.QmfQuery.EQ, qmf2.common.QmfQuery.KEY_AGENT_NAME,
-- [qmf2.common.QmfQuery.QUOTE, "agent1"]])
-- self.console.enable_agent_discovery(query)
--
-- agent1_found = agent2_found = False
-- wi = self.console.get_next_workitem(timeout=3)
-- while wi:
-- if wi.get_type() == wi.AGENT_ADDED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = True
-- elif agent.get_name() == "agent2":
-- agent2_found = True
-- else:
-- self.fail("Unexpected agent name received: %s" %
-- agent.get_name())
--
-- wi = self.console.get_next_workitem(timeout=2)
--
-- self.assertTrue(agent1_found and not agent2_found, "Unexpected agent discovered")
--
-- self.console.destroy(10)
--
--
-- def test_heartbeat(self):
-- """
-- create console with 2 sec agent timeout
-- enable agent discovery, find all agents
-- stop agent1, expect timeout notification
-- stop agent2, expect timeout notification
-- """
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=2)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
-- self.console.enable_agent_discovery()
--
-- agent1_found = agent2_found = False
-- wi = self.console.get_next_workitem(timeout=4)
-- while wi and not (agent1_found and agent2_found):
-- if wi.get_type() == wi.AGENT_ADDED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = True
-- elif agent.get_name() == "agent2":
-- agent2_found = True
-- else:
-- self.fail("Unexpected agent name received: %s" %
-- agent.get_name())
-- if agent1_found and agent2_found:
-- break;
--
-- wi = self.console.get_next_workitem(timeout=4)
--
-- self.assertTrue(agent1_found and agent2_found, "All agents not discovered")
--
-- # now kill agent1 and wait for expiration
--
-- agent1 = self.agent1
-- self.agent1 = None
-- agent1.stop_app()
--
-- wi = self.console.get_next_workitem(timeout=4)
-- while wi is not None:
-- if wi.get_type() == wi.AGENT_DELETED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = False
-- else:
-- self.fail("Unexpected agent_deleted received: %s" %
-- agent.get_name())
-- if not agent1_found:
-- break;
--
-- wi = self.console.get_next_workitem(timeout=4)
--
-- self.assertFalse(agent1_found, "agent1 did not delete!")
--
-- # now kill agent2 and wait for expiration
--
-- agent2 = self.agent2
-- self.agent2 = None
-- agent2.stop_app()
--
-- wi = self.console.get_next_workitem(timeout=4)
-- while wi is not None:
-- if wi.get_type() == wi.AGENT_DELETED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent2":
-- agent2_found = False
-- else:
-- self.fail("Unexpected agent_deleted received: %s" %
-- agent.get_name())
-- if not agent2_found:
-- break;
--
-- wi = self.console.get_next_workitem(timeout=4)
--
-- self.assertFalse(agent2_found, "agent2 did not delete!")
--
-- self.console.destroy(10)
--
--
-- def test_find_agent(self):
-- """
-- create console
-- do not enable agent discovery
-- find agent1, expect success
-- find agent-none, expect failure
-- find agent2, expect success
-- """
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- agent1 = self.console.find_agent("agent1", timeout=3)
-- self.assertTrue(agent1 and agent1.get_name() == "agent1")
--
-- no_agent = self.console.find_agent("agent-none", timeout=3)
-- self.assertTrue(no_agent == None)
--
-- agent2 = self.console.find_agent("agent2", timeout=3)
-- self.assertTrue(agent2 and agent2.get_name() == "agent2")
--
-- self.console.remove_connection(self.conn, 10)
-- self.console.destroy(10)
--
--
-- def test_heartbeat_x2(self):
-- """
-- create 2 consoles with 2 sec agent timeout
-- enable agent discovery, find all agents
-- stop agent1, expect timeout notification on both consoles
-- stop agent2, expect timeout notification on both consoles
-- """
-- console_count = 2
-- self.consoles = []
-- for i in range(console_count):
-- console = qmf2.console.Console("test-console-" + str(i),
-- notifier=_testNotifier(),
-- agent_timeout=2)
-- conn = qpid.messaging.Connection(self.broker)
-- conn.open()
-- console.add_connection(conn)
-- console.enable_agent_discovery()
-- self.consoles.append(console)
--
-- # now wait for all consoles to discover all agents,
-- # agents send a heartbeat once a second
-- for console in self.consoles:
-- agent1_found = agent2_found = False
-- wi = console.get_next_workitem(timeout=2)
-- while wi and not (agent1_found and agent2_found):
-- if wi.get_type() == wi.AGENT_ADDED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = True
-- elif agent.get_name() == "agent2":
-- agent2_found = True
-- else:
-- self.fail("Unexpected agent name received: %s" %
-- agent.get_name())
-- if agent1_found and agent2_found:
-- break;
-- wi = console.get_next_workitem(timeout=2)
--
-- self.assertTrue(agent1_found and agent2_found, "All agents not discovered")
--
-- # now kill agent1 and wait for expiration
--
-- agent1 = self.agent1
-- self.agent1 = None
-- agent1.stop_app()
--
-- for console in self.consoles:
-- agent1_found = True
-- wi = console.get_next_workitem(timeout=4)
-- while wi is not None:
-- if wi.get_type() == wi.AGENT_DELETED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent1":
-- agent1_found = False
-- break
-- else:
-- self.fail("Unexpected agent_deleted received: %s" %
-- agent.get_name())
--
-- wi = console.get_next_workitem(timeout=4)
--
-- self.assertFalse(agent1_found, "agent1 did not delete!")
--
-- # now kill agent2 and wait for expiration
--
-- agent2 = self.agent2
-- self.agent2 = None
-- agent2.stop_app()
--
-- for console in self.consoles:
-- agent2_found = True
-- wi = console.get_next_workitem(timeout=4)
-- while wi is not None:
-- if wi.get_type() == wi.AGENT_DELETED:
-- agent = wi.get_params().get("agent")
-- if not agent or not isinstance(agent, qmf2.console.Agent):
-- self.fail("Unexpected workitem from agent")
-- else:
-- if agent.get_name() == "agent2":
-- agent2_found = False
-- break
-- else:
-- self.fail("Unexpected agent_deleted received: %s" %
-- agent.get_name())
--
-- wi = console.get_next_workitem(timeout=4)
--
-- self.assertFalse(agent2_found, "agent2 did not delete!")
--
--
-- for console in self.consoles:
-- console.destroy(10)
--
--
-- def test_find_agent_x2(self):
-- """
-- create 2 consoles, do not enable agent discovery
-- console-1: find agent1, expect success
-- console-2: find agent2, expect success
-- Verify console-1 does -not- know agent2
-- Verify console-2 does -not- know agent1
-- """
-- console_count = 2
-- self.consoles = []
-- for i in range(console_count):
-- console = qmf2.console.Console("test-console-" + str(i),
-- notifier=_testNotifier(),
-- agent_timeout=2)
-- conn = qpid.messaging.Connection(self.broker)
-- conn.open()
-- console.add_connection(conn)
-- self.consoles.append(console)
--
-- agent1 = self.consoles[0].find_agent("agent1", timeout=3)
-- self.assertTrue(agent1 and agent1.get_name() == "agent1")
--
-- agent2 = self.consoles[1].find_agent("agent2", timeout=3)
-- self.assertTrue(agent2 and agent2.get_name() == "agent2")
--
-- # wait long enough for agent heartbeats to be sent...
--
-- time.sleep(self.agent_heartbeat * 2)
--
-- agents = self.consoles[0].get_agents()
-- self.assertTrue(len(agents) == 1 and agents[0].get_name() == "agent1")
-- agent1 = self.consoles[0].get_agent("agent1")
-- self.assertTrue(agent1 and agent1.get_name() == "agent1")
--
--
-- agents = self.consoles[1].get_agents()
-- self.assertTrue(len(agents) == 1 and agents[0].get_name() == "agent2")
-- agent2 = self.consoles[1].get_agent("agent2")
-- self.assertTrue(agent2 and agent2.get_name() == "agent2")
--
-- # verify no new agents were learned
--
-- for console in self.consoles:
-- console.destroy(10)
--
-Index: extras/qmf/src/py/qmf2/tests/basic_query.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/basic_query.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/basic_query.py (working copy)
-@@ -1,492 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat)
--
-- # Dynamically construct a management database
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"] )
-- # add properties
-- _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # These two properties can be set via the method call
-- _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod( _desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- self.agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- _obj1 = QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":100, "index2":"a name"})
-- _obj1.set_value("set_string", "UNSET")
-- _obj1.set_value("set_int", 0)
-- _obj1.set_value("query_count", 0)
-- _obj1.set_value("method_call_count", 0)
-- self.agent.add_object( _obj1 )
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
-- self.agent.add_object( QmfAgentData( self.agent, _schema=_schema,
-- _values={"index1":50,
-- "index2": "my name",
-- "set_string": "SET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0} ))
--
--
-- # add an "unstructured" object to the Agent
-- _obj2 = QmfAgentData(self.agent, _object_id="01545")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 2)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 50)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01546")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 3)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 51)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01544")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 4)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 49)
-- self.agent.add_object(_obj2)
--
-- _obj2 = QmfAgentData(self.agent, _object_id="01543")
-- _obj2.set_value("field1", "a value")
-- _obj2.set_value("field2", 4)
-- _obj2.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj2.set_value("field4", ["a", "list", "value"])
-- _obj2.set_value("index1", 48)
-- self.agent.add_object(_obj2)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- # wake main thread
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--
--
--class BaseTest(unittest.TestCase):
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- # one second agent indication interval
-- self.agent_heartbeat = 1
-- self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat)
-- self.agent1.start_app()
-- self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat)
-- self.agent2.start_app()
--
-- def tearDown(self):
-- if self.agent1:
-- self.agent1.stop_app()
-- self.agent1 = None
-- if self.agent2:
-- self.agent2.stop_app()
-- self.agent2 = None
--
-- def test_all_oids(self):
-- # create console
-- # find agents
-- # synchronous query for all schemas
-- # synchronous query for all objects per schema
-- # verify known object ids are returned
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # first, find objects per schema
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == 1)
-- for sid in sid_list:
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID,
-- _target_params=t_params)
--
-- oid_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(oid_list, type([])),
-- "Unexpected return type")
-- self.assertTrue(len(oid_list) == 3, "Wrong count")
-- self.assertTrue('100a name' in oid_list)
-- self.assertTrue('99another name' in oid_list)
-- self.assertTrue('50my name' in oid_list)
-- self.assertTrue('01545' not in oid_list)
--
--
-- # now, find all unmanaged objects (no schema)
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID)
-- oid_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(oid_list, type([])),
-- "Unexpected return type")
-- self.assertTrue(len(oid_list) == 4, "Wrong count")
-- self.assertTrue('100a name' not in oid_list)
-- self.assertTrue('99another name' not in oid_list)
-- self.assertTrue('01545' in oid_list)
-- self.assertTrue('01544' in oid_list)
-- self.assertTrue('01543' in oid_list)
-- self.assertTrue('01546' in oid_list)
--
-- self.console.destroy(10)
--
--
-- def test_direct_oids(self):
-- # create console
-- # find agents
-- # synchronous query for each objects
-- # verify objects and schemas are correct
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # first, find objects per schema
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID)
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(sid_list and len(sid_list) == 1)
--
-- for oid in ['100a name', '99another name']:
-- query = QmfQuery.create_id_object(oid, sid_list[0])
-- obj_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(obj_list, type([])),
-- "Unexpected return type")
-- self.assertTrue(len(obj_list) == 1)
-- obj = obj_list[0]
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == oid)
-- self.assertTrue(obj.get_schema_class_id() == sid_list[0])
-- schema_id = obj.get_schema_class_id()
-- self.assertTrue(isinstance(schema_id, SchemaClassId))
-- self.assertTrue(obj.is_described())
--
-- # now find schema-less objects
-- for oid in ['01545']:
-- query = QmfQuery.create_id_object(oid)
-- obj_list = self.console.do_query(agent, query)
--
-- self.assertTrue(isinstance(obj_list, type([])),
-- "Unexpected return type")
-- self.assertTrue(len(obj_list) == 1)
-- obj = obj_list[0]
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == oid)
-- self.assertFalse(obj.is_described())
--
-- self.console.destroy(10)
--
--
--
-- def test_packages(self):
-- # create console
-- # find agents
-- # synchronous query all package names
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_PACKAGES)
-- package_list = self.console.do_query(agent, query)
-- self.assertTrue(len(package_list) == 1)
-- self.assertTrue('MyPackage' in package_list)
--
--
-- self.console.destroy(10)
--
--
--
-- def test_predicate_schema_id(self):
-- # create console
-- # find agents
-- # synchronous query for all schema by package name
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA,
-- [QmfQuery.EQ,
-- SchemaClassId.KEY_PACKAGE,
-- [QmfQuery.QUOTE, "MyPackage"]])
--
-- schema_list = self.console.do_query(agent, query)
-- self.assertTrue(len(schema_list))
-- for schema in schema_list:
-- self.assertTrue(schema.get_class_id().get_package_name() ==
-- "MyPackage")
--
--
-- self.console.destroy(10)
--
--
--
-- def test_predicate_no_match(self):
-- # create console
-- # find agents
-- # synchronous query for all schema by package name
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA,
-- [QmfQuery.EQ,
-- [QmfQuery.UNQUOTE, SchemaClassId.KEY_PACKAGE],
-- [QmfQuery.QUOTE, "No-Such-Package"]])
--
-- schema_list = self.console.do_query(agent, query)
-- self.assertTrue(len(schema_list) == 0)
--
-- self.console.destroy(10)
--
--
-- def test_predicate_match_string(self):
-- # create console
-- # find agents
-- # synchronous query for all objects with a value named
-- # set_string which is < or equal to "UNSET"
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # get the schema id for MyPackage:MyClass schema
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID,
-- [QmfQuery.AND,
-- [QmfQuery.EQ, SchemaClassId.KEY_PACKAGE,
-- [QmfQuery.QUOTE, "MyPackage"]],
-- [QmfQuery.EQ, SchemaClassId.KEY_CLASS,
-- [QmfQuery.QUOTE, "MyClass"]]])
-- sid_list = self.console.do_query(agent, query)
-- self.assertTrue(len(sid_list) == 1)
--
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT,
-- [QmfQuery.AND,
-- [QmfQuery.EXISTS, [QmfQuery.QUOTE, "set_string"]],
-- [QmfQuery.EQ, "set_string", [QmfQuery.QUOTE, "UNSET"]]],
-- _target_params={QmfData.KEY_SCHEMA_ID: sid_list[0]})
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 2)
-- for obj in obj_list:
-- self.assertTrue(obj.has_value("set_string"))
-- self.assertTrue(obj.get_value("set_string") == "UNSET")
--
-- self.console.destroy(10)
--
--
--
-- def test_predicate_match_integer(self):
-- # create console
-- # find agents
-- # synchronous query for all objects with a value named
-- # "index1" which is < or equal to various values
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- for aname in ["agent1", "agent2"]:
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # Query the unmanaged (no schema) objects
--
-- # == 50
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT,
-- [QmfQuery.AND,
-- [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]],
-- [QmfQuery.EQ, "index1", 50]])
--
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 1)
-- self.assertTrue(obj_list[0].has_value("index1"))
-- self.assertTrue(obj_list[0].get_value("index1") == 50)
--
-- # <= 50
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT,
-- [QmfQuery.AND,
-- [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]],
-- [QmfQuery.LE, "index1", 50]])
--
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 3)
-- for obj in obj_list:
-- self.assertTrue(obj.has_value("index1"))
-- self.assertTrue(obj.get_value("index1") <= 50)
--
--
-- # > 50
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT,
-- [QmfQuery.AND,
-- [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]],
-- [QmfQuery.GT, "index1", 50]])
--
-- obj_list = self.console.do_query(agent, query)
-- self.assertTrue(len(obj_list) == 1)
-- for obj in obj_list:
-- self.assertTrue(obj.has_value("index1"))
-- self.assertTrue(obj.get_value("index1") > 50)
--
-- self.console.destroy(10)
--
-Index: extras/qmf/src/py/qmf2/tests/subscriptions.py
-===================================================================
---- extras/qmf/src/py/qmf2/tests/subscriptions.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/tests/subscriptions.py (working copy)
-@@ -1,983 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import unittest
--import logging
--import datetime
--import time
--from threading import Thread, Event
--
--import qpid.messaging
--from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId,
-- SchemaProperty, qmfTypes, SchemaMethod, QmfQuery,
-- QmfData, WorkItem)
--import qmf2.console
--from qmf2.agent import(QmfAgentData, Agent)
--
--
--class _testNotifier(Notifier):
-- def __init__(self):
-- self._event = Event()
--
-- def indication(self):
-- # note: called by qmf daemon thread
-- self._event.set()
--
-- def wait_for_work(self, timeout):
-- # note: called by application thread to wait
-- # for qmf to generate work
-- self._event.wait(timeout)
-- timed_out = self._event.isSet() == False
-- if not timed_out:
-- self._event.clear()
-- return True
-- return False
--
--
--class _agentApp(Thread):
-- def __init__(self, name, broker_url, heartbeat):
-- Thread.__init__(self)
-- self.notifier = _testNotifier()
-- self.broker_url = broker_url
-- self.agent = Agent(name,
-- _notifier=self.notifier,
-- heartbeat_interval=heartbeat,
-- max_duration=10,
-- default_duration=7,
-- min_duration=5,
-- min_interval=1,
-- default_interval=2)
--
-- # Management Database
-- # - two different schema packages,
-- # - two classes within one schema package
-- # - multiple objects per schema package+class
-- # - two "undescribed" objects
--
-- # "package1/class1"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class1"),
-- _desc="A test data schema - one",
-- _object_id_names=["key"] )
--
-- _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # note: count1 is continuous, count2 is not
-- count1_prop = SchemaProperty.create(qmfTypes.TYPE_UINT32,
-- continuous=True)
-- _schema.add_property( "count1", count1_prop)
-- count2_prop = SchemaProperty.create(qmfTypes.TYPE_UINT32,
-- continuous=False)
-- _schema.add_property( "count2", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p1c1_key1"},
-- _schema=_schema)
-- _obj.set_value("count1", 0)
-- _obj.set_value("count2", 0)
-- self.agent.add_object( _obj )
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p1c1_key2"},
-- _schema=_schema )
-- _obj.set_value("count1", 9)
-- _obj.set_value("count2", 10)
-- self.agent.add_object( _obj )
--
-- # "package1/class2"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class2"),
-- _desc="A test data schema - two",
-- _object_id_names=["name"] )
-- # add properties
-- _schema.add_property( "name", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "string1", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"name":"p1c2_name1"},
-- _schema=_schema )
-- _obj.set_value("string1", "a data string")
-- self.agent.add_object( _obj )
--
-- _obj = QmfAgentData( self.agent,
-- _values={"name":"p1c2_name2"},
-- _schema=_schema )
-- _obj.set_value("string1", "another data string")
-- self.agent.add_object( _obj )
--
--
-- # "package2/class1"
--
-- _schema = SchemaObjectClass( _classId=SchemaClassId("package2", "class1"),
-- _desc="A test data schema - second package",
-- _object_id_names=["key"] )
--
-- _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property( "counter", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- self.agent.register_object_class(_schema)
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p2c1_key1"},
-- _schema=_schema )
-- _obj.set_value("counter", 0)
-- self.agent.add_object( _obj )
--
-- _obj = QmfAgentData( self.agent,
-- _values={"key":"p2c1_key2"},
-- _schema=_schema )
-- _obj.set_value("counter", 2112)
-- self.agent.add_object( _obj )
--
--
-- # add two "unstructured" objects to the Agent
--
-- _obj = QmfAgentData(self.agent, _object_id="undesc-1")
-- _obj.set_value("field1", "a value")
-- _obj.set_value("field2", 2)
-- _obj.set_value("field3", {"a":1, "map":2, "value":3})
-- _obj.set_value("field4", ["a", "list", "value"])
-- self.agent.add_object(_obj)
--
--
-- _obj = QmfAgentData(self.agent, _object_id="undesc-2")
-- _obj.set_value("key-1", "a value")
-- _obj.set_value("key-2", 2)
-- self.agent.add_object(_obj)
--
-- self.running = False
-- self.ready = Event()
--
-- def start_app(self):
-- self.running = True
-- self.start()
-- self.ready.wait(10)
-- if not self.ready.is_set():
-- raise Exception("Agent failed to connect to broker.")
--
-- def stop_app(self):
-- self.running = False
-- self.notifier.indication() # hmmm... collide with daemon???
-- self.join(10)
-- if self.isAlive():
-- raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!")
--
-- def run(self):
-- # broker_url = "user/passwd at hostname:port"
-- self.conn = qpid.messaging.Connection(self.broker_url)
-- self.conn.open()
-- self.agent.set_connection(self.conn)
-- self.ready.set()
--
-- while self.running:
-- self.notifier.wait_for_work(None)
-- wi = self.agent.get_next_workitem(timeout=0)
-- while wi is not None:
-- logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type())
-- self.agent.release_workitem(wi)
-- wi = self.agent.get_next_workitem(timeout=0)
--
-- if self.conn:
-- self.agent.remove_connection(10)
-- self.agent.destroy(10)
--
--
--class BaseTest(unittest.TestCase):
-- agent_count = 5
--
-- def configure(self, config):
-- self.config = config
-- self.broker = config.broker
-- self.defines = self.config.defines
--
-- def setUp(self):
-- self.agents = []
-- for i in range(self.agent_count):
-- agent = _agentApp("agent-" + str(i), self.broker, 1)
-- agent.start_app()
-- self.agents.append(agent)
-- #print("!!!! STARTING TEST: %s" % datetime.datetime.utcnow())
--
-- def tearDown(self):
-- #print("!!!! STOPPING TEST: %s" % datetime.datetime.utcnow())
-- for agent in self.agents:
-- if agent is not None:
-- agent.stop_app()
--
--
-- def test_sync_by_schema(self):
-- # create console
-- # find all agents
-- # subscribe to changes to any object in package1/class1
-- # should succeed - verify 1 publish
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- subscriptions = []
-- index = 0
--
-- # query to match all objects in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- _target_params=t_params)
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # now subscribe to agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- index)
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- self.assertTrue(sp.get_duration() == 10)
-- self.assertTrue(sp.get_publish_interval() == 2)
--
-- subscriptions.append([sp, 0])
-- index += 1
--
-- # now wait for the (2 * interval) and count the updates
-- r_count = 0
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 2)
-- for obj in reply:
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == "p1c1_key2" or
-- obj.get_object_id() == "p1c1_key1")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
--
-- self.assertTrue(wi.get_handle() < len(subscriptions))
-- subscriptions[wi.get_handle()][1] += 1
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect 1 publish per subscription
-- self.assertTrue(r_count == 5)
-- for ii in range(len(subscriptions)):
-- self.assertTrue(subscriptions[ii][1] == 1)
--
-- self.console.destroy(10)
--
--
-- def test_sync_by_obj_id(self):
-- # create console
-- # find all agents
-- # subscribe to changes to any object in package1/class1
-- # should succeed
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- subscriptions = []
-- index = 0
--
-- # query to match all objects in schema package1/class1
-- # sid = SchemaClassId.create("package1", "class1")
-- # t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_id_object("undesc-2")
--
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # now subscribe to agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- index)
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
--
-- subscriptions.append([sp, 0])
-- index += 1
--
-- # now wait for all subscriptions to expire (2x interval w/o
-- # indications)
-- r_count = 0
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "undesc-2")
-- self.assertTrue(wi.get_handle() < len(subscriptions))
-- subscriptions[wi.get_handle()][1] += 1
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect 1 publish per subscription
-- self.assertTrue(r_count == 5)
-- for ii in range(len(subscriptions)):
-- self.assertTrue(subscriptions[ii][1] == 1)
--
-- self.console.destroy(10)
--
--
-- def test_sync_by_obj_id_schema(self):
-- # create console
-- # find all agents
-- # subscribe to changes to any object in package1/class1
-- # should succeed
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- subscriptions = []
-- index = 0
--
-- # query to match object "p2c1_key2" in schema package2/class1
-- sid = SchemaClassId.create("package2", "class1")
-- query = QmfQuery.create_id_object("p2c1_key2", sid)
--
-- for agent_app in self.agents:
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # now subscribe to agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- index)
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
--
-- subscriptions.append([sp, 0])
-- index += 1
--
-- # now wait for all subscriptions to expire (2x interval w/o
-- # indications)
-- r_count = 0
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p2c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package2")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() < len(subscriptions))
-- subscriptions[wi.get_handle()][1] += 1
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect 1 publish per subscription
-- self.assertTrue(r_count == 5)
-- for ii in range(len(subscriptions)):
-- self.assertTrue(subscriptions[ii][1] == 1)
--
-- self.console.destroy(10)
--
--
--
-- def test_sync_refresh(self):
-- # create console
-- # find one agent
-- # subscribe to changes to any object in package1/class1
-- # after 3 data indications, refresh
-- # verify > 5 more data indications received
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # query to match object "p1c1_key2" in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- query = QmfQuery.create_id_object("p1c1_key2", sid)
--
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- "my-handle")
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
--
-- # refresh after three subscribe indications, count all
-- # indications to verify refresh worked
-- r_count = 0
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p1c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() == "my-handle")
--
-- # count1 is continuous, touching it will force a
-- # publish on the interval
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count1", r_count)
--
-- self.console.release_workitem(wi)
--
-- if r_count == 3:
-- rp = self.console.refresh_subscription(sp.get_subscription_id())
-- self.assertTrue(rp)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect 5 publish per subscription, more if refreshed
-- self.assertTrue(r_count > 5)
--
-- self.console.destroy(10)
--
--
--
-- def test_sync_cancel(self):
-- # create console
-- # find one agent
-- # subscribe to changes to any object in package1/class1
-- # after 2 data indications, cancel subscription
-- # verify < 5 data indications received
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # query to match object "p1c1_key2" in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- query = QmfQuery.create_id_object("p1c1_key2", sid)
--
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- "my-handle")
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
--
-- # refresh after three subscribe indications, count all
-- # indications to verify refresh worked
-- r_count = 0
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p1c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() == "my-handle")
--
-- # count1 is continuous, touching it will force a
-- # publish on the interval
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count1", r_count)
--
-- self.console.release_workitem(wi)
--
-- if r_count == 3:
-- self.console.cancel_subscription(sp.get_subscription_id())
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect only 3 publish received before cancel
-- self.assertTrue(r_count == 3)
--
-- self.console.destroy(10)
--
--
-- def test_async_by_obj_id_schema(self):
-- # create console
-- # find one agent
-- # async subscribe to changes to any object in package1/class1
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # query to match object "p2c1_key2" in schema package2/class1
-- sid = SchemaClassId.create("package2", "class1")
-- query = QmfQuery.create_id_object("p2c1_key2", sid)
--
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- rc = self.console.create_subscription(agent,
-- query,
-- "my-handle",
-- _blocking=False)
-- self.assertTrue(rc)
--
-- r_count = 0
-- sp = None
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- if wi.get_type() == WorkItem.SUBSCRIBE_RESPONSE:
-- self.assertTrue(wi.get_handle() == "my-handle")
-- sp = wi.get_params()
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- else:
-- self.assertTrue(wi.get_type() ==
-- WorkItem.SUBSCRIBE_INDICATION)
-- # sp better be set up by now!
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p2c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package2")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() == "my-handle")
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # one response + one publish = 2
-- self.assertTrue(r_count == 2)
--
-- self.console.destroy(10)
--
-- def test_async_refresh(self):
-- # create console
-- # find one agent
-- # async subscribe to changes to any object in package1/class1
-- # refresh after third data indication
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # query to match object "p1c1_key2" in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- query = QmfQuery.create_id_object("p1c1_key2", sid)
--
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- rc = self.console.create_subscription(agent,
-- query,
-- "my-handle",
-- _blocking=False)
-- self.assertTrue(rc)
--
-- # refresh after three subscribe indications, count all
-- # indications to verify refresh worked
-- r_count = 0
-- i_count = 0
-- sp = None
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- if wi.get_type() == WorkItem.SUBSCRIBE_RESPONSE:
-- self.assertTrue(wi.get_handle() == "my-handle")
-- sp = wi.get_params()
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- else:
-- self.assertTrue(wi.get_type() ==
-- WorkItem.SUBSCRIBE_INDICATION)
-- i_count += 1
-- # sp better be set up by now!
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p1c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() == "my-handle")
--
-- # count1 is continuous, touching it will force a
-- # publish on the interval
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count1", r_count)
--
-- if r_count == 4: # 3 data + 1 subscribe reply
-- rp = self.console.refresh_subscription(sp.get_subscription_id())
-- self.assertTrue(rp)
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect 5 publish per subscription, more if refreshed
-- self.assertTrue(sp is not None)
-- self.assertTrue(i_count > 5)
--
-- self.console.destroy(10)
--
--
-- def test_async_cancel(self):
-- # create console
-- # find one agent
-- # async subscribe to changes to any object in package1/class1
-- # cancel after first data indication
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- # query to match object "p1c1_key2" in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- query = QmfQuery.create_id_object("p1c1_key2", sid)
--
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- rc = self.console.create_subscription(agent,
-- query,
-- "my-handle",
-- _blocking=False)
-- self.assertTrue(rc)
--
-- r_count = 0
-- sp = None
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- if wi.get_type() == WorkItem.SUBSCRIBE_RESPONSE:
-- self.assertTrue(wi.get_handle() == "my-handle")
-- sp = wi.get_params()
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- else:
-- self.assertTrue(wi.get_type() ==
-- WorkItem.SUBSCRIBE_INDICATION)
-- # sp better be set up by now!
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- self.assertTrue(isinstance(reply[0], QmfData))
-- self.assertTrue(reply[0].get_object_id() == "p1c1_key2")
-- sid = reply[0].get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
-- self.assertTrue(wi.get_handle() == "my-handle")
--
-- # count1 is continuous, touching it will force a
-- # publish on the interval
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count1", r_count)
--
-- if r_count == 3:
-- self.console.cancel_subscription(sp.get_subscription_id())
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect cancel after 3 replies
-- self.assertTrue(r_count == 3)
--
-- self.console.destroy(10)
--
--
--
--
-- def test_sync_periodic_publish_continuous(self):
-- # create console
-- # find all agents
-- # subscribe to changes to any object in package1/class1
-- # should succeed - verify 1 publish
-- # Change continuous property on each publish,
-- # should only see 1 publish per interval
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- subscriptions = []
-- index = 0
--
-- # query to match all objects in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- _target_params=t_params)
-- # find an agent
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- "some-handle")
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- self.assertTrue(sp.get_duration() == 10)
-- self.assertTrue(sp.get_publish_interval() == 2)
--
-- # now wait for the (2 * interval) and count the updates
-- r_count = 0
-- sid = None
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- self.assertTrue(wi.get_handle() == "some-handle")
-- if r_count == 1:
-- # first indication - returns all matching objects
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 2)
-- for obj in reply:
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == "p1c1_key2" or
-- obj.get_object_id() == "p1c1_key1")
-- sid = obj.get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
--
-- else:
-- # verify publish of modified object only!
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- obj = reply[0]
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == "p1c1_key2")
-- self.assertTrue(obj.get_value("count1") == r_count - 1)
-- # fail test if we receive more than expected
-- self.assertTrue(r_count < 10)
--
--
-- # now update one of the objects!
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count1", r_count)
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect at most 1 publish per interval seen
-- self.assertTrue(r_count < 10)
--
-- self.console.destroy(10)
--
--
--
--
-- def test_sync_periodic_publish_noncontinuous(self):
-- # create console, find agent
-- # subscribe to changes to any object in package1/class1
-- # should succeed - verify 1 publish
-- # Change noncontinuous property on each publish,
-- # should only see 1 publish per each update
-- self.notifier = _testNotifier()
-- self.console = qmf2.console.Console(notifier=self.notifier,
-- agent_timeout=3)
-- self.conn = qpid.messaging.Connection(self.broker)
-- self.conn.open()
-- self.console.add_connection(self.conn)
--
-- subscriptions = []
-- index = 0
--
-- # query to match all objects in schema package1/class1
-- sid = SchemaClassId.create("package1", "class1")
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- _target_params=t_params)
-- # find an agent
-- agent_app = self.agents[0]
-- aname = agent_app.agent.get_name()
-- agent = self.console.find_agent(aname, timeout=3)
-- self.assertTrue(agent and agent.get_name() == aname)
--
-- # setup subscription on agent
--
-- sp = self.console.create_subscription(agent,
-- query,
-- "some-handle")
-- self.assertTrue(isinstance(sp, qmf2.console.SubscribeParams))
-- self.assertTrue(sp.succeeded())
-- self.assertTrue(sp.get_error() == None)
-- self.assertTrue(sp.get_duration() == 10)
-- self.assertTrue(sp.get_publish_interval() == 2)
--
-- # now wait for the (2 * interval) and count the updates
-- r_count = 0
-- sid = None
-- while self.notifier.wait_for_work(4):
-- wi = self.console.get_next_workitem(timeout=0)
-- while wi is not None:
-- r_count += 1
-- self.assertTrue(wi.get_type() == WorkItem.SUBSCRIBE_INDICATION)
-- self.assertTrue(wi.get_handle() == "some-handle")
-- if r_count == 1:
-- # first indication - returns all matching objects
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 2)
-- for obj in reply:
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == "p1c1_key2" or
-- obj.get_object_id() == "p1c1_key1")
-- sid = obj.get_schema_class_id()
-- self.assertTrue(isinstance(sid, SchemaClassId))
-- self.assertTrue(sid.get_package_name() == "package1")
-- self.assertTrue(sid.get_class_name() == "class1")
--
-- else:
-- # verify publish of modified object only!
-- reply = wi.get_params()
-- self.assertTrue(isinstance(reply, type([])))
-- self.assertTrue(len(reply) == 1)
-- obj = reply[0]
-- self.assertTrue(isinstance(obj, QmfData))
-- self.assertTrue(obj.get_object_id() == "p1c1_key2")
-- self.assertTrue(obj.get_value("count2") == r_count - 1)
-- # fail test if we receive more than expected
-- self.assertTrue(r_count < 30)
--
--
-- # now update the noncontinuous field of one of the objects!
-- if r_count < 20:
-- self.assertTrue(sid is not None)
-- test_obj = agent_app.agent.get_object("p1c1_key2", sid)
-- self.assertTrue(test_obj is not None)
-- test_obj.set_value("count2", r_count)
--
-- self.console.release_workitem(wi)
--
-- wi = self.console.get_next_workitem(timeout=0)
--
-- # expect at least 1 publish per update
-- self.assertTrue(r_count > 10)
--
-- self.console.destroy(10)
-Index: extras/qmf/src/py/qmf2/agent.py
-===================================================================
---- extras/qmf/src/py/qmf2/agent.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/agent.py (working copy)
-@@ -1,1380 +0,0 @@
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--
--import sys
--import datetime
--import time
--import Queue
--from logging import getLogger
--from threading import Thread, RLock, currentThread, Event
--from qpid.messaging import Connection, Message, Empty, SendError
--from uuid import uuid4
--from common import (OpCode, QmfQuery, ContentType, SchemaObjectClass,
-- QmfData, QmfAddress, SchemaClass, SchemaClassId, WorkItem,
-- SchemaMethod, timedelta_to_secs, QMF_APP_ID)
--
--# global flag that indicates which thread (if any) is
--# running the agent notifier callback
--_callback_thread=None
--
--log = getLogger("qmf")
--trace = getLogger("qmf.agent")
--
--
-- ##==============================================================================
-- ## METHOD CALL
-- ##==============================================================================
--
--class _MethodCallHandle(object):
-- """
-- Private class used to hold context when handing off a method call to the
-- application. Given to the app in a WorkItem, provided to the agent when
-- method_response() is invoked.
-- """
-- def __init__(self, correlation_id, reply_to, meth_name, _oid=None,
-- _schema_id=None):
-- self.correlation_id = correlation_id
-- self.reply_to = reply_to
-- self.meth_name = meth_name
-- self.oid = _oid
-- self.schema_id = _schema_id
--
--class MethodCallParams(object):
-- """
-- """
-- def __init__(self, name, _oid=None, _schema_id=None, _in_args=None,
-- _user_id=None):
-- self._meth_name = name
-- self._oid = _oid
-- self._schema_id = _schema_id
-- self._in_args = _in_args
-- self._user_id = _user_id
--
-- def get_name(self):
-- return self._meth_name
--
-- def get_object_id(self):
-- return self._oid
--
-- def get_schema_id(self):
-- return self._schema_id
--
-- def get_args(self):
-- return self._in_args
--
-- def get_user_id(self):
-- return self._user_id
--
--
-- ##==============================================================================
-- ## SUBSCRIPTIONS
-- ##==============================================================================
--
--
--class _SubscriptionState(object):
-- """
-- An internally-managed subscription.
-- """
-- def __init__(self, reply_to, cid, query, interval, duration):
-- self.reply_to = reply_to
-- self.correlation_id = cid
-- self.query = query
-- self.interval = interval
-- self.duration = duration
-- now = datetime.datetime.utcnow()
-- self.next_update = now # do an immediate update
-- self.expiration = now + datetime.timedelta(seconds=duration)
-- self.last_update = None
-- self.id = 0
--
-- def resubscribe(self, now, _duration=None):
-- if _duration is not None:
-- self.duration = _duration
-- self.expiration = now + datetime.timedelta(seconds=self.duration)
--
-- def published(self, now):
-- self.next_update = now + datetime.timedelta(seconds=self.interval)
-- self.last_update = now
--
--
-- ##==============================================================================
-- ## AGENT
-- ##==============================================================================
--
--class Agent(Thread):
-- def __init__(self, name, _domain=None, _notifier=None, **options):
-- Thread.__init__(self)
-- self._running = False
-- self._ready = Event()
--
-- self.name = str(name)
-- self._domain = _domain
-- self._address = QmfAddress.direct(self.name, self._domain)
-- self._notifier = _notifier
--
-- # configurable parameters
-- #
-- self._heartbeat_interval = options.get("heartbeat_interval", 30)
-- self._capacity = options.get("capacity", 10)
-- self._default_duration = options.get("default_duration", 300)
-- self._max_duration = options.get("max_duration", 3600)
-- self._min_duration = options.get("min_duration", 10)
-- self._default_interval = options.get("default_interval", 30)
-- self._min_interval = options.get("min_interval", 5)
--
-- # @todo: currently, max # of objects in a single reply message, would
-- # be better if it were max bytesize of per-msg content...
-- self._max_msg_size = options.get("max_msg_size", 0)
--
-- self._conn = None
-- self._session = None
-- self._direct_receiver = None
-- self._topic_receiver = None
-- self._direct_sender = None
-- self._topic_sender = None
--
-- self._lock = RLock()
-- self._packages = {}
-- self._schema_timestamp = long(0)
-- self._schema = {}
-- # _described_data holds QmfData objects that are associated with schema
-- # it is index by schema_id, object_id
-- self._described_data = {}
-- # _undescribed_data holds unstructured QmfData objects - these objects
-- # have no schema. it is indexed by object_id only.
-- self._undescribed_data = {}
-- self._work_q = Queue.Queue()
-- self._work_q_put = False
-- # subscriptions
-- self._subscription_id = long(time.time())
-- self._subscriptions = {}
-- self._next_subscribe_event = None
--
-- # prevents multiple _wake_thread() calls
-- self._noop_pending = False
--
--
-- def destroy(self, timeout=None):
-- """
-- Must be called before the Agent is deleted.
-- Frees up all resources and shuts down all background threads.
--
-- @type timeout: float
-- @param timeout: maximum time in seconds to wait for all background threads to terminate. Default: forever.
-- """
-- trace.debug("Destroying Agent %s" % self.name)
-- if self._conn:
-- self.remove_connection(timeout)
-- trace.debug("Agent Destroyed")
--
--
-- def get_name(self):
-- return self.name
--
-- def set_connection(self, conn):
-- self._conn = conn
-- self._session = self._conn.session()
--
-- # for messages directly addressed to me
-- self._direct_receiver = self._session.receiver(str(self._address) +
-- ";{create:always,"
-- " node:"
-- " {type:topic,"
-- " x-declare:"
-- " {type:direct}}}",
-- capacity=self._capacity)
-- trace.debug("my direct addr=%s" % self._direct_receiver.source)
--
-- # for sending directly addressed messages.
-- self._direct_sender = self._session.sender(str(self._address.get_node()) +
-- ";{create:always,"
-- " node:"
-- " {type:topic,"
-- " x-declare:"
-- " {type:direct}}}")
-- trace.debug("my default direct send addr=%s" % self._direct_sender.target)
--
-- # for receiving "broadcast" messages from consoles
-- default_addr = QmfAddress.topic(QmfAddress.SUBJECT_CONSOLE_IND + ".#",
-- self._domain)
-- self._topic_receiver = self._session.receiver(str(default_addr) +
-- ";{create:always,"
-- " node:"
-- " {type:topic}}",
-- capacity=self._capacity)
-- trace.debug("console.ind addr=%s" % self._topic_receiver.source)
--
-- # for sending to topic subscribers
-- ind_addr = QmfAddress.topic(QmfAddress.SUBJECT_AGENT_IND,
-- self._domain)
-- self._topic_sender = self._session.sender(str(ind_addr) +
-- ";{create:always,"
-- " node:"
-- " {type:topic}}")
-- trace.debug("agent.ind addr=%s" % self._topic_sender.target)
--
-- self._running = True
-- self.start()
-- self._ready.wait(10)
-- if not self._ready.isSet():
-- raise Exception("Agent managment thread failed to start.")
--
-- def remove_connection(self, timeout=None):
-- # tell connection thread to shutdown
-- self._running = False
-- if self.isAlive():
-- # kick my thread to wake it up
-- self._wake_thread()
-- trace.debug("waiting for agent receiver thread to exit")
-- self.join(timeout)
-- if self.isAlive():
-- log.error( "Agent thread '%s' is hung..." % self.name)
-- self._direct_receiver.close()
-- self._direct_receiver = None
-- self._direct_sender.close()
-- self._direct_sender = None
-- self._topic_receiver.close()
-- self._topic_receiver = None
-- self._topic_sender.close()
-- self._topic_sender = None
-- self._session.close()
-- self._session = None
-- self._conn = None
-- trace.debug("agent connection removal complete")
--
-- def register_object_class(self, schema):
-- """
-- Register an instance of a SchemaClass with this agent
-- """
-- # @todo: need to update subscriptions
-- # @todo: need to mark schema as "non-const"
-- if not isinstance(schema, SchemaClass):
-- raise TypeError("SchemaClass instance expected")
--
-- classId = schema.get_class_id()
-- pname = classId.get_package_name()
-- cname = classId.get_class_name()
-- hstr = classId.get_hash_string()
-- if not hstr:
-- raise Exception("Schema hash is not set.")
--
-- self._lock.acquire()
-- try:
-- if pname not in self._packages:
-- self._packages[pname] = [cname]
-- else:
-- if cname not in self._packages[pname]:
-- self._packages[pname].append(cname)
-- self._schema[classId] = schema
-- self._schema_timestamp = long(time.time() * 1000)
-- finally:
-- self._lock.release()
--
-- def register_event_class(self, schema):
-- return self.register_object_class(schema)
--
-- def raise_event(self, qmfEvent):
-- """
-- TBD
-- """
-- if not self._topic_sender:
-- raise Exception("No connection available")
--
-- # @todo: should we validate against the schema?
-- msg = Message(id=QMF_APP_ID,
-- subject=QmfAddress.SUBJECT_AGENT_EVENT + "." +
-- qmfEvent.get_severity() + "." + self.name,
-- properties={"method":"indication",
-- "qmf.opcode":OpCode.data_ind,
-- "qmf.content": ContentType.event,
-- "qmf.agent":self.name},
-- content=[qmfEvent.map_encode()])
-- # TRACE
-- # log.error("!!! Agent %s sending Event (%s)" %
-- # (self.name, str(msg)))
-- self._topic_sender.send(msg)
--
-- def add_object(self, data):
-- """
-- Register an instance of a QmfAgentData object.
-- """
-- # @todo: need to mark schema as "non-const"
-- if not isinstance(data, QmfAgentData):
-- raise TypeError("QmfAgentData instance expected")
--
-- oid = data.get_object_id()
-- if not oid:
-- raise TypeError("No identifier assigned to QmfAgentData!")
--
-- sid = data.get_schema_class_id()
--
-- self._lock.acquire()
-- try:
-- if sid:
-- if sid not in self._described_data:
-- self._described_data[sid] = {oid: data}
-- else:
-- self._described_data[sid][oid] = data
-- else:
-- self._undescribed_data[oid] = data
--
-- # does the new object match any subscriptions?
-- now = datetime.datetime.utcnow()
-- for sid,sub in self._subscriptions.iteritems():
-- if sub.query.evaluate(data):
-- # matched. Mark the subscription as needing to be
-- # serviced. The _publish() method will notice the new
-- # object and will publish it next time it runs.
-- sub.next_update = now
-- self._next_subscribe_event = None
-- # @todo: should we immediately publish?
--
-- finally:
-- self._lock.release()
--
-- def get_object(self, oid, schema_id):
-- data = None
-- self._lock.acquire()
-- try:
-- if schema_id:
-- data = self._described_data.get(schema_id)
-- if data:
-- data = data.get(oid)
-- else:
-- data = self._undescribed_data.get(oid)
-- finally:
-- self._lock.release()
-- return data
--
--
-- def method_response(self, handle, _out_args=None, _error=None):
-- """
-- """
-- if not isinstance(handle, _MethodCallHandle):
-- raise TypeError("Invalid handle passed to method_response!")
--
-- _map = {SchemaMethod.KEY_NAME:handle.meth_name}
-- if handle.oid is not None:
-- _map[QmfData.KEY_OBJECT_ID] = handle.oid
-- if handle.schema_id is not None:
-- _map[QmfData.KEY_SCHEMA_ID] = handle.schema_id.map_encode()
-- if _out_args is not None:
-- _map[SchemaMethod.KEY_ARGUMENTS] = _out_args.copy()
-- if _error is not None:
-- if not isinstance(_error, QmfData):
-- raise TypeError("Invalid type for error - must be QmfData")
-- _map[SchemaMethod.KEY_ERROR] = _error.map_encode()
--
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.method_rsp},
-- content=_map)
-- msg.correlation_id = handle.correlation_id
--
-- self._send_reply(msg, handle.reply_to)
--
-- def get_workitem_count(self):
-- """
-- Returns the count of pending WorkItems that can be retrieved.
-- """
-- return self._work_q.qsize()
--
-- def get_next_workitem(self, timeout=None):
-- """
-- Obtains the next pending work item, or None if none available.
-- """
-- try:
-- wi = self._work_q.get(True, timeout)
-- except Queue.Empty:
-- return None
-- return wi
--
-- def release_workitem(self, wi):
-- """
-- Releases a WorkItem instance obtained by getNextWorkItem(). Called when
-- the application has finished processing the WorkItem.
-- """
-- pass
--
--
-- def run(self):
-- global _callback_thread
-- next_heartbeat = datetime.datetime.utcnow()
-- batch_limit = 10 # a guess
--
-- self._ready.set()
--
-- while self._running:
--
-- #
-- # Process inbound messages
-- #
-- trace.debug("%s processing inbound messages..." % self.name)
-- for i in range(batch_limit):
-- try:
-- msg = self._topic_receiver.fetch(timeout=0)
-- except Empty:
-- break
-- # TRACE
-- # log.error("!!! Agent %s: msg on %s [%s]" %
-- # (self.name, self._topic_receiver.source, msg))
-- self._dispatch(msg, _direct=False)
--
-- for i in range(batch_limit):
-- try:
-- msg = self._direct_receiver.fetch(timeout=0)
-- except Empty:
-- break
-- # TRACE
-- # log.error("!!! Agent %s: msg on %s [%s]" %
-- # (self.name, self._direct_receiver.source, msg))
-- self._dispatch(msg, _direct=True)
--
-- #
-- # Send Heartbeat Notification
-- #
-- now = datetime.datetime.utcnow()
-- if now >= next_heartbeat:
-- trace.debug("%s sending heartbeat..." % self.name)
-- ind = Message(id=QMF_APP_ID,
-- subject=QmfAddress.SUBJECT_AGENT_HEARTBEAT,
-- properties={"method":"indication",
-- "qmf.opcode":OpCode.agent_heartbeat_ind,
-- "qmf.agent":self.name},
-- content=self._makeAgentInfoBody())
-- # TRACE
-- #log.error("!!! Agent %s sending Heartbeat (%s)" %
-- # (self.name, str(ind)))
-- self._topic_sender.send(ind)
-- trace.debug("Agent Indication Sent")
-- next_heartbeat = now + datetime.timedelta(seconds = self._heartbeat_interval)
--
-- #
-- # Monitor Subscriptions
-- #
-- self._lock.acquire()
-- try:
-- now = datetime.datetime.utcnow()
-- if (self._next_subscribe_event is None or
-- now >= self._next_subscribe_event):
-- trace.debug("%s polling subscriptions..." % self.name)
-- self._next_subscribe_event = now + datetime.timedelta(seconds=
-- self._max_duration)
-- dead_ss = {}
-- for sid,ss in self._subscriptions.iteritems():
-- if now >= ss.expiration:
-- dead_ss[sid] = ss
-- continue
-- if now >= ss.next_update:
-- self._publish(ss)
-- next_timeout = min(ss.expiration, ss.next_update)
-- if next_timeout < self._next_subscribe_event:
-- self._next_subscribe_event = next_timeout
--
-- for sid,ss in dead_ss.iteritems():
-- del self._subscriptions[sid]
-- self._unpublish(ss)
-- finally:
-- self._lock.release()
--
-- #
-- # notify application of pending WorkItems
-- #
-- if self._work_q_put and self._notifier:
-- trace.debug("%s notifying application..." % self.name)
-- # new stuff on work queue, kick the the application...
-- self._work_q_put = False
-- _callback_thread = currentThread()
-- trace.debug("Calling agent notifier.indication")
-- self._notifier.indication()
-- _callback_thread = None
--
-- #
-- # Sleep until messages arrive or something times out
-- #
-- now = datetime.datetime.utcnow()
-- next_timeout = next_heartbeat
-- self._lock.acquire()
-- try:
-- # the mailbox expire flag may be cleared by the
-- # app thread(s) in order to force an immediate publish
-- if self._next_subscribe_event is None:
-- next_timeout = now
-- elif self._next_subscribe_event < next_timeout:
-- next_timeout = self._next_subscribe_event
-- finally:
-- self._lock.release()
--
-- timeout = timedelta_to_secs(next_timeout - now)
--
-- if self._running and timeout > 0.0:
-- trace.debug("%s sleeping %s seconds..." % (self.name,
-- timeout))
-- try:
-- self._session.next_receiver(timeout=timeout)
-- except Empty:
-- pass
--
--
-- trace.debug("Shutting down Agent %s thread" % self.name)
--
-- #
-- # Private:
-- #
--
-- def _makeAgentInfoBody(self):
-- """
-- Create an agent indication message body identifying this agent
-- """
-- return QmfData.create({"_name": self.get_name(),
-- "_schema_timestamp": self._schema_timestamp}).map_encode()
--
-- def _send_reply(self, msg, reply_to):
-- """
-- Send a reply message to the given reply_to address
-- """
-- if not isinstance(reply_to, QmfAddress):
-- try:
-- reply_to = QmfAddress.from_string(str(reply_to))
-- except ValueError:
-- log.error("Invalid reply-to address '%s'" % reply_to)
--
-- msg.subject = reply_to.get_subject()
--
-- try:
-- if reply_to.is_direct():
-- # TRACE
-- #log.error("!!! Agent %s direct REPLY-To:%s (%s)" %
-- # (self.name, str(reply_to), str(msg)))
-- self._direct_sender.send(msg)
-- else:
-- # TRACE
-- # log.error("!!! Agent %s topic REPLY-To:%s (%s)" %
-- # (self.name, str(reply_to), str(msg)))
-- self._topic_sender.send(msg)
-- trace.debug("reply msg sent to [%s]" % str(reply_to))
-- except SendError, e:
-- log.error("Failed to send reply msg '%s' (%s)" % (msg, str(e)))
--
-- def _send_query_response(self, content_type, cid, reply_to, objects):
-- """
-- Send a response to a query, breaking the result into multiple
-- messages based on the agent's _max_msg_size config parameter
-- """
--
-- total = len(objects)
-- if self._max_msg_size:
-- max_count = self._max_msg_size
-- else:
-- max_count = total
--
-- start = 0
-- end = min(total, max_count)
-- # send partial response if too many objects present
-- while end < total:
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "partial":None,
-- "qmf.opcode":OpCode.data_ind,
-- "qmf.content":content_type,
-- "qmf.agent":self.name},
-- correlation_id = cid,
-- content=objects[start:end])
-- self._send_reply(m, reply_to)
-- start = end
-- end = min(total, end + max_count)
--
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.data_ind,
-- "qmf.content":content_type,
-- "qmf.agent":self.name},
-- correlation_id = cid,
-- content=objects[start:end])
-- self._send_reply(m, reply_to)
--
-- def _dispatch(self, msg, _direct=False):
-- """
-- Process a message from a console.
--
-- @param _direct: True if msg directly addressed to this agent.
-- """
-- trace.debug( "Message received from Console! [%s]" % msg )
--
-- opcode = msg.properties.get("qmf.opcode")
-- if not opcode:
-- log.warning("Ignoring unrecognized message '%s'" % msg)
-- return
-- version = 2 # @todo: fix me
-- cmap = {}; props={}
-- if msg.content_type == "amqp/map":
-- cmap = msg.content
-- if msg.properties:
-- props = msg.properties
--
-- if opcode == OpCode.agent_locate_req:
-- self._handleAgentLocateMsg( msg, cmap, props, version, _direct )
-- elif opcode == OpCode.query_req:
-- self._handleQueryMsg( msg, cmap, props, version, _direct )
-- elif opcode == OpCode.method_req:
-- self._handleMethodReqMsg(msg, cmap, props, version, _direct)
-- elif opcode == OpCode.subscribe_req:
-- self._handleSubscribeReqMsg(msg, cmap, props, version, _direct)
-- elif opcode == OpCode.subscribe_refresh_ind:
-- self._handleResubscribeReqMsg(msg, cmap, props, version, _direct)
-- elif opcode == OpCode.subscribe_cancel_ind:
-- self._handleUnsubscribeReqMsg(msg, cmap, props, version, _direct)
-- elif opcode == OpCode.noop:
-- self._noop_pending = False
-- trace.debug("No-op msg received.")
-- else:
-- log.warning("Ignoring message with unrecognized 'opcode' value: '%s'"
-- % opcode)
--
-- def _handleAgentLocateMsg( self, msg, cmap, props, version, direct ):
-- """
-- Process a received agent-locate message
-- """
-- trace.debug("_handleAgentLocateMsg")
--
-- reply = False
-- if props.get("method") == "request":
-- # if the message is addressed to me or wildcard, process it
-- if (msg.subject == "console.ind" or
-- msg.subject == "console.ind.locate" or
-- msg.subject == "console.ind.locate." + self.name):
-- pred = msg.content
-- if not pred:
-- reply = True
-- elif isinstance(pred, type([])):
-- # fake a QmfData containing my identifier for the query compare
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_AGENT, pred)
-- tmpData = QmfData.create({QmfQuery.KEY_AGENT_NAME:
-- self.get_name()},
-- _object_id="my-name")
-- reply = query.evaluate(tmpData)
--
-- if reply:
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.agent_locate_rsp},
-- content=self._makeAgentInfoBody())
-- m.correlation_id = msg.correlation_id
-- self._send_reply(m, msg.reply_to)
-- else:
-- trace.debug("agent-locate msg not mine - no reply sent")
--
--
-- def _handleQueryMsg(self, msg, cmap, props, version, _direct ):
-- """
-- Handle received query message
-- """
-- trace.debug("_handleQueryMsg")
--
-- if "method" in props and props["method"] == "request":
-- if cmap:
-- try:
-- query = QmfQuery.from_map(cmap)
-- except TypeError:
-- log.error("Invalid Query format: '%s'" % str(cmap))
-- return
-- target = query.get_target()
-- if target == QmfQuery.TARGET_PACKAGES:
-- self._queryPackagesReply( msg, query )
-- elif target == QmfQuery.TARGET_SCHEMA_ID:
-- self._querySchemaReply( msg, query, _idOnly=True )
-- elif target == QmfQuery.TARGET_SCHEMA:
-- self._querySchemaReply( msg, query)
-- elif target == QmfQuery.TARGET_AGENT:
-- log.warning("!!! @todo: Query TARGET=AGENT TBD !!!")
-- elif target == QmfQuery.TARGET_OBJECT_ID:
-- self._queryDataReply(msg, query, _idOnly=True)
-- elif target == QmfQuery.TARGET_OBJECT:
-- self._queryDataReply(msg, query)
-- else:
-- log.warning("Unrecognized query target: '%s'" % str(target))
--
--
--
-- def _handleMethodReqMsg(self, msg, cmap, props, version, _direct):
-- """
-- Process received Method Request
-- """
-- if "method" in props and props["method"] == "request":
-- mname = cmap.get(SchemaMethod.KEY_NAME)
-- if not mname:
-- log.warning("Invalid method call from '%s': no name"
-- % msg.reply_to)
-- return
--
-- in_args = cmap.get(SchemaMethod.KEY_ARGUMENTS)
-- oid = cmap.get(QmfData.KEY_OBJECT_ID)
-- schema_id = cmap.get(QmfData.KEY_SCHEMA_ID)
-- if schema_id:
-- schema_id = SchemaClassId.from_map(schema_id)
-- handle = _MethodCallHandle(msg.correlation_id,
-- msg.reply_to,
-- mname,
-- oid, schema_id)
-- param = MethodCallParams( mname, oid, schema_id, in_args,
-- msg.user_id)
--
-- # @todo: validate the method against the schema:
-- # if self._schema:
-- # # validate
-- # _in_args = _in_args.copy()
-- # ms = self._schema.get_method(name)
-- # if ms is None:
-- # raise ValueError("Method '%s' is undefined." % name)
--
-- # for aname,prop in ms.get_arguments().iteritems():
-- # if aname not in _in_args:
-- # if prop.get_default():
-- # _in_args[aname] = prop.get_default()
-- # elif not prop.is_optional():
-- # raise ValueError("Method '%s' requires argument '%s'"
-- # % (name, aname))
-- # for aname in _in_args.iterkeys():
-- # prop = ms.get_argument(aname)
-- # if prop is None:
-- # raise ValueError("Method '%s' does not define argument"
-- # " '%s'" % (name, aname))
-- # if "I" not in prop.get_direction():
-- # raise ValueError("Method '%s' argument '%s' is not an"
-- # " input." % (name, aname))
--
-- # # @todo check if value is correct (type, range, etc)
--
-- self._work_q.put(WorkItem(WorkItem.METHOD_CALL, handle, param))
-- self._work_q_put = True
--
-- def _handleSubscribeReqMsg(self, msg, cmap, props, version, _direct):
-- """
-- Process received Subscription Request
-- """
-- if "method" in props and props["method"] == "request":
-- query_map = cmap.get("_query")
-- interval = cmap.get("_interval")
-- duration = cmap.get("_duration")
--
-- try:
-- query = QmfQuery.from_map(query_map)
-- except TypeError:
-- log.warning("Invalid query for subscription: %s" %
-- str(query_map))
-- return
--
-- if isinstance(self, AgentExternal):
-- # param = SubscriptionParams(_ConsoleHandle(console_handle,
-- # msg.reply_to),
-- # query,
-- # interval,
-- # duration,
-- # msg.user_id)
-- # self._work_q.put(WorkItem(WorkItem.SUBSCRIBE_REQUEST,
-- # msg.correlation_id, param))
-- # self._work_q_put = True
-- log.error("External Subscription TBD")
-- return
--
-- # validate the query - only specific objects, or
-- # objects wildcard, are currently supported.
-- if (query.get_target() != QmfQuery.TARGET_OBJECT or
-- (query.get_selector() == QmfQuery.PREDICATE and
-- query.get_predicate())):
-- log.error("Subscriptions only support (wildcard) Object"
-- " Queries.")
-- err = QmfData.create(
-- {"reason": "Unsupported Query type for subscription.",
-- "query": str(query.map_encode())})
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.subscribe_rsp},
-- correlation_id = msg.correlation_id,
-- content={"_error": err.map_encode()})
-- self._send_reply(m, msg.reply_to)
-- return
--
-- if duration is None:
-- duration = self._default_duration
-- else:
-- try:
-- duration = float(duration)
-- if duration > self._max_duration:
-- duration = self._max_duration
-- elif duration < self._min_duration:
-- duration = self._min_duration
-- except:
-- log.warning("Bad duration value: %s" % str(msg))
-- duration = self._default_duration
--
-- if interval is None:
-- interval = self._default_interval
-- else:
-- try:
-- interval = float(interval)
-- if interval < self._min_interval:
-- interval = self._min_interval
-- except:
-- log.warning("Bad interval value: %s" % str(msg))
-- interval = self._default_interval
--
-- ss = _SubscriptionState(msg.reply_to,
-- msg.correlation_id,
-- query,
-- interval,
-- duration)
-- self._lock.acquire()
-- try:
-- sid = self._subscription_id
-- self._subscription_id += 1
-- ss.id = sid
-- self._subscriptions[sid] = ss
-- self._next_subscribe_event = None
-- finally:
-- self._lock.release()
--
-- sr_map = {"_subscription_id": sid,
-- "_interval": interval,
-- "_duration": duration}
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.subscribe_rsp},
-- correlation_id = msg.correlation_id,
-- content=sr_map)
-- self._send_reply(m, msg.reply_to)
--
--
--
-- def _handleResubscribeReqMsg(self, msg, cmap, props, version, _direct):
-- """
-- Process received Renew Subscription Request
-- """
-- if props.get("method") == "request":
-- sid = cmap.get("_subscription_id")
-- if not sid:
-- log.error("Invalid subscription refresh msg: %s" %
-- str(msg))
-- return
--
-- self._lock.acquire()
-- try:
-- ss = self._subscriptions.get(sid)
-- if not ss:
-- log.error("Ignoring unknown subscription: %s" %
-- str(sid))
-- return
-- duration = cmap.get("_duration")
-- if duration is not None:
-- try:
-- duration = float(duration)
-- if duration > self._max_duration:
-- duration = self._max_duration
-- elif duration < self._min_duration:
-- duration = self._min_duration
-- except:
-- log.error("Bad duration value: %s" % str(msg))
-- duration = None # use existing duration
--
-- ss.resubscribe(datetime.datetime.utcnow(), duration)
--
-- new_duration = ss.duration
-- new_interval = ss.interval
--
-- finally:
-- self._lock.release()
--
--
-- sr_map = {"_subscription_id": sid,
-- "_interval": new_interval,
-- "_duration": new_duration}
-- m = Message(id=QMF_APP_ID,
-- properties={"method":"response",
-- "qmf.opcode":OpCode.subscribe_rsp},
-- correlation_id = msg.correlation_id,
-- content=sr_map)
-- self._send_reply(m, msg.reply_to)
--
--
-- def _handleUnsubscribeReqMsg(self, msg, cmap, props, version, _direct):
-- """
-- Process received Cancel Subscription Request
-- """
-- if props.get("method") == "request":
-- sid = cmap.get("_subscription_id")
-- if not sid:
-- log.warning("No subscription id supplied: %s" % msg)
-- return
--
-- self._lock.acquire()
-- try:
-- if sid in self._subscriptions:
-- dead_sub = self._subscriptions[sid]
-- del self._subscriptions[sid]
-- finally:
-- self._lock.release()
--
-- self._unpublish(dead_sub)
--
--
-- def _queryPackagesReply(self, msg, query):
-- """
-- Run a query against the list of known packages
-- """
-- pnames = []
-- self._lock.acquire()
-- try:
-- for name in self._packages.iterkeys():
-- qmfData = QmfData.create({SchemaClassId.KEY_PACKAGE:name},
-- _object_id="_package")
-- if query.evaluate(qmfData):
-- pnames.append(name)
--
-- self._send_query_response(ContentType.schema_package,
-- msg.correlation_id,
-- msg.reply_to,
-- pnames)
-- finally:
-- self._lock.release()
--
--
-- def _querySchemaReply( self, msg, query, _idOnly=False ):
-- """
-- """
-- schemas = []
--
-- self._lock.acquire()
-- try:
-- # if querying for a specific schema, do a direct lookup
-- if query.get_selector() == QmfQuery.ID:
-- found = self._schema.get(query.get_id())
-- if found:
-- if _idOnly:
-- schemas.append(query.get_id().map_encode())
-- else:
-- schemas.append(found.map_encode())
-- else: # otherwise, evaluate all schema
-- for sid,val in self._schema.iteritems():
-- if query.evaluate(val):
-- if _idOnly:
-- schemas.append(sid.map_encode())
-- else:
-- schemas.append(val.map_encode())
-- if _idOnly:
-- msgkey = ContentType.schema_id
-- else:
-- msgkey = ContentType.schema_class
--
-- self._send_query_response(msgkey,
-- msg.correlation_id,
-- msg.reply_to,
-- schemas)
-- finally:
-- self._lock.release()
--
--
-- def _queryDataReply( self, msg, query, _idOnly=False ):
-- """
-- """
-- # hold the (recursive) lock for the duration so the Agent
-- # won't send data that is currently being modified by the
-- # app.
-- self._lock.acquire()
-- try:
-- response = []
-- data_objs = self._queryData(query)
-- if _idOnly:
-- for obj in data_objs:
-- response.append(obj.get_object_id())
-- else:
-- for obj in data_objs:
-- response.append(obj.map_encode())
--
-- if _idOnly:
-- msgkey = ContentType.object_id
-- else:
-- msgkey = ContentType.data
--
-- self._send_query_response(msgkey,
-- msg.correlation_id,
-- msg.reply_to,
-- response)
-- finally:
-- self._lock.release()
--
--
-- def _queryData(self, query):
-- """
-- Return a list of QmfData objects that match a given query
-- """
-- data_objs = []
-- # extract optional schema_id from target params
-- sid = None
-- t_params = query.get_target_param()
-- if t_params:
-- sid = t_params.get(QmfData.KEY_SCHEMA_ID)
--
-- self._lock.acquire()
-- try:
-- # if querying for a specific object, do a direct lookup
-- if query.get_selector() == QmfQuery.ID:
-- oid = query.get_id()
-- if sid and not sid.get_hash_string():
-- # wildcard schema_id match, check each schema
-- for name,db in self._described_data.iteritems():
-- if (name.get_class_name() == sid.get_class_name()
-- and name.get_package_name() == sid.get_package_name()):
-- found = db.get(oid)
-- if found:
-- data_objs.append(found)
-- else:
-- found = None
-- if sid:
-- db = self._described_data.get(sid)
-- if db:
-- found = db.get(oid)
-- else:
-- found = self._undescribed_data.get(oid)
-- if found:
-- data_objs.append(found)
--
-- else: # otherwise, evaluate all data
-- if sid and not sid.get_hash_string():
-- # wildcard schema_id match, check each schema
-- for name,db in self._described_data.iteritems():
-- if (name.get_class_name() == sid.get_class_name()
-- and name.get_package_name() == sid.get_package_name()):
-- for oid,data in db.iteritems():
-- if query.evaluate(data):
-- data_objs.append(data)
-- else:
-- if sid:
-- db = self._described_data.get(sid)
-- else:
-- db = self._undescribed_data
--
-- if db:
-- for oid,data in db.iteritems():
-- if query.evaluate(data):
-- data_objs.append(data)
-- finally:
-- self._lock.release()
--
-- return data_objs
--
-- def _publish(self, sub):
-- """ Publish a subscription.
-- """
-- response = []
-- now = datetime.datetime.utcnow()
-- objs = self._queryData(sub.query)
-- if objs:
-- for obj in objs:
-- if sub.id not in obj._subscriptions:
-- # new to subscription - publish it
-- obj._subscriptions[sub.id] = sub
-- response.append(obj.map_encode())
-- elif obj._dtime:
-- # obj._dtime is millisec since utc. Convert to datetime
-- utcdt = datetime.datetime.utcfromtimestamp(obj._dtime/1000.0)
-- if utcdt > sub.last_update:
-- response.append(obj.map_encode())
-- else:
-- # obj._utime is millisec since utc. Convert to datetime
-- utcdt = datetime.datetime.utcfromtimestamp(obj._utime/1000.0)
-- if utcdt > sub.last_update:
-- response.append(obj.map_encode())
--
-- if response:
-- trace.debug("!!! %s publishing %s!!!" % (self.name, sub.correlation_id))
-- self._send_query_response( ContentType.data,
-- sub.correlation_id,
-- sub.reply_to,
-- response)
-- sub.published(now)
--
-- def _unpublish(self, sub):
-- """ This subscription is about to be deleted, remove it from any
-- referencing objects.
-- """
-- objs = self._queryData(sub.query)
-- if objs:
-- for obj in objs:
-- if sub.id in obj._subscriptions:
-- del obj._subscriptions[sub.id]
--
--
--
-- def _wake_thread(self):
-- """
-- Make the agent management thread loop wakeup from its next_receiver
-- sleep.
-- """
-- self._lock.acquire()
-- try:
-- if not self._noop_pending:
-- trace.debug("Sending noop to wake up [%s]" % self._address)
-- msg = Message(id=QMF_APP_ID,
-- subject=self.name,
-- properties={"method":"indication",
-- "qmf.opcode":OpCode.noop},
-- content={})
-- try:
-- self._direct_sender.send( msg, sync=True )
-- self._noop_pending = True
-- except SendError, e:
-- log.error(str(e))
-- finally:
-- self._lock.release()
--
--
-- ##==============================================================================
-- ## EXTERNAL DATABASE AGENT
-- ##==============================================================================
--
--class AgentExternal(Agent):
-- """
-- An Agent which uses an external management database.
-- """
-- def __init__(self, name, _domain=None, _notifier=None,
-- _heartbeat_interval=30, _max_msg_size=0, _capacity=10):
-- super(AgentExternal, self).__init__(name, _domain, _notifier,
-- _heartbeat_interval,
-- _max_msg_size, _capacity)
-- log.error("AgentExternal TBD")
--
--
--
-- ##==============================================================================
-- ## DATA MODEL
-- ##==============================================================================
--
--
--class QmfAgentData(QmfData):
-- """
-- A managed data object that is owned by an agent.
-- """
--
-- def __init__(self, agent, _values={}, _subtypes={}, _tag=None,
-- _object_id=None, _schema=None):
-- schema_id = None
-- if _schema:
-- schema_id = _schema.get_class_id()
--
-- if _object_id is None:
-- if not isinstance(_schema, SchemaObjectClass):
-- raise Exception("An object_id must be provided if the object"
-- "doesn't have an associated schema.")
-- ids = _schema.get_id_names()
-- if not ids:
-- raise Exception("Object must have an Id or a schema that"
-- " provides an Id")
-- _object_id = u""
-- for key in ids:
-- value = _values.get(key)
-- if value is None:
-- raise Exception("Object must have a value for key"
-- " attribute '%s'" % str(key))
-- try:
-- _object_id += unicode(value)
-- except:
-- raise Exception("Cannot create object_id from key"
-- " value '%s'" % str(value))
--
-- # timestamp in millisec since epoch UTC
-- ctime = long(time.time() * 1000)
-- super(QmfAgentData, self).__init__(_values=_values, _subtypes=_subtypes,
-- _tag=_tag, _ctime=ctime,
-- _utime=ctime, _object_id=_object_id,
-- _schema_id=schema_id, _const=False)
-- self._agent = agent
-- self._validated = False
-- self._modified = True
-- self._subscriptions = {}
--
-- def destroy(self):
-- self._dtime = long(time.time() * 1000)
-- self._touch()
-- # @todo: publish change
--
-- def is_deleted(self):
-- return self._dtime == 0
--
-- def set_value(self, _name, _value, _subType=None):
-- super(QmfAgentData, self).set_value(_name, _value, _subType)
-- self._utime = long(time.time() * 1000)
-- self._touch(_name)
-- # @todo: publish change
--
-- def inc_value(self, name, delta=1):
-- """ add the delta to the property """
-- # @todo: need to take write-lock
-- val = self.get_value(name)
-- try:
-- val += delta
-- except:
-- raise
-- self.set_value(name, val)
--
-- def dec_value(self, name, delta=1):
-- """ subtract the delta from the property """
-- # @todo: need to take write-lock
-- val = self.get_value(name)
-- try:
-- val -= delta
-- except:
-- raise
-- self.set_value(name, val)
--
-- def validate(self):
-- """
-- Compares this object's data against the associated schema. Throws an
-- exception if the data does not conform to the schema.
-- """
-- props = self._schema.get_properties()
-- for name,val in props.iteritems():
-- # @todo validate: type compatible with amqp_type?
-- # @todo validate: primary keys have values
-- if name not in self._values:
-- if val._isOptional:
-- # ok not to be present, put in dummy value
-- # to simplify access
-- self._values[name] = None
-- else:
-- raise Exception("Required property '%s' not present." % name)
-- self._validated = True
--
-- def _touch(self, field=None):
-- """
-- Mark this object as modified. Used to force a publish of this object
-- if on subscription.
-- """
-- now = datetime.datetime.utcnow()
-- publish = False
-- if field:
-- # if the named field is not continuous, mark any subscriptions as
-- # needing to be published.
-- sid = self.get_schema_class_id()
-- if sid:
-- self._agent._lock.acquire()
-- try:
-- schema = self._agent._schema.get(sid)
-- if schema:
-- prop = schema.get_property(field)
-- if prop and not prop.is_continuous():
-- for sid,sub in self._subscriptions.iteritems():
-- sub.next_update = now
-- publish = True
-- if publish:
-- self._agent._next_subscribe_event = None
-- self._agent._wake_thread()
-- finally:
-- self._agent._lock.release()
--
--
--
--################################################################################
--################################################################################
--################################################################################
--################################################################################
--
--if __name__ == '__main__':
-- # static test cases - no message passing, just exercise API
-- import logging
-- from common import (AgentName, SchemaProperty, qmfTypes, SchemaEventClass)
--
-- logging.getLogger().setLevel(logging.INFO)
--
-- logging.info( "Create an Agent" )
-- _agent_name = AgentName("redhat.com", "agent", "tross")
-- _agent = Agent(str(_agent_name))
--
-- logging.info( "Get agent name: '%s'" % _agent.get_name())
--
-- logging.info( "Create SchemaObjectClass" )
--
-- _schema = SchemaObjectClass(SchemaClassId("MyPackage", "MyClass"),
-- _desc="A test data schema",
-- _object_id_names=["index1", "index2"])
-- # add properties
-- _schema.add_property("index1", SchemaProperty(qmfTypes.TYPE_UINT8))
-- _schema.add_property("index2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- # these two properties are statistics
-- _schema.add_property("query_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- _schema.add_property("method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32))
-- # These two properties can be set via the method call
-- _schema.add_property("set_string", SchemaProperty(qmfTypes.TYPE_LSTR))
-- _schema.add_property("set_int", SchemaProperty(qmfTypes.TYPE_UINT32))
--
-- # add method
-- _meth = SchemaMethod(_desc="Method to set string and int in object." )
-- _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) )
-- _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) )
-- _schema.add_method( "set_meth", _meth )
--
-- # Add schema to Agent
--
-- print("Schema Map='%s'" % str(_schema.map_encode()))
--
-- _agent.register_object_class(_schema)
--
-- # instantiate managed data objects matching the schema
--
-- logging.info( "Create QmfAgentData" )
--
-- _obj = QmfAgentData( _agent, _schema=_schema )
-- _obj.set_value("index1", 100)
-- _obj.set_value("index2", "a name" )
-- _obj.set_value("set_string", "UNSET")
-- _obj.set_value("set_int", 0)
-- _obj.set_value("query_count", 0)
-- _obj.set_value("method_call_count", 0)
--
-- print("Obj1 Map='%s'" % str(_obj.map_encode()))
--
-- _agent.add_object( _obj )
--
-- _obj = QmfAgentData( _agent,
-- _values={"index1":99,
-- "index2": "another name",
-- "set_string": "UNSET",
-- "set_int": 0,
-- "query_count": 0,
-- "method_call_count": 0},
-- _schema=_schema)
--
-- print("Obj2 Map='%s'" % str(_obj.map_encode()))
--
-- _agent.add_object(_obj)
--
-- ##############
--
--
--
-- logging.info( "Create SchemaEventClass" )
--
-- _event = SchemaEventClass(SchemaClassId("MyPackage", "MyEvent",
-- stype=SchemaClassId.TYPE_EVENT),
-- _desc="A test data schema",
-- _props={"edata_1": SchemaProperty(qmfTypes.TYPE_UINT32)})
-- _event.add_property("edata_2", SchemaProperty(qmfTypes.TYPE_LSTR))
--
-- print("Event Map='%s'" % str(_event.map_encode()))
--
-- _agent.register_event_class(_event)
-Index: extras/qmf/src/py/qmf2/__init__.py
-===================================================================
---- extras/qmf/src/py/qmf2/__init__.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/__init__.py (working copy)
-@@ -1,18 +0,0 @@
--#
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
-Index: extras/qmf/src/py/qmf2/console.py
-===================================================================
---- extras/qmf/src/py/qmf2/console.py (revision 1056407)
-+++ extras/qmf/src/py/qmf2/console.py (working copy)
-@@ -1,2626 +0,0 @@
--#
--# Licensed to the Apache Software Foundation (ASF) under one
--# or more contributor license agreements. See the NOTICE file
--# distributed with this work for additional information
--# regarding copyright ownership. The ASF licenses this file
--# to you under the Apache License, Version 2.0 (the
--# "License"); you may not use this file except in compliance
--# with the License. You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing,
--# software distributed under the License is distributed on an
--# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--# KIND, either express or implied. See the License for the
--# specific language governing permissions and limitations
--# under the License.
--#
--import sys
--import os
--import platform
--import time
--import datetime
--import Queue
--from logging import getLogger
--from threading import Thread, Event
--from threading import RLock
--from threading import currentThread
--from threading import Condition
--
--from qpid.messaging import Connection, Message, Empty, SendError
--
--from common import (QMF_APP_ID, OpCode, QmfQuery, Notifier, ContentType,
-- QmfData, QmfAddress, SchemaClass, SchemaClassId,
-- SchemaEventClass, SchemaObjectClass, WorkItem,
-- SchemaMethod, QmfEvent, timedelta_to_secs)
--
--
--# global flag that indicates which thread (if any) is
--# running the console notifier callback
--_callback_thread=None
--
--
--log = getLogger("qmf")
--trace = getLogger("qmf.console")
--
--
--##==============================================================================
--## Console Transaction Management
--##
--## At any given time, a console application may have multiple outstanding
--## message transactions with agents. The following objects allow the console
--## to track these outstanding transactions.
--##==============================================================================
--
--
--class _Mailbox(object):
-- """
-- Virtual base class for all Mailbox-like objects.
-- """
-- def __init__(self, console):
-- self.console = console
-- self.cid = 0
-- self.console._add_mailbox(self)
--
-- def get_address(self):
-- return self.cid
--
-- def deliver(self, data):
-- """
-- Invoked by Console Management thread when a message arrives for
-- this mailbox.
-- """
-- raise Exception("_Mailbox deliver() method must be provided")
--
-- def destroy(self):
-- """
-- Release the mailbox. Once called, the mailbox should no longer be
-- referenced.
-- """
-- self.console._remove_mailbox(self.cid)
--
--
--class _SyncMailbox(_Mailbox):
-- """
-- A simple mailbox that allows a consumer to wait for delivery of data.
-- """
-- def __init__(self, console):
-- """
-- Invoked by application thread.
-- """
-- super(_SyncMailbox, self).__init__(console)
-- self._cv = Condition()
-- self._data = []
-- self._waiting = False
--
-- def deliver(self, data):
-- """
-- Drop data into the mailbox, waking any waiters if necessary.
-- Invoked by Console Management thread only.
-- """
-- self._cv.acquire()
-- try:
-- self._data.append(data)
-- # if was empty, notify waiters
-- if len(self._data) == 1:
-- self._cv.notify()
-- finally:
-- self._cv.release()
--
-- def fetch(self, timeout=None):
-- """
-- Get one data item from a mailbox, with timeout.
-- Invoked by application thread.
-- """
-- self._cv.acquire()
-- try:
-- if len(self._data) == 0:
-- self._cv.wait(timeout)
-- if len(self._data):
-- return self._data.pop(0)
-- return None
-- finally:
-- self._cv.release()
--
--
--class _AsyncMailbox(_Mailbox):
-- """
-- A Mailbox for asynchronous delivery, with a timeout value.
-- """
-- def __init__(self, console,
-- _timeout=None):
-- """
-- Invoked by application thread.
-- """
-- super(_AsyncMailbox, self).__init__(console)
-- self.console = console
--
-- if _timeout is None:
-- _timeout = console._reply_timeout
-- self.expiration_date = (datetime.datetime.utcnow() +
-- datetime.timedelta(seconds=_timeout))
-- console._lock.acquire()
-- try:
-- console._async_mboxes[self.cid] = self
-- console._next_mbox_expire = None
-- finally:
-- console._lock.release()
--
-- # now that an async mbox has been created, wake the
-- # console mgmt thread so it will know about the mbox expiration
-- # date (and adjust its idle sleep period correctly)
--
-- console._wake_thread()
--
-- def reset_timeout(self, _timeout=None):
-- """ Reset the expiration date for this mailbox.
-- """
-- if _timeout is None:
-- _timeout = self.console._reply_timeout
-- self.console._lock.acquire()
-- try:
-- self.expiration_date = (datetime.datetime.utcnow() +
-- datetime.timedelta(seconds=_timeout))
-- self.console._next_mbox_expire = None
-- finally:
-- self.console._lock.release()
--
-- # wake the console mgmt thread so it will learn about the mbox
-- # expiration date (and adjust its idle sleep period correctly)
--
-- self.console._wake_thread()
--
-- def deliver(self, msg):
-- """
-- """
-- raise Exception("deliver() method must be provided")
--
-- def expire(self):
-- raise Exception("expire() method must be provided")
--
--
-- def destroy(self):
-- self.console._lock.acquire()
-- try:
-- if self.cid in self.console._async_mboxes:
-- del self.console._async_mboxes[self.cid]
-- finally:
-- self.console._lock.release()
-- super(_AsyncMailbox, self).destroy()
--
--
--
--class _QueryMailbox(_AsyncMailbox):
-- """
-- A mailbox used for asynchronous query requests.
-- """
-- def __init__(self, console,
-- agent_name,
-- context,
-- target,
-- _timeout=None):
-- """
-- Invoked by application thread.
-- """
-- super(_QueryMailbox, self).__init__(console,
-- _timeout)
-- self.agent_name = agent_name
-- self.target = target
-- self.context = context
-- self.result = []
--
-- def deliver(self, reply):
-- """
-- Process query response messages delivered to this mailbox.
-- Invoked by Console Management thread only.
-- """
-- trace.debug("Delivering to query mailbox (agent=%s)." % self.agent_name)
-- objects = reply.content
-- if isinstance(objects, type([])):
-- # convert from map to native types if needed
-- if self.target == QmfQuery.TARGET_SCHEMA_ID:
-- for sid_map in objects:
-- self.result.append(SchemaClassId.from_map(sid_map))
--
-- elif self.target == QmfQuery.TARGET_SCHEMA:
-- for schema_map in objects:
-- # extract schema id, convert based on schema type
-- sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID)
-- if sid_map:
-- sid = SchemaClassId.from_map(sid_map)
-- if sid:
-- if sid.get_type() == SchemaClassId.TYPE_DATA:
-- schema = SchemaObjectClass.from_map(schema_map)
-- else:
-- schema = SchemaEventClass.from_map(schema_map)
-- self.console._add_schema(schema) # add to schema cache
-- self.result.append(schema)
--
-- elif self.target == QmfQuery.TARGET_OBJECT:
-- for obj_map in objects:
-- # @todo: need the agent name - ideally from the
-- # reply message iself.
-- agent = self.console.get_agent(self.agent_name)
-- if agent:
-- obj = QmfConsoleData(map_=obj_map, agent=agent)
-- # start fetch of schema if not known
-- sid = obj.get_schema_class_id()
-- if sid:
-- self.console._prefetch_schema(sid, agent)
-- self.result.append(obj)
--
--
-- else:
-- # no conversion needed.
-- self.result += objects
--
-- if not "partial" in reply.properties:
-- # log.error("QUERY COMPLETE for %s" % str(self.context))
-- wi = WorkItem(WorkItem.QUERY_COMPLETE, self.context, self.result)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- self.destroy()
--
--
-- def expire(self):
-- trace.debug("Expiring query mailbox (agent=%s)." % self.agent_name)
-- # send along whatever (possibly none) has been received so far
-- wi = WorkItem(WorkItem.QUERY_COMPLETE, self.context, self.result)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- self.destroy()
--
--
--
--class _SchemaPrefetchMailbox(_AsyncMailbox):
-- """
-- Handles responses to schema fetches made by the console.
-- """
-- def __init__(self, console,
-- schema_id,
-- _timeout=None):
-- """
-- Invoked by application thread.
-- """
-- super(_SchemaPrefetchMailbox, self).__init__(console,
-- _timeout)
-- self.schema_id = schema_id
--
-- def deliver(self, reply):
-- """
-- Process schema response messages.
-- """
-- trace.debug("Delivering schema mailbox (id=%s)." % self.schema_id)
-- done = False
-- schemas = reply.content
-- if schemas and isinstance(schemas, type([])):
-- for schema_map in schemas:
-- # extract schema id, convert based on schema type
-- sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID)
-- if sid_map:
-- sid = SchemaClassId.from_map(sid_map)
-- if sid:
-- if sid.get_type() == SchemaClassId.TYPE_DATA:
-- schema = SchemaObjectClass.from_map(schema_map)
-- else:
-- schema = SchemaEventClass.from_map(schema_map)
-- self.console._add_schema(schema) # add to schema cache
-- self.destroy()
--
--
-- def expire(self):
-- trace.debug("Expiring schema mailbox (id=%s)." % self.schema_id)
-- self.destroy()
--
--
--
--class _MethodMailbox(_AsyncMailbox):
-- """
-- A mailbox used for asynchronous method requests.
-- """
-- def __init__(self, console,
-- context,
-- _timeout=None):
-- """
-- Invoked by application thread.
-- """
-- super(_MethodMailbox, self).__init__(console,
-- _timeout)
-- self.context = context
--
-- def deliver(self, reply):
-- """
-- Process method response messages delivered to this mailbox.
-- Invoked by Console Management thread only.
-- """
-- trace.debug("Delivering to method mailbox.")
-- _map = reply.content
-- if not _map or not isinstance(_map, type({})):
-- log.error("Invalid method call reply message")
-- result = None
-- else:
-- error=_map.get(SchemaMethod.KEY_ERROR)
-- if error:
-- error = QmfData.from_map(error)
-- result = MethodResult(_error=error)
-- else:
-- result = MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS))
--
-- # create workitem
-- wi = WorkItem(WorkItem.METHOD_RESPONSE, self.context, result)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- self.destroy()
--
--
-- def expire(self):
-- """
-- The mailbox expired without receiving a reply.
-- Invoked by the Console Management thread only.
-- """
-- trace.debug("Expiring method mailbox.")
-- # send along an empty response
-- wi = WorkItem(WorkItem.METHOD_RESPONSE, self.context, None)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- self.destroy()
--
--
--
--class _SubscriptionMailbox(_AsyncMailbox):
-- """
-- A Mailbox for a single subscription. Allows only sychronous "subscribe"
-- and "refresh" requests.
-- """
-- def __init__(self, console, context, agent, duration, interval):
-- """
-- Invoked by application thread.
-- """
-- super(_SubscriptionMailbox, self).__init__(console, duration)
-- self.cv = Condition()
-- self.data = []
-- self.result = []
-- self.context = context
-- self.duration = duration
-- self.interval = interval
-- self.agent_name = agent.get_name()
-- self.agent_subscription_id = None # from agent
--
-- def subscribe(self, query):
-- agent = self.console.get_agent(self.agent_name)
-- if not agent:
-- log.warning("subscribed failed - unknown agent '%s'" %
-- self.agent_name)
-- return False
-- try:
-- trace.debug("Sending Subscribe to Agent (%s)" % self.agent_name)
-- agent._send_subscribe_req(query, self.get_address(), self.interval,
-- self.duration)
-- except SendError, e:
-- log.error(str(e))
-- return False
-- return True
--
-- def resubscribe(self):
-- agent = self.console.get_agent(self.agent_name)
-- if not agent:
-- log.warning("resubscribed failed - unknown agent '%s'",
-- self.agent_name)
-- return False
-- try:
-- trace.debug("Sending resubscribe to Agent %s", self.agent_name)
-- agent._send_resubscribe_req(self.get_address(),
-- self.agent_subscription_id)
-- except SendError, e:
-- log.error(str(e))
-- return False
-- return True
--
-- def deliver(self, msg):
-- """
-- """
-- opcode = msg.properties.get("qmf.opcode")
-- if (opcode == OpCode.subscribe_rsp):
--
-- error = msg.content.get("_error")
-- if error:
-- try:
-- e_map = QmfData.from_map(error)
-- except TypeError:
-- log.warning("Invalid QmfData map received: '%s'"
-- % str(error))
-- e_map = QmfData.create({"error":"Unknown error"})
-- sp = SubscribeParams(None, None, None, e_map)
-- else:
-- self.agent_subscription_id = msg.content.get("_subscription_id")
-- self.duration = msg.content.get("_duration", self.duration)
-- self.interval = msg.content.get("_interval", self.interval)
-- self.reset_timeout(self.duration)
-- sp = SubscribeParams(self.get_address(),
-- self.interval,
-- self.duration,
-- None)
-- self.cv.acquire()
-- try:
-- self.data.append(sp)
-- # if was empty, notify waiters
-- if len(self.data) == 1:
-- self.cv.notify()
-- finally:
-- self.cv.release()
-- return
--
-- # else: data indication
-- agent_name = msg.properties.get("qmf.agent")
-- if not agent_name:
-- log.warning("Ignoring data_ind - no agent name given: %s" %
-- msg)
-- return
-- agent = self.console.get_agent(agent_name)
-- if not agent:
-- log.warning("Ignoring data_ind - unknown agent '%s'" %
-- agent_name)
-- return
--
-- objects = msg.content
-- for obj_map in objects:
-- obj = QmfConsoleData(map_=obj_map, agent=agent)
-- # start fetch of schema if not known
-- sid = obj.get_schema_class_id()
-- if sid:
-- self.console._prefetch_schema(sid, agent)
-- self.result.append(obj)
--
-- if not "partial" in msg.properties:
-- wi = WorkItem(WorkItem.SUBSCRIBE_INDICATION, self.context, self.result)
-- self.result = []
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- def fetch(self, timeout=None):
-- """
-- Get one data item from a mailbox, with timeout.
-- Invoked by application thread.
-- """
-- self.cv.acquire()
-- try:
-- if len(self.data) == 0:
-- self.cv.wait(timeout)
-- if len(self.data):
-- return self.data.pop(0)
-- return None
-- finally:
-- self.cv.release()
--
-- def expire(self):
-- """ The subscription expired.
-- """
-- self.destroy()
--
--
--
--
--class _AsyncSubscriptionMailbox(_SubscriptionMailbox):
-- """
-- A Mailbox for a single subscription. Allows only asychronous "subscribe"
-- and "refresh" requests.
-- """
-- def __init__(self, console, context, agent, duration, interval):
-- """
-- Invoked by application thread.
-- """
-- super(_AsyncSubscriptionMailbox, self).__init__(console, context,
-- agent, duration,
-- interval)
-- self.subscribe_pending = False
--
-- def subscribe(self, query, reply_timeout):
-- if super(_AsyncSubscriptionMailbox, self).subscribe(query):
-- self.subscribe_pending = True
-- self.reset_timeout(reply_timeout)
-- return True
-- return False
--
-- def deliver(self, msg):
-- """
-- """
-- super(_AsyncSubscriptionMailbox, self).deliver(msg)
-- sp = self.fetch(0)
-- if sp and self.subscribe_pending:
-- wi = WorkItem(WorkItem.SUBSCRIBE_RESPONSE, self.context, sp)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
--
-- self.subscribe_pending = False
--
-- if not sp.succeeded():
-- self.destroy()
--
--
-- def expire(self):
-- """ Either the subscription expired, or a request timedout.
-- """
-- if self.subscribe_pending:
-- wi = WorkItem(WorkItem.SUBSCRIBE_RESPONSE, self.context, None)
-- self.console._work_q.put(wi)
-- self.console._work_q_put = True
-- self.destroy()
--
--
--##==============================================================================
--## DATA MODEL
--##==============================================================================
--
--
--class QmfConsoleData(QmfData):
-- """
-- Console's representation of an managed QmfData instance.
-- """
-- def __init__(self, map_, agent):
-- super(QmfConsoleData, self).__init__(_map=map_,
-- _const=True)
-- self._agent = agent
--
-- def get_timestamps(self):
-- """
-- Returns a list of timestamps describing the lifecycle of
-- the object. All timestamps are represented by the AMQP
-- timestamp type. [0] = time of last update from Agent,
-- [1] = creation timestamp
-- [2] = deletion timestamp, or zero if not
-- deleted.
-- """
-- return [self._utime, self._ctime, self._dtime]
--
-- def get_create_time(self):
-- """
-- returns the creation timestamp
-- """
-- return self._ctime
--
-- def get_update_time(self):
-- """
-- returns the update timestamp
-- """
-- return self._utime
--
-- def get_delete_time(self):
-- """
-- returns the deletion timestamp, or zero if not yet deleted.
-- """
-- return self._dtime
--
-- def is_deleted(self):
-- """
-- True if deletion timestamp not zero.
-- """
-- return self._dtime != long(0)
--
-- def refresh(self, _reply_handle=None, _timeout=None):
-- """
-- request that the Agent update the value of this object's
-- contents.
-- """
-- if _reply_handle is not None:
-- log.error(" ASYNC REFRESH TBD!!!")
-- return None
--
-- assert self._agent
-- assert self._agent._console
--
-- if _timeout is None:
-- _timeout = self._agent._console._reply_timeout
--
-- # create query to agent using this objects ID
-- query = QmfQuery.create_id_object(self.get_object_id(),
-- self.get_schema_class_id())
-- obj_list = self._agent._console.do_query(self._agent, query,
-- _timeout=_timeout)
-- if obj_list is None or len(obj_list) != 1:
-- return None
--
-- self._update(obj_list[0])
-- return self
--
--
-- def invoke_method(self, name, _in_args={}, _reply_handle=None,
-- _timeout=None):
-- """
-- Invoke the named method on this object.
-- """
-- assert self._agent
-- assert self._agent._console
--
-- oid = self.get_object_id()
-- if oid is None:
-- raise ValueError("Cannot invoke methods on unmanaged objects.")
--
-- if _timeout is None:
-- _timeout = self._agent._console._reply_timeout
--
-- if _reply_handle is not None:
-- mbox = _MethodMailbox(self._agent._console,
-- _reply_handle)
-- else:
-- mbox = _SyncMailbox(self._agent._console)
-- cid = mbox.get_address()
--
-- _map = {self.KEY_OBJECT_ID:str(oid),
-- SchemaMethod.KEY_NAME:name}
--
-- sid = self.get_schema_class_id()
-- if sid:
-- _map[self.KEY_SCHEMA_ID] = sid.map_encode()
-- if _in_args:
-- _map[SchemaMethod.KEY_ARGUMENTS] = _in_args
--
-- trace.debug("Sending method req to Agent (%s)" % time.time())
-- try:
-- self._agent._send_method_req(_map, cid)
-- except SendError, e:
-- log.error(str(e))
-- mbox.destroy()
-- return None
--
-- if _reply_handle is not None:
-- return True
--
-- trace.debug("Waiting for response to method req (%s)" % _timeout)
-- replyMsg = mbox.fetch(_timeout)
-- mbox.destroy()
--
-- if not replyMsg:
-- trace.debug("Agent method req wait timed-out.")
-- return None
--
-- _map = replyMsg.content
-- if not _map or not isinstance(_map, type({})):
-- log.error("Invalid method call reply message")
-- return None
--
-- error=_map.get(SchemaMethod.KEY_ERROR)
-- if error:
-- return MethodResult(_error=QmfData.from_map(error))
-- else:
-- return MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS))
--
-- def _update(self, newer):
-- super(QmfConsoleData,self).__init__(_values=newer._values, _subtypes=newer._subtypes,
-- _tag=newer._tag, _object_id=newer._object_id,
-- _ctime=newer._ctime, _utime=newer._utime,
-- _dtime=newer._dtime,
-- _schema_id=newer._schema_id, _const=True)
--
--class QmfLocalData(QmfData):
-- """
-- Console's representation of an unmanaged QmfData instance. There
-- is no remote agent associated with this instance. The Console has
-- full control over this instance.
-- """
-- def __init__(self, values, _subtypes={}, _tag=None, _object_id=None,
-- _schema=None):
-- # timestamp in millisec since epoch UTC
-- ctime = long(time.time() * 1000)
-- super(QmfLocalData, self).__init__(_values=values,
-- _subtypes=_subtypes, _tag=_tag,
-- _object_id=_object_id,
-- _schema=_schema, _ctime=ctime,
-- _utime=ctime, _const=False)
--
--
--class Agent(object):
-- """
-- A local representation of a remote agent managed by this console.
-- """
-- def __init__(self, name, console):
-- """
-- @type name: string
-- @param name: uniquely identifies this agent in the AMQP domain.
-- """
--
-- if not isinstance(console, Console):
-- raise TypeError("parameter must be an instance of class Console")
--
-- self._name = name
-- self._address = QmfAddress.direct(name, console._domain)
-- self._console = console
-- self._sender = None
-- self._packages = {} # map of {package-name:[list of class-names], } for this agent
-- self._subscriptions = [] # list of active standing subscriptions for this agent
-- self._announce_timestamp = None # datetime when last announce received
-- trace.debug( "Created Agent with address: [%s]" % self._address )
--
--
-- def get_name(self):
-- return self._name
--
-- def is_active(self):
-- return self._announce_timestamp != None
--
-- def _send_msg(self, msg, correlation_id=None):
-- """
-- Low-level routine to asynchronously send a message to this agent.
-- """
-- msg.reply_to = str(self._console._address)
-- if correlation_id:
-- msg.correlation_id = str(correlation_id)
-- # TRACE
-- #log.error("!!! Console %s sending to agent %s (%s)" %
-- # (self._console._name, self._name, str(msg)))
-- self._sender.send(msg)
-- # return handle
--
-- def get_packages(self):
-- """
-- Return a list of the names of all packages known to this agent.
-- """
-- return self._packages.keys()
--
-- def get_classes(self):
-- """
-- Return a dictionary [key:class] of classes known to this agent.
-- """
-- return self._packages.copy()
--
-- def get_objects(self, query, kwargs={}):
-- """
-- Return a list of objects that satisfy the given query.
--
-- @type query: dict, or common.Query
-- @param query: filter for requested objects
-- @type kwargs: dict
-- @param kwargs: ??? used to build match selector and query ???
-- @rtype: list
-- @return: list of matching objects, or None.
-- """
-- pass
--
-- def get_object(self, query, kwargs={}):
-- """
-- Get one object - query is expected to match only one object.
-- ??? Recommended: explicit timeout param, default None ???
--
-- @type query: dict, or common.Query
-- @param query: filter for requested objects
-- @type kwargs: dict
-- @param kwargs: ??? used to build match selector and query ???
-- @rtype: qmfConsole.ObjectProxy
-- @return: one matching object, or none
-- """
-- pass
--
--
-- def create_subscription(self, query):
-- """
-- Factory for creating standing subscriptions based on a given query.
--
-- @type query: common.Query object
-- @param query: determines the list of objects for which this subscription applies
-- @rtype: qmfConsole.Subscription
-- @returns: an object representing the standing subscription.
-- """
-- pass
--
--
-- def invoke_method(self, name, _in_args={}, _reply_handle=None,
-- _timeout=None):
-- """
-- Invoke the named method on this agent.
-- """
-- assert self._console
--
-- if _timeout is None:
-- _timeout = self._console._reply_timeout
--
-- if _reply_handle is not None:
-- mbox = _MethodMailbox(self._console,
-- _reply_handle)
-- else:
-- mbox = _SyncMailbox(self._console)
-- cid = mbox.get_address()
--
-- _map = {SchemaMethod.KEY_NAME:name}
-- if _in_args:
-- _map[SchemaMethod.KEY_ARGUMENTS] = _in_args.copy()
--
-- trace.debug("Sending method req to Agent (%s)" % time.time())
-- try:
-- self._send_method_req(_map, cid)
-- except SendError, e:
-- log.error(str(e))
-- mbox.destroy()
-- return None
--
-- if _reply_handle is not None:
-- return True
--
-- trace.debug("Waiting for response to method req (%s)" % _timeout)
-- replyMsg = mbox.fetch(_timeout)
-- mbox.destroy()
--
-- if not replyMsg:
-- trace.debug("Agent method req wait timed-out.")
-- return None
--
-- _map = replyMsg.content
-- if not _map or not isinstance(_map, type({})):
-- log.error("Invalid method call reply message")
-- return None
--
-- return MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS),
-- _error=_map.get(SchemaMethod.KEY_ERROR))
--
-- def enable_events(self):
-- raise Exception("enable_events tbd")
--
-- def disable_events(self):
-- raise Exception("disable_events tbd")
--
-- def destroy(self):
-- raise Exception("destroy tbd")
--
-- def __repr__(self):
-- return str(self._address)
--
-- def __str__(self):
-- return self.__repr__()
--
-- def _send_query(self, query, correlation_id=None):
-- """
-- """
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.query_req},
-- content=query.map_encode())
-- self._send_msg( msg, correlation_id )
--
--
-- def _send_method_req(self, mr_map, correlation_id=None):
-- """
-- """
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.method_req},
-- content=mr_map)
-- self._send_msg( msg, correlation_id )
--
-- def _send_subscribe_req(self, query, correlation_id, _interval=None,
-- _lifetime=None):
-- """
-- """
-- sr_map = {"_query":query.map_encode()}
-- if _interval is not None:
-- sr_map["_interval"] = _interval
-- if _lifetime is not None:
-- sr_map["_duration"] = _lifetime
--
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.subscribe_req},
-- content=sr_map)
-- self._send_msg(msg, correlation_id)
--
--
-- def _send_resubscribe_req(self, correlation_id,
-- subscription_id):
-- """
-- """
-- sr_map = {"_subscription_id":subscription_id}
--
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.subscribe_refresh_ind},
-- content=sr_map)
-- self._send_msg(msg, correlation_id)
--
--
-- def _send_unsubscribe_ind(self, correlation_id, subscription_id):
-- """
-- """
-- sr_map = {"_subscription_id":subscription_id}
--
-- msg = Message(id=QMF_APP_ID,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.subscribe_cancel_ind},
-- content=sr_map)
-- self._send_msg(msg, correlation_id)
--
--
-- ##==============================================================================
-- ## METHOD CALL
-- ##==============================================================================
--
--class MethodResult(object):
-- def __init__(self, _out_args=None, _error=None):
-- self._error = _error
-- self._out_args = _out_args
--
-- def succeeded(self):
-- return self._error is None
--
-- def get_exception(self):
-- return self._error
--
-- def get_arguments(self):
-- return self._out_args
--
-- def get_argument(self, name):
-- arg = None
-- if self._out_args:
-- arg = self._out_args.get(name)
-- return arg
--
--
--
-- ##==============================================================================
-- ## SUBSCRIPTION
-- ##==============================================================================
--
--class SubscribeParams(object):
-- """ Represents a standing subscription for this console.
-- """
-- def __init__(self, sid, interval, duration, _error=None):
-- self._sid = sid
-- self._interval = interval
-- self._duration = duration
-- self._error = _error
--
-- def succeeded(self):
-- return self._error is None
--
-- def get_error(self):
-- return self._error
--
-- def get_subscription_id(self):
-- return self._sid
--
-- def get_publish_interval(self):
-- return self._interval
--
-- def get_duration(self):
-- return self._duration
--
--
-- ##==============================================================================
-- ## CONSOLE
-- ##==============================================================================
--
--
--
--
--
--
--class Console(Thread):
-- """
-- A Console manages communications to a collection of agents on behalf of an application.
-- """
-- def __init__(self, name=None, _domain=None, notifier=None,
-- reply_timeout = 60,
-- # agent_timeout = 120,
-- agent_timeout = 60,
-- kwargs={}):
-- """
-- @type name: str
-- @param name: identifier for this console. Must be unique.
-- @type notifier: qmfConsole.Notifier
-- @param notifier: invoked when events arrive for processing.
-- @type kwargs: dict
-- @param kwargs: ??? Unused
-- """
-- Thread.__init__(self)
-- self._operational = False
-- self._ready = Event()
--
-- if not name:
-- self._name = "qmfc-%s.%d" % (platform.node(), os.getpid())
-- else:
-- self._name = str(name)
-- self._domain = _domain
-- self._address = QmfAddress.direct(self._name, self._domain)
-- self._notifier = notifier
-- self._lock = RLock()
-- self._conn = None
-- self._session = None
-- # dict of "agent-direct-address":class Agent entries
-- self._agent_map = {}
-- self._direct_recvr = None
-- self._announce_recvr = None
-- self._locate_sender = None
-- self._schema_cache = {}
-- self._pending_schema_req = []
-- self._agent_discovery_filter = None
-- self._reply_timeout = reply_timeout
-- self._agent_timeout = agent_timeout
-- self._subscribe_timeout = 300 # @todo: parameterize
-- self._next_agent_expire = None
-- self._next_mbox_expire = None
-- # for passing WorkItems to the application
-- self._work_q = Queue.Queue()
-- self._work_q_put = False
-- # Correlation ID and mailbox storage
-- self._correlation_id = long(time.time()) # pseudo-randomize
-- self._post_office = {} # indexed by cid
-- self._async_mboxes = {} # indexed by cid, used to expire them
--
-- def destroy(self, timeout=None):
-- """
-- Must be called before the Console is deleted.
-- Frees up all resources and shuts down all background threads.
--
-- @type timeout: float
-- @param timeout: maximum time in seconds to wait for all background threads to terminate. Default: forever.
-- """
-- trace.debug("Destroying Console...")
-- if self._conn:
-- self.remove_connection(self._conn, timeout)
-- trace.debug("Console Destroyed")
--
-- def add_connection(self, conn):
-- """
-- Add a AMQP connection to the console. The console will setup a session over the
-- connection. The console will then broadcast an Agent Locate Indication over
-- the session in order to discover present agents.
--
-- @type conn: qpid.messaging.Connection
-- @param conn: the connection to the AMQP messaging infrastructure.
-- """
-- if self._conn:
-- raise Exception( "Multiple connections per Console not supported." );
-- self._conn = conn
-- self._session = conn.session(name=self._name)
--
-- # for messages directly addressed to me
-- self._direct_recvr = self._session.receiver(str(self._address) +
-- ";{create:always,"
-- " node:"
-- " {type:topic,"
-- " x-declare:"
-- " {type:direct}}}",
-- capacity=1)
-- trace.debug("my direct addr=%s" % self._direct_recvr.source)
--
-- self._direct_sender = self._session.sender(str(self._address.get_node()) +
-- ";{create:always,"
-- " node:"
-- " {type:topic,"
-- " x-declare:"
-- " {type:direct}}}")
-- trace.debug("my direct sender=%s" % self._direct_sender.target)
--
-- # for receiving "broadcast" messages from agents
-- default_addr = QmfAddress.topic(QmfAddress.SUBJECT_AGENT_IND + ".#",
-- self._domain)
-- self._topic_recvr = self._session.receiver(str(default_addr) +
-- ";{create:always,"
-- " node:{type:topic}}",
-- capacity=1)
-- trace.debug("default topic recv addr=%s" % self._topic_recvr.source)
--
--
-- # for sending to topic subscribers
-- topic_addr = QmfAddress.topic(QmfAddress.SUBJECT_CONSOLE_IND, self._domain)
-- self._topic_sender = self._session.sender(str(topic_addr) +
-- ";{create:always,"
-- " node:{type:topic}}")
-- trace.debug("default topic send addr=%s" % self._topic_sender.target)
--
-- #
-- # Now that receivers are created, fire off the receive thread...
-- #
-- self._operational = True
-- self.start()
-- self._ready.wait(10)
-- if not self._ready.isSet():
-- raise Exception("Console managment thread failed to start.")
--
--
--
-- def remove_connection(self, conn, timeout=None):
-- """
-- Remove an AMQP connection from the console. Un-does the add_connection() operation,
-- and releases any agents and sessions associated with the connection.
--
-- @type conn: qpid.messaging.Connection
-- @param conn: connection previously added by add_connection()
-- """
-- if self._conn and conn and conn != self._conn:
-- log.error( "Attempt to delete unknown connection: %s" % str(conn))
--
-- # tell connection thread to shutdown
-- self._operational = False
-- if self.isAlive():
-- # kick my thread to wake it up
-- self._wake_thread()
-- trace.debug("waiting for console receiver thread to exit")
-- self.join(timeout)
-- if self.isAlive():
-- log.error( "Console thread '%s' is hung..." % self.getName() )
-- self._direct_recvr.close()
-- self._direct_sender.close()
-- self._topic_recvr.close()
-- self._topic_sender.close()
-- self._session.close()
-- self._session = None
-- self._conn = None
-- trace.debug("console connection removal complete")
--
--
-- def get_address(self):
-- """
-- The AMQP address this Console is listening to.
-- """
-- return self._address
--
--
-- def destroy_agent( self, agent ):
-- """
-- Undoes create.
-- """
-- if not isinstance(agent, Agent):
-- raise TypeError("agent must be an instance of class Agent")
--
-- self._lock.acquire()
-- try:
-- if agent._name in self._agent_map:
-- del self._agent_map[agent._name]
-- finally:
-- self._lock.release()
--
-- def find_agent(self, name, timeout=None ):
-- """
-- Given the name of a particular agent, return an instance of class Agent
-- representing that agent. Return None if the agent does not exist.
-- """
--
-- self._lock.acquire()
-- try:
-- agent = self._agent_map.get(name)
-- if agent:
-- return agent
-- finally:
-- self._lock.release()
--
-- # agent not present yet - ping it with an agent_locate
--
-- mbox = _SyncMailbox(self)
-- cid = mbox.get_address()
--
-- query = QmfQuery.create_id(QmfQuery.TARGET_AGENT, name)
-- msg = Message(id=QMF_APP_ID,
-- subject="console.ind.locate." + name,
-- properties={"method":"request",
-- "qmf.opcode":OpCode.agent_locate_req},
-- content=query._predicate)
-- msg.content_type="amqp/list"
-- msg.reply_to = str(self._address)
-- msg.correlation_id = str(cid)
-- trace.debug("%s Sending Agent Locate (%s)", self._name, str(msg))
-- try:
-- self._topic_sender.send(msg)
-- except SendError, e:
-- log.error(str(e))
-- mbox.destroy()
-- return None
--
-- if timeout is None:
-- timeout = self._reply_timeout
--
-- new_agent = None
-- trace.debug("Waiting for response to Agent Locate (%s)" % timeout)
-- mbox.fetch(timeout)
-- mbox.destroy()
-- trace.debug("Agent Locate wait ended (%s)" % time.time())
-- self._lock.acquire()
-- try:
-- new_agent = self._agent_map.get(name)
-- finally:
-- self._lock.release()
--
-- return new_agent
--
--
-- def get_agents(self):
-- """
-- Return the list of known agents.
-- """
-- self._lock.acquire()
-- try:
-- agents = self._agent_map.values()
-- finally:
-- self._lock.release()
-- return agents
--
--
-- def get_agent(self, name):
-- """
-- Return the named agent, else None if not currently available.
-- """
-- self._lock.acquire()
-- try:
-- agent = self._agent_map.get(name)
-- finally:
-- self._lock.release()
-- return agent
--
--
-- def do_query(self, agent, query, _reply_handle=None, _timeout=None ):
-- """
-- """
-- target = query.get_target()
--
-- if _reply_handle is not None:
-- mbox = _QueryMailbox(self,
-- agent.get_name(),
-- _reply_handle,
-- target,
-- _timeout)
-- else:
-- mbox = _SyncMailbox(self)
--
-- cid = mbox.get_address()
--
-- try:
-- trace.debug("Sending Query to Agent (%s)" % time.time())
-- agent._send_query(query, cid)
-- except SendError, e:
-- log.error(str(e))
-- mbox.destroy()
-- return None
--
-- # return now if async reply expected
-- if _reply_handle is not None:
-- return True
--
-- if not _timeout:
-- _timeout = self._reply_timeout
--
-- trace.debug("Waiting for response to Query (%s)" % _timeout)
-- now = datetime.datetime.utcnow()
-- expire = now + datetime.timedelta(seconds=_timeout)
--
-- response = []
-- while (expire > now):
-- _timeout = timedelta_to_secs(expire - now)
-- reply = mbox.fetch(_timeout)
-- if not reply:
-- trace.debug("Query wait timed-out.")
-- break
--
-- objects = reply.content
-- if not objects or not isinstance(objects, type([])):
-- break
--
-- # convert from map to native types if needed
-- if target == QmfQuery.TARGET_SCHEMA_ID:
-- for sid_map in objects:
-- response.append(SchemaClassId.from_map(sid_map))
--
-- elif target == QmfQuery.TARGET_SCHEMA:
-- for schema_map in objects:
-- # extract schema id, convert based on schema type
-- sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID)
-- if sid_map:
-- sid = SchemaClassId.from_map(sid_map)
-- if sid:
-- if sid.get_type() == SchemaClassId.TYPE_DATA:
-- schema = SchemaObjectClass.from_map(schema_map)
-- else:
-- schema = SchemaEventClass.from_map(schema_map)
-- self._add_schema(schema) # add to schema cache
-- response.append(schema)
--
-- elif target == QmfQuery.TARGET_OBJECT:
-- for obj_map in objects:
-- obj = QmfConsoleData(map_=obj_map, agent=agent)
-- # start fetch of schema if not known
-- sid = obj.get_schema_class_id()
-- if sid:
-- self._prefetch_schema(sid, agent)
-- response.append(obj)
-- else:
-- # no conversion needed.
-- response += objects
--
-- if not "partial" in reply.properties:
-- # reply not broken up over multiple msgs
-- break
--
-- now = datetime.datetime.utcnow()
--
-- mbox.destroy()
-- return response
--
--
-- def create_subscription(self, agent, query, console_handle,
-- _interval=None, _duration=None,
-- _blocking=True, _timeout=None):
-- if not _duration:
-- _duration = self._subscribe_timeout
--
-- if _timeout is None:
-- _timeout = self._reply_timeout
--
-- if not _blocking:
-- mbox = _AsyncSubscriptionMailbox(self, console_handle, agent,
-- _duration, _interval)
-- if not mbox.subscribe(query, _timeout):
-- mbox.destroy()
-- return False
-- return True
-- else:
-- mbox = _SubscriptionMailbox(self, console_handle, agent, _duration,
-- _interval)
--
-- if not mbox.subscribe(query):
-- mbox.destroy()
-- return None
--
-- trace.debug("Waiting for response to subscription (%s)" % _timeout)
-- # @todo: what if mbox expires here?
-- sp = mbox.fetch(_timeout)
--
-- if not sp:
-- trace.debug("Subscription request wait timed-out.")
-- mbox.destroy()
-- return None
--
-- if not sp.succeeded():
-- mbox.destroy()
--
-- return sp
--
-- def refresh_subscription(self, subscription_id,
-- _duration=None,
-- _timeout=None):
-- if _timeout is None:
-- _timeout = self._reply_timeout
--
-- mbox = self._get_mailbox(subscription_id)
-- if not mbox:
-- log.warning("Subscription %s not found." % subscription_id)
-- return None
--
-- if isinstance(mbox, _AsyncSubscriptionMailbox):
-- return mbox.resubscribe()
-- else:
-- # synchronous - wait for reply
-- if not mbox.resubscribe():
-- # @todo ???? mbox.destroy()
-- return None
--
-- # wait for reply
--
-- trace.debug("Waiting for response to subscription (%s)" % _timeout)
-- sp = mbox.fetch(_timeout)
--
-- if not sp:
-- trace.debug("re-subscribe request wait timed-out.")
-- # @todo???? mbox.destroy()
-- return None
--
-- return sp
--
--
-- def cancel_subscription(self, subscription_id):
-- """
-- """
-- mbox = self._get_mailbox(subscription_id)
-- if not mbox:
-- return
--
-- agent = self.get_agent(mbox.agent_name)
-- if agent:
-- try:
-- trace.debug("Sending UnSubscribe to Agent (%s)" % time.time())
-- agent._send_unsubscribe_ind(subscription_id,
-- mbox.agent_subscription_id)
-- except SendError, e:
-- log.error(str(e))
--
-- mbox.destroy()
--
--
-- def _wake_thread(self):
-- """
-- Make the console management thread loop wakeup from its next_receiver
-- sleep.
-- """
-- trace.debug("Sending noop to wake up [%s]" % self._address)
-- msg = Message(id=QMF_APP_ID,
-- subject=self._name,
-- properties={"method":"indication",
-- "qmf.opcode":OpCode.noop},
-- content={})
-- try:
-- self._direct_sender.send( msg, sync=True )
-- except SendError, e:
-- log.error(str(e))
--
--
-- def run(self):
-- """
-- Console Management Thread main loop.
-- Handles inbound messages, agent discovery, async mailbox timeouts.
-- """
-- global _callback_thread
--
-- self._ready.set()
--
-- while self._operational:
--
-- # qLen = self._work_q.qsize()
--
-- while True:
-- try:
-- msg = self._topic_recvr.fetch(timeout=0)
-- except Empty:
-- break
-- # TRACE:
-- # log.error("!!! Console %s: msg on %s [%s]" %
-- # (self._name, self._topic_recvr.source, msg))
-- self._dispatch(msg, _direct=False)
--
-- while True:
-- try:
-- msg = self._direct_recvr.fetch(timeout = 0)
-- except Empty:
-- break
-- # TRACE
-- #log.error("!!! Console %s: msg on %s [%s]" %
-- # (self._name, self._direct_recvr.source, msg))
-- self._dispatch(msg, _direct=True)
--
-- self._expire_agents() # check for expired agents
-- self._expire_mboxes() # check for expired async mailbox requests
--
-- #if qLen == 0 and self._work_q.qsize() and self._notifier:
-- if self._work_q_put and self._notifier:
-- # new stuff on work queue, kick the the application...
-- self._work_q_put = False
-- _callback_thread = currentThread()
-- trace.debug("Calling console notifier.indication")
-- self._notifier.indication()
-- _callback_thread = None
--
--
-- # wait for a message to arrive, or an agent
-- # to expire, or a mailbox requrest to time out
-- now = datetime.datetime.utcnow()
-- next_expire = self._next_agent_expire
--
-- self._lock.acquire()
-- try:
-- # the mailbox expire flag may be cleared by the
-- # app thread(s) to force an immedate mailbox scan
-- if self._next_mbox_expire is None:
-- next_expire = now
-- elif self._next_mbox_expire < next_expire:
-- next_expire = self._next_mbox_expire
-- finally:
-- self._lock.release()
--
-- timeout = timedelta_to_secs(next_expire - now)
--
-- if self._operational and timeout > 0.0:
-- try:
-- trace.debug("waiting for next rcvr (timeout=%s)..." % timeout)
-- self._session.next_receiver(timeout = timeout)
-- except Empty:
-- pass
--
-- trace.debug("Shutting down Console thread")
--
-- def get_objects(self,
-- _object_id=None,
-- _schema_id=None,
-- _pname=None, _cname=None,
-- _agents=None,
-- _timeout=None):
-- """
-- Retrieve objects by id or schema.
--
-- By object_id: must specify schema_id or pname & cname if object defined
-- by a schema. Undescribed objects: only object_id needed.
--
-- By schema: must specify schema_id or pname & cname - all instances of
-- objects defined by that schema are returned.
-- """
-- if _agents is None:
-- # use copy of current agent list
-- self._lock.acquire()
-- try:
-- agent_list = self._agent_map.values()
-- finally:
-- self._lock.release()
-- elif isinstance(_agents, Agent):
-- agent_list = [_agents]
-- else:
-- agent_list = _agents
-- # @todo validate this list!
--
-- if _timeout is None:
-- _timeout = self._reply_timeout
--
-- # @todo: fix when async do_query done - query all agents at once, then
-- # wait for replies, instead of per-agent querying....
--
-- obj_list = []
-- expired = datetime.datetime.utcnow() + datetime.timedelta(seconds=_timeout)
-- for agent in agent_list:
-- if not agent.is_active():
-- continue
-- now = datetime.datetime.utcnow()
-- if now >= expired:
-- break
--
-- if _pname is None:
-- if _object_id:
-- query = QmfQuery.create_id_object(_object_id,
-- _schema_id)
-- else:
-- if _schema_id is not None:
-- t_params = {QmfData.KEY_SCHEMA_ID: _schema_id}
-- else:
-- t_params = None
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT,
-- t_params)
-- timeout = timedelta_to_secs(expired - now)
-- reply = self.do_query(agent, query, _timeout=timeout)
-- if reply:
-- obj_list = obj_list + reply
-- else:
-- # looking up by package name (and maybe class name), need to
-- # find all schema_ids in that package, then lookup object by
-- # schema_id
-- if _cname is not None:
-- pred = [QmfQuery.AND,
-- [QmfQuery.EQ,
-- SchemaClassId.KEY_PACKAGE,
-- [QmfQuery.QUOTE, _pname]],
-- [QmfQuery.EQ, SchemaClassId.KEY_CLASS,
-- [QmfQuery.QUOTE, _cname]]]
-- else:
-- pred = [QmfQuery.EQ,
-- SchemaClassId.KEY_PACKAGE,
-- [QmfQuery.QUOTE, _pname]]
-- query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID, pred)
-- timeout = timedelta_to_secs(expired - now)
-- sid_list = self.do_query(agent, query, _timeout=timeout)
-- if sid_list:
-- for sid in sid_list:
-- now = datetime.datetime.utcnow()
-- if now >= expired:
-- break
-- if _object_id is not None:
-- query = QmfQuery.create_id_object(_object_id, sid)
-- else:
-- t_params = {QmfData.KEY_SCHEMA_ID: sid}
-- query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, t_params)
-- timeout = timedelta_to_secs(expired - now)
-- reply = self.do_query(agent, query, _timeout=timeout)
-- if reply:
-- obj_list = obj_list + reply
-- if obj_list:
-- return obj_list
-- return None
--
--
--
-- # called by run() thread ONLY
-- #
-- def _dispatch(self, msg, _direct=True):
-- """
-- PRIVATE: Process a message received from an Agent
-- """
-- trace.debug( "Message received from Agent! [%s]", msg )
--
-- opcode = msg.properties.get("qmf.opcode")
-- if not opcode:
-- log.error("Ignoring unrecognized message '%s'", msg)
-- return
-- version = 2 # @todo: fix me
--
-- cmap = {}; props = {}
-- if msg.content_type == "amqp/map":
-- cmap = msg.content
-- if msg.properties:
-- props = msg.properties
--
-- if opcode == OpCode.agent_heartbeat_ind:
-- self._handle_agent_ind_msg( msg, cmap, version, _direct )
-- elif opcode == OpCode.agent_locate_rsp:
-- self._handle_agent_ind_msg( msg, cmap, version, _direct )
-- elif msg.correlation_id:
-- self._handle_response_msg(msg, cmap, version, _direct)
-- elif opcode == OpCode.data_ind:
-- self._handle_indication_msg(msg, cmap, version, _direct)
-- elif opcode == OpCode.noop:
-- trace.debug("No-op msg received.")
-- else:
-- log.warning("Ignoring message with unrecognized 'opcode' value: '%s'", opcode)
--
--
-- def _handle_agent_ind_msg(self, msg, cmap, version, direct):
-- """
-- Process a received agent-ind message. This message may be a response to a
-- agent-locate, or it can be an unsolicited agent announce.
-- """
--
-- trace.debug("%s _handle_agent_ind_msg '%s'", self._name, str(msg))
--
-- try:
-- tmp = QmfData.from_map(msg.content)
-- except:
-- log.warning("%s invalid Agent Indication msg format '%s'",
-- self._name, str(msg))
-- return
--
-- try:
-- name = tmp.get_value("_name")
-- except:
-- log.warning("Bad Agent ind msg received: %s", str(msg))
-- return
--
-- correlated = False
-- if msg.correlation_id:
-- mbox = self._get_mailbox(msg.correlation_id)
-- correlated = mbox is not None
--
-- agent = None
-- self._lock.acquire()
-- try:
-- agent = self._agent_map.get(name)
-- if agent:
-- # agent already known, just update timestamp
-- agent._announce_timestamp = datetime.datetime.utcnow()
-- finally:
-- self._lock.release()
--
-- if not agent:
-- # need to create and add a new agent?
-- matched = False
-- if self._agent_discovery_filter:
-- matched = self._agent_discovery_filter.evaluate(tmp)
--
-- if (correlated or matched):
-- agent = self._create_agent(name)
-- if not agent:
-- return # failed to add agent
-- agent._announce_timestamp = datetime.datetime.utcnow()
--
-- if matched:
-- # unsolicited, but newly discovered
-- trace.debug("AGENT_ADDED for %s (%s)" % (agent, time.time()))
-- wi = WorkItem(WorkItem.AGENT_ADDED, None, {"agent": agent})
-- self._work_q.put(wi)
-- self._work_q_put = True
--
-- if correlated:
-- # wake up all waiters
-- trace.debug("waking waiters for correlation id %s" % msg.correlation_id)
-- mbox.deliver(msg)
--
-- def _handle_response_msg(self, msg, cmap, version, direct):
-- """
-- Process a received data-ind message.
-- """
-- trace.debug("%s _handle_response_msg '%s'", self._name, str(msg))
--
-- mbox = self._get_mailbox(msg.correlation_id)
-- if not mbox:
-- log.warning("%s Response msg received with unknown correlation_id"
-- " msg='%s'", self._name, str(msg))
-- return
--
-- # wake up all waiters
-- trace.debug("waking waiters for correlation id %s" % msg.correlation_id)
-- mbox.deliver(msg)
--
-- def _handle_indication_msg(self, msg, cmap, version, _direct):
--
-- aname = msg.properties.get("qmf.agent")
-- if not aname:
-- trace.debug("No agent name field in indication message.")
-- return
--
-- content_type = msg.properties.get("qmf.content")
-- if (content_type != ContentType.event or
-- not isinstance(msg.content, type([]))):
-- log.warning("Bad event indication message received: '%s'", msg)
-- return
--
-- emap = msg.content[0]
-- if not isinstance(emap, type({})):
-- trace.debug("Invalid event body in indication message: '%s'", msg)
-- return
--
-- agent = None
-- self._lock.acquire()
-- try:
-- agent = self._agent_map.get(aname)
-- finally:
-- self._lock.release()
-- if not agent:
-- trace.debug("Agent '%s' not known." % aname)
-- return
-- try:
-- # @todo: schema???
-- event = QmfEvent.from_map(emap)
-- except TypeError:
-- trace.debug("Invalid QmfEvent map received: %s" % str(emap))
-- return
--
-- # @todo: schema? Need to fetch it, but not from this thread!
-- # This thread can not pend on a request.
-- trace.debug("Publishing event received from agent %s" % aname)
-- wi = WorkItem(WorkItem.EVENT_RECEIVED, None,
-- {"agent":agent,
-- "event":event})
-- self._work_q.put(wi)
-- self._work_q_put = True
--
--
-- def _expire_mboxes(self):
-- """
-- Check all async mailboxes for outstanding requests that have expired.
-- """
-- self._lock.acquire()
-- try:
-- now = datetime.datetime.utcnow()
-- if self._next_mbox_expire and now < self._next_mbox_expire:
-- return
-- expired_mboxes = []
-- self._next_mbox_expire = None
-- for mbox in self._async_mboxes.itervalues():
-- if now >= mbox.expiration_date:
-- expired_mboxes.append(mbox)
-- else:
-- if (self._next_mbox_expire is None or
-- mbox.expiration_date < self._next_mbox_expire):
-- self._next_mbox_expire = mbox.expiration_date
--
-- for mbox in expired_mboxes:
-- del self._async_mboxes[mbox.cid]
-- finally:
-- self._lock.release()
--
-- for mbox in expired_mboxes:
-- # note: expire() may deallocate the mbox, so don't touch
-- # it further.
-- mbox.expire()
--
--
-- def _expire_agents(self):
-- """
-- Check for expired agents and issue notifications when they expire.
-- """
-- now = datetime.datetime.utcnow()
-- if self._next_agent_expire and now < self._next_agent_expire:
-- return
-- lifetime_delta = datetime.timedelta(seconds = self._agent_timeout)
-- next_expire_delta = lifetime_delta
-- self._lock.acquire()
-- try:
-- trace.debug("!!! expiring agents '%s'" % now)
-- for agent in self._agent_map.itervalues():
-- if agent._announce_timestamp:
-- agent_deathtime = agent._announce_timestamp + lifetime_delta
-- if agent_deathtime <= now:
-- trace.debug("AGENT_DELETED for %s" % agent)
-- agent._announce_timestamp = None
-- wi = WorkItem(WorkItem.AGENT_DELETED, None,
-- {"agent":agent})
-- # @todo: remove agent from self._agent_map
-- self._work_q.put(wi)
-- self._work_q_put = True
-- else:
-- if (agent_deathtime - now) < next_expire_delta:
-- next_expire_delta = agent_deathtime - now
--
-- self._next_agent_expire = now + next_expire_delta
-- trace.debug("!!! next expire cycle = '%s'" % self._next_agent_expire)
-- finally:
-- self._lock.release()
--
--
--
-- def _create_agent( self, name ):
-- """
-- Factory to create/retrieve an agent for this console
-- """
-- trace.debug("creating agent %s" % name)
-- self._lock.acquire()
-- try:
-- agent = self._agent_map.get(name)
-- if agent:
-- return agent
--
-- agent = Agent(name, self)
-- try:
-- agent._sender = self._session.sender(str(agent._address) +
-- ";{create:always,"
-- " node:"
-- " {type:topic,"
-- " x-declare:"
-- " {type:direct}}}")
-- except:
-- log.warning("Unable to create sender for %s" % name)
-- return None
-- trace.debug("created agent sender %s" % agent._sender.target)
--
-- self._agent_map[name] = agent
-- finally:
-- self._lock.release()
--
-- # new agent - query for its schema database for
-- # seeding the schema cache (@todo)
-- # query = QmfQuery({QmfQuery.TARGET_SCHEMA_ID:None})
-- # agent._sendQuery( query )
--
-- return agent
--
--
--
-- def enable_agent_discovery(self, _query=None):
-- """
-- Called to enable the asynchronous Agent Discovery process.
-- Once enabled, AGENT_ADD work items can arrive on the WorkQueue.
-- """
-- # @todo: fix - take predicate only, not entire query!
-- if _query is not None:
-- if (not isinstance(_query, QmfQuery) or
-- _query.get_target() != QmfQuery.TARGET_AGENT):
-- raise TypeError("Type QmfQuery with target == TARGET_AGENT expected")
-- self._agent_discovery_filter = _query
-- else:
-- # create a match-all agent query (no predicate)
-- self._agent_discovery_filter = QmfQuery.create_wildcard(QmfQuery.TARGET_AGENT)
--
-- def disable_agent_discovery(self):
-- """
-- Called to disable the async Agent Discovery process enabled by
-- calling enableAgentDiscovery()
-- """
-- self._agent_discovery_filter = None
--
--
--
-- def get_workitem_count(self):
-- """
-- Returns the count of pending WorkItems that can be retrieved.
-- """
-- return self._work_q.qsize()
--
--
--
-- def get_next_workitem(self, timeout=None):
-- """
-- Returns the next pending work item, or None if none available.
-- @todo: subclass and return an Empty event instead.
-- """
-- try:
-- wi = self._work_q.get(True, timeout)
-- except Queue.Empty:
-- return None
-- return wi
--
--
-- def release_workitem(self, wi):
-- """
-- Return a WorkItem to the Console when it is no longer needed.
-- @todo: call Queue.task_done() - only 2.5+
--
-- @type wi: class qmfConsole.WorkItem
-- @param wi: work item object to return.
-- """
-- pass
--
-- def _add_schema(self, schema):
-- """
-- @todo
-- """
-- if not isinstance(schema, SchemaClass):
-- raise TypeError("SchemaClass type expected")
--
-- self._lock.acquire()
-- try:
-- sid = schema.get_class_id()
-- if not self._schema_cache.has_key(sid):
-- self._schema_cache[sid] = schema
-- if sid in self._pending_schema_req:
-- self._pending_schema_req.remove(sid)
-- finally:
-- self._lock.release()
--
-- def _prefetch_schema(self, schema_id, agent):
-- """
-- Send an async request for the schema identified by schema_id if the
-- schema is not available in the cache.
-- """
-- need_fetch = False
-- self._lock.acquire()
-- try:
-- if ((not self._schema_cache.has_key(schema_id)) and
-- schema_id not in self._pending_schema_req):
-- self._pending_schema_req.append(schema_id)
-- need_fetch = True
-- finally:
-- self._lock.release()
--
-- if need_fetch:
-- mbox = _SchemaPrefetchMailbox(self, schema_id)
-- query = QmfQuery.create_id(QmfQuery.TARGET_SCHEMA, schema_id)
-- trace.debug("Sending Schema Query to Agent (%s)" % time.time())
-- try:
-- agent._send_query(query, mbox.get_address())
-- except SendError, e:
-- log.error(str(e))
-- mbox.destroy()
-- self._lock.acquire()
-- try:
-- self._pending_schema_req.remove(schema_id)
-- finally:
-- self._lock.release()
--
--
-- def _fetch_schema(self, schema_id, _agent=None, _timeout=None):
-- """
-- Find the schema identified by schema_id. If not in the cache, ask the
-- agent for it.
-- """
-- if not isinstance(schema_id, SchemaClassId):
-- raise TypeError("SchemaClassId type expected")
--
-- self._lock.acquire()
-- try:
-- schema = self._schema_cache.get(schema_id)
-- if schema:
-- return schema
-- finally:
-- self._lock.release()
--
-- if _agent is None:
-- return None
--
-- # note: do_query will add the new schema to the cache automatically.
-- slist = self.do_query(_agent,
-- QmfQuery.create_id(QmfQuery.TARGET_SCHEMA, schema_id),
-- _timeout=_timeout)
-- if slist:
-- return slist[0]
-- else:
-- return None
--
-- def _add_mailbox(self, mbox):
-- """
-- Add a mailbox to the post office, and assign it a unique address.
-- """
-- self._lock.acquire()
-- try:
-- mbox.cid = self._correlation_id
-- self._correlation_id += 1
-- self._post_office[mbox.cid] = mbox
-- finally:
-- self._lock.release()
--
-- def _get_mailbox(self, mid):
-- try:
-- mid = long(mid)
-- except TypeError:
-- log.error("Invalid mailbox id: %s" % str(mid))
-- return None
--
-- self._lock.acquire()
-- try:
-- return self._post_office.get(mid)
-- finally:
-- self._lock.release()
--
--
-- def _remove_mailbox(self, mid):
-- """ Remove a mailbox and its address from the post office """
-- try:
-- mid = long(mid)
-- except TypeError:
-- log.error("Invalid mailbox id: %s" % str(mid))
-- return None
--
-- self._lock.acquire()
-- try:
-- if mid in self._post_office:
-- del self._post_office[mid]
-- finally:
-- self._lock.release()
--
-- def __repr__(self):
-- return str(self._address)
--
-- # def get_packages(self):
-- # plist = []
-- # for i in range(self.impl.packageCount()):
-- # plist.append(self.impl.getPackageName(i))
-- # return plist
--
--
-- # def get_classes(self, package, kind=CLASS_OBJECT):
-- # clist = []
-- # for i in range(self.impl.classCount(package)):
-- # key = self.impl.getClass(package, i)
-- # class_kind = self.impl.getClassKind(key)
-- # if class_kind == kind:
-- # if kind == CLASS_OBJECT:
-- # clist.append(SchemaObjectClass(None, None, {"impl":self.impl.getObjectClass(key)}))
-- # elif kind == CLASS_EVENT:
-- # clist.append(SchemaEventClass(None, None, {"impl":self.impl.getEventClass(key)}))
-- # return clist
--
--
-- # def bind_package(self, package):
-- # return self.impl.bindPackage(package)
--
--
-- # def bind_class(self, kwargs = {}):
-- # if "key" in kwargs:
-- # self.impl.bindClass(kwargs["key"])
-- # elif "package" in kwargs:
-- # package = kwargs["package"]
-- # if "class" in kwargs:
-- # self.impl.bindClass(package, kwargs["class"])
-- # else:
-- # self.impl.bindClass(package)
-- # else:
-- # raise Exception("Argument error: invalid arguments, use 'key' or 'package'[,'class']")
--
--
-- # def get_agents(self, broker=None):
-- # blist = []
-- # if broker:
-- # blist.append(broker)
-- # else:
-- # self._cv.acquire()
-- # try:
-- # # copy while holding lock
-- # blist = self._broker_list[:]
-- # finally:
-- # self._cv.release()
--
-- # agents = []
-- # for b in blist:
-- # for idx in range(b.impl.agentCount()):
-- # agents.append(AgentProxy(b.impl.getAgent(idx), b))
--
-- # return agents
--
--
-- # def get_objects(self, query, kwargs = {}):
-- # timeout = 30
-- # agent = None
-- # temp_args = kwargs.copy()
-- # if type(query) == type({}):
-- # temp_args.update(query)
--
-- # if "_timeout" in temp_args:
-- # timeout = temp_args["_timeout"]
-- # temp_args.pop("_timeout")
--
-- # if "_agent" in temp_args:
-- # agent = temp_args["_agent"]
-- # temp_args.pop("_agent")
--
-- # if type(query) == type({}):
-- # query = Query(temp_args)
--
-- # self._select = {}
-- # for k in temp_args.iterkeys():
-- # if type(k) == str:
-- # self._select[k] = temp_args[k]
--
-- # self._cv.acquire()
-- # try:
-- # self._sync_count = 1
-- # self._sync_result = []
-- # broker = self._broker_list[0]
-- # broker.send_query(query.impl, None, agent)
-- # self._cv.wait(timeout)
-- # if self._sync_count == 1:
-- # raise Exception("Timed out: waiting for query response")
-- # finally:
-- # self._cv.release()
--
-- # return self._sync_result
--
--
-- # def get_object(self, query, kwargs = {}):
-- # '''
-- # Return one and only one object or None.
-- # '''
-- # objs = objects(query, kwargs)
-- # if len(objs) == 1:
-- # return objs[0]
-- # else:
-- # return None
--
--
-- # def first_object(self, query, kwargs = {}):
-- # '''
-- # Return the first of potentially many objects.
-- # '''
-- # objs = objects(query, kwargs)
-- # if objs:
-- # return objs[0]
-- # else:
-- # return None
--
--
-- # # Check the object against select to check for a match
-- # def _select_match(self, object):
-- # schema_props = object.properties()
-- # for key in self._select.iterkeys():
-- # for prop in schema_props:
-- # if key == p[0].name() and self._select[key] != p[1]:
-- # return False
-- # return True
--
--
-- # def _get_result(self, list, context):
-- # '''
-- # Called by Broker proxy to return the result of a query.
-- # '''
-- # self._cv.acquire()
-- # try:
-- # for item in list:
-- # if self._select_match(item):
-- # self._sync_result.append(item)
-- # self._sync_count -= 1
-- # self._cv.notify()
-- # finally:
-- # self._cv.release()
--
--
-- # def start_sync(self, query): pass
--
--
-- # def touch_sync(self, sync): pass
--
--
-- # def end_sync(self, sync): pass
--
--
--
--
--# def start_console_events(self):
--# self._cb_cond.acquire()
--# try:
--# self._cb_cond.notify()
--# finally:
--# self._cb_cond.release()
--
--
--# def _do_console_events(self):
--# '''
--# Called by the Console thread to poll for events. Passes the events
--# onto the ConsoleHandler associated with this Console. Is called
--# periodically, but can also be kicked by Console.start_console_events().
--# '''
--# count = 0
--# valid = self.impl.getEvent(self._event)
--# while valid:
--# count += 1
--# try:
--# if self._event.kind == qmfengine.ConsoleEvent.AGENT_ADDED:
--# trace.debug("Console Event AGENT_ADDED received")
--# if self._handler:
--# self._handler.agent_added(AgentProxy(self._event.agent, None))
--# elif self._event.kind == qmfengine.ConsoleEvent.AGENT_DELETED:
--# trace.debug("Console Event AGENT_DELETED received")
--# if self._handler:
--# self._handler.agent_deleted(AgentProxy(self._event.agent, None))
--# elif self._event.kind == qmfengine.ConsoleEvent.NEW_PACKAGE:
--# trace.debug("Console Event NEW_PACKAGE received")
--# if self._handler:
--# self._handler.new_package(self._event.name)
--# elif self._event.kind == qmfengine.ConsoleEvent.NEW_CLASS:
--# trace.debug("Console Event NEW_CLASS received")
--# if self._handler:
--# self._handler.new_class(SchemaClassKey(self._event.classKey))
--# elif self._event.kind == qmfengine.ConsoleEvent.OBJECT_UPDATE:
--# trace.debug("Console Event OBJECT_UPDATE received")
--# if self._handler:
--# self._handler.object_update(ConsoleObject(None, {"impl":self._event.object}),
--# self._event.hasProps, self._event.hasStats)
--# elif self._event.kind == qmfengine.ConsoleEvent.EVENT_RECEIVED:
--# trace.debug("Console Event EVENT_RECEIVED received")
--# elif self._event.kind == qmfengine.ConsoleEvent.AGENT_HEARTBEAT:
--# trace.debug("Console Event AGENT_HEARTBEAT received")
--# if self._handler:
--# self._handler.agent_heartbeat(AgentProxy(self._event.agent, None), self._event.timestamp)
--# elif self._event.kind == qmfengine.ConsoleEvent.METHOD_RESPONSE:
--# trace.debug("Console Event METHOD_RESPONSE received")
--# else:
--# trace.debug("Console thread received unknown event: '%s'" % str(self._event.kind))
--# except e:
--# print "Exception caught in callback thread:", e
--# self.impl.popEvent()
--# valid = self.impl.getEvent(self._event)
--# return count
--
--
--
--
--
--# class Broker(ConnectionHandler):
--# # attr_reader :impl :conn, :console, :broker_bank
--# def __init__(self, console, conn):
--# self.broker_bank = 1
--# self.console = console
--# self.conn = conn
--# self._session = None
--# self._cv = Condition()
--# self._stable = None
--# self._event = qmfengine.BrokerEvent()
--# self._xmtMessage = qmfengine.Message()
--# self.impl = qmfengine.BrokerProxy(self.console.impl)
--# self.console.impl.addConnection(self.impl, self)
--# self.conn.add_conn_handler(self)
--# self._operational = True
--
--
--# def shutdown(self):
--# trace.debug("broker.shutdown() called.")
--# self.console.impl.delConnection(self.impl)
--# self.conn.del_conn_handler(self)
--# if self._session:
--# self.impl.sessionClosed()
--# trace.debug("broker.shutdown() sessionClosed done.")
--# self._session.destroy()
--# trace.debug("broker.shutdown() session destroy done.")
--# self._session = None
--# self._operational = False
--# trace.debug("broker.shutdown() done.")
--
--
--# def wait_for_stable(self, timeout = None):
--# self._cv.acquire()
--# try:
--# if self._stable:
--# return
--# if timeout:
--# self._cv.wait(timeout)
--# if not self._stable:
--# raise Exception("Timed out: waiting for broker connection to become stable")
--# else:
--# while not self._stable:
--# self._cv.wait()
--# finally:
--# self._cv.release()
--
--
--# def send_query(self, query, ctx, agent):
--# agent_impl = None
--# if agent:
--# agent_impl = agent.impl
--# self.impl.sendQuery(query, ctx, agent_impl)
--# self.conn.kick()
--
--
--# def _do_broker_events(self):
--# count = 0
--# valid = self.impl.getEvent(self._event)
--# while valid:
--# count += 1
--# if self._event.kind == qmfengine.BrokerEvent.BROKER_INFO:
--# trace.debug("Broker Event BROKER_INFO received");
--# elif self._event.kind == qmfengine.BrokerEvent.DECLARE_QUEUE:
--# trace.debug("Broker Event DECLARE_QUEUE received");
--# self.conn.impl.declareQueue(self._session.handle, self._event.name)
--# elif self._event.kind == qmfengine.BrokerEvent.DELETE_QUEUE:
--# trace.debug("Broker Event DELETE_QUEUE received");
--# self.conn.impl.deleteQueue(self._session.handle, self._event.name)
--# elif self._event.kind == qmfengine.BrokerEvent.BIND:
--# trace.debug("Broker Event BIND received");
--# self.conn.impl.bind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
--# elif self._event.kind == qmfengine.BrokerEvent.UNBIND:
--# trace.debug("Broker Event UNBIND received");
--# self.conn.impl.unbind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
--# elif self._event.kind == qmfengine.BrokerEvent.SETUP_COMPLETE:
--# trace.debug("Broker Event SETUP_COMPLETE received");
--# self.impl.startProtocol()
--# elif self._event.kind == qmfengine.BrokerEvent.STABLE:
--# trace.debug("Broker Event STABLE received");
--# self._cv.acquire()
--# try:
--# self._stable = True
--# self._cv.notify()
--# finally:
--# self._cv.release()
--# elif self._event.kind == qmfengine.BrokerEvent.QUERY_COMPLETE:
--# result = []
--# for idx in range(self._event.queryResponse.getObjectCount()):
--# result.append(ConsoleObject(None, {"impl":self._event.queryResponse.getObject(idx), "broker":self}))
--# self.console._get_result(result, self._event.context)
--# elif self._event.kind == qmfengine.BrokerEvent.METHOD_RESPONSE:
--# obj = self._event.context
--# obj._method_result(MethodResponse(self._event.methodResponse()))
--
--# self.impl.popEvent()
--# valid = self.impl.getEvent(self._event)
--
--# return count
--
--
--# def _do_broker_messages(self):
--# count = 0
--# valid = self.impl.getXmtMessage(self._xmtMessage)
--# while valid:
--# count += 1
--# trace.debug("Broker: sending msg on connection")
--# self.conn.impl.sendMessage(self._session.handle, self._xmtMessage)
--# self.impl.popXmt()
--# valid = self.impl.getXmtMessage(self._xmtMessage)
--
--# return count
--
--
--# def _do_events(self):
--# while True:
--# self.console.start_console_events()
--# bcnt = self._do_broker_events()
--# mcnt = self._do_broker_messages()
--# if bcnt == 0 and mcnt == 0:
--# break;
--
--
--# def conn_event_connected(self):
--# trace.debug("Broker: Connection event CONNECTED")
--# self._session = Session(self.conn, "qmfc-%s.%d" % (socket.gethostname(), os.getpid()), self)
--# self.impl.sessionOpened(self._session.handle)
--# self._do_events()
--
--
--# def conn_event_disconnected(self, error):
--# trace.debug("Broker: Connection event DISCONNECTED")
--# pass
--
--
--# def conn_event_visit(self):
--# self._do_events()
--
--
--# def sess_event_session_closed(self, context, error):
--# trace.debug("Broker: Session event CLOSED")
--# self.impl.sessionClosed()
--
--
--# def sess_event_recv(self, context, message):
--# trace.debug("Broker: Session event MSG_RECV")
--# if not self._operational:
--# log.warning("Unexpected session event message received by Broker proxy: context='%s'" % str(context))
--# self.impl.handleRcvMessage(message)
--# self._do_events()
--
--
--
--################################################################################
--################################################################################
--################################################################################
--################################################################################
--# TEMPORARY TEST CODE - TO BE DELETED
--################################################################################
--################################################################################
--################################################################################
--################################################################################
--
--if __name__ == '__main__':
-- # temp test code
-- import logging
-- from common import (qmfTypes, SchemaProperty)
--
-- logging.getLogger().setLevel(logging.INFO)
--
-- logging.info( "************* Creating Async Console **************" )
--
-- class MyNotifier(Notifier):
-- def __init__(self, context):
-- self._myContext = context
-- self.WorkAvailable = False
--
-- def indication(self):
-- print("Indication received! context=%d" % self._myContext)
-- self.WorkAvailable = True
--
-- _noteMe = MyNotifier( 666 )
--
-- _myConsole = Console(notifier=_noteMe)
--
-- _myConsole.enable_agent_discovery()
-- logging.info("Waiting...")
--
--
-- logging.info( "Destroying console:" )
-- _myConsole.destroy( 10 )
--
-- logging.info( "******** Messing around with Schema ********" )
--
-- _sec = SchemaEventClass( _classId=SchemaClassId("myPackage", "myClass",
-- stype=SchemaClassId.TYPE_EVENT),
-- _desc="A typical event schema",
-- _props={"Argument-1": SchemaProperty(_type_code=qmfTypes.TYPE_UINT8,
-- kwargs = {"min":0,
-- "max":100,
-- "unit":"seconds",
-- "desc":"sleep value"}),
-- "Argument-2": SchemaProperty(_type_code=qmfTypes.TYPE_LSTR,
-- kwargs={"maxlen":100,
-- "desc":"a string argument"})})
-- print("_sec=%s" % _sec.get_class_id())
-- print("_sec.gePropertyCount()=%d" % _sec.get_property_count() )
-- print("_sec.getProperty('Argument-1`)=%s" % _sec.get_property('Argument-1') )
-- print("_sec.getProperty('Argument-2`)=%s" % _sec.get_property('Argument-2') )
-- try:
-- print("_sec.getProperty('not-found')=%s" % _sec.get_property('not-found') )
-- except:
-- pass
-- print("_sec.getProperties()='%s'" % _sec.get_properties())
--
-- print("Adding another argument")
-- _arg3 = SchemaProperty( _type_code=qmfTypes.TYPE_BOOL,
-- kwargs={"dir":"IO",
-- "desc":"a boolean argument"})
-- _sec.add_property('Argument-3', _arg3)
-- print("_sec=%s" % _sec.get_class_id())
-- print("_sec.getPropertyCount()=%d" % _sec.get_property_count() )
-- print("_sec.getProperty('Argument-1')=%s" % _sec.get_property('Argument-1') )
-- print("_sec.getProperty('Argument-2')=%s" % _sec.get_property('Argument-2') )
-- print("_sec.getProperty('Argument-3')=%s" % _sec.get_property('Argument-3') )
--
-- print("_arg3.mapEncode()='%s'" % _arg3.map_encode() )
--
-- _secmap = _sec.map_encode()
-- print("_sec.mapEncode()='%s'" % _secmap )
--
-- _sec2 = SchemaEventClass( _map=_secmap )
--
-- print("_sec=%s" % _sec.get_class_id())
-- print("_sec2=%s" % _sec2.get_class_id())
--
-- _soc = SchemaObjectClass( _map = {"_schema_id": {"_package_name": "myOtherPackage",
-- "_class_name": "myOtherClass",
-- "_type": "_data"},
-- "_desc": "A test data object",
-- "_values":
-- {"prop1": {"amqp_type": qmfTypes.TYPE_UINT8,
-- "access": "RO",
-- "index": True,
-- "unit": "degrees"},
-- "prop2": {"amqp_type": qmfTypes.TYPE_UINT8,
-- "access": "RW",
-- "index": True,
-- "desc": "The Second Property(tm)",
-- "unit": "radians"},
-- "statistics": { "amqp_type": qmfTypes.TYPE_DELTATIME,
-- "unit": "seconds",
-- "desc": "time until I retire"},
-- "meth1": {"_desc": "A test method",
-- "_arguments":
-- {"arg1": {"amqp_type": qmfTypes.TYPE_UINT32,
-- "desc": "an argument 1",
-- "dir": "I"},
-- "arg2": {"amqp_type": qmfTypes.TYPE_BOOL,
-- "dir": "IO",
-- "desc": "some weird boolean"}}},
-- "meth2": {"_desc": "A test method",
-- "_arguments":
-- {"m2arg1": {"amqp_type": qmfTypes.TYPE_UINT32,
-- "desc": "an 'nuther argument",
-- "dir":
-- "I"}}}},
-- "_subtypes":
-- {"prop1":"qmfProperty",
-- "prop2":"qmfProperty",
-- "statistics":"qmfProperty",
-- "meth1":"qmfMethod",
-- "meth2":"qmfMethod"},
-- "_primary_key_names": ["prop2", "prop1"]})
--
-- print("_soc='%s'" % _soc)
--
-- print("_soc.getPrimaryKeyList='%s'" % _soc.get_id_names())
--
-- print("_soc.getPropertyCount='%d'" % _soc.get_property_count())
-- print("_soc.getProperties='%s'" % _soc.get_properties())
-- print("_soc.getProperty('prop2')='%s'" % _soc.get_property('prop2'))
--
-- print("_soc.getMethodCount='%d'" % _soc.get_method_count())
-- print("_soc.getMethods='%s'" % _soc.get_methods())
-- print("_soc.getMethod('meth2')='%s'" % _soc.get_method('meth2'))
--
-- _socmap = _soc.map_encode()
-- print("_socmap='%s'" % _socmap)
-- _soc2 = SchemaObjectClass( _map=_socmap )
-- print("_soc='%s'" % _soc)
-- print("_soc2='%s'" % _soc2)
--
-- if _soc2.get_class_id() == _soc.get_class_id():
-- print("soc and soc2 are the same schema")
--
--
-- logging.info( "******** Messing around with ObjectIds ********" )
--
--
-- qd = QmfData( _values={"prop1":1, "prop2":True, "prop3": {"a":"map"}, "prop4": "astring"} )
-- print("qd='%s':" % qd)
--
-- print("prop1=%d prop2=%s prop3=%s prop4=%s" % (qd.prop1, qd.prop2, qd.prop3, qd.prop4))
--
-- print("qd map='%s'" % qd.map_encode())
-- print("qd getProperty('prop4')='%s'" % qd.get_value("prop4"))
-- qd.set_value("prop4", 4, "A test property called 4")
-- print("qd setProperty('prop4', 4)='%s'" % qd.get_value("prop4"))
-- qd.prop4 = 9
-- print("qd.prop4 = 9 ='%s'" % qd.prop4)
-- qd["prop4"] = 11
-- print("qd[prop4] = 11 ='%s'" % qd["prop4"])
--
-- print("qd.mapEncode()='%s'" % qd.map_encode())
-- _qd2 = QmfData( _map = qd.map_encode() )
-- print("_qd2.mapEncode()='%s'" % _qd2.map_encode())
--
-- _qmfDesc1 = QmfConsoleData( {"_values" : {"prop1": 1, "statistics": 666,
-- "prop2": 0}},
-- agent="some agent name?",
-- _schema = _soc)
--
-- print("_qmfDesc1 map='%s'" % _qmfDesc1.map_encode())
--
-- _qmfDesc1._set_schema( _soc )
--
-- print("_qmfDesc1 prop2 = '%s'" % _qmfDesc1.get_value("prop2"))
-- print("_qmfDesc1 primarykey = '%s'" % _qmfDesc1.get_object_id())
-- print("_qmfDesc1 classid = '%s'" % _qmfDesc1.get_schema_class_id())
--
--
-- _qmfDescMap = _qmfDesc1.map_encode()
-- print("_qmfDescMap='%s'" % _qmfDescMap)
--
-- _qmfDesc2 = QmfData( _map=_qmfDescMap, _schema=_soc )
--
-- print("_qmfDesc2 map='%s'" % _qmfDesc2.map_encode())
-- print("_qmfDesc2 prop2 = '%s'" % _qmfDesc2.get_value("prop2"))
-- print("_qmfDesc2 primary key = '%s'" % _qmfDesc2.get_object_id())
--
--
-- logging.info( "******** Messing around with QmfEvents ********" )
--
--
-- _qmfevent1 = QmfEvent( _timestamp = 1111,
-- _schema = _sec,
-- _values = {"Argument-1": 77,
-- "Argument-3": True,
-- "Argument-2": "a string"})
-- print("_qmfevent1.mapEncode()='%s'" % _qmfevent1.map_encode())
-- print("_qmfevent1.getTimestamp()='%s'" % _qmfevent1.get_timestamp())
--
-- _qmfevent1Map = _qmfevent1.map_encode()
--
-- _qmfevent2 = QmfEvent(_map=_qmfevent1Map, _schema=_sec)
-- print("_qmfevent2.mapEncode()='%s'" % _qmfevent2.map_encode())
--
--
-- logging.info( "******** Messing around with Queries ********" )
--
-- _q1 = QmfQuery.create_predicate(QmfQuery.TARGET_AGENT,
-- [QmfQuery.AND,
-- [QmfQuery.EQ, "vendor", [QmfQuery.QUOTE, "AVendor"]],
-- [QmfQuery.EQ, [QmfQuery.QUOTE, "SomeProduct"], "product"],
-- [QmfQuery.EQ, [QmfQuery.UNQUOTE, "name"], [QmfQuery.QUOTE, "Thingy"]],
-- [QmfQuery.OR,
-- [QmfQuery.LE, "temperature", -10],
-- [QmfQuery.FALSE],
-- [QmfQuery.EXISTS, "namey"]]])
--
-- print("_q1.mapEncode() = [%s]" % _q1.map_encode())
-Index: extras/qmf/setup.py
-===================================================================
---- extras/qmf/setup.py (revision 1056407)
-+++ extras/qmf/setup.py (working copy)
-@@ -23,7 +23,7 @@
- version="0.8",
- author="Apache Qpid",
- author_email="dev at qpid.apache.org",
-- packages=["qmf", "qmf2", "qmf2.tests"],
-+ packages=["qmf"],
- package_dir={"": "src/py"},
- url="http://qpid.apache.org/",
- license="Apache Software License",
-Index: cpp/src/qpid/framing/SendContent.h
-===================================================================
---- cpp/src/qpid/framing/SendContent.h 2009-03-12 16:55:34.000000000 -0400
-+++ cpp/src/qpid/framing/SendContent.h 2011-02-07 16:12:01.949172798 -0500
-@@ -37,7 +37,7 @@
- */
- class SendContent
- {
-- mutable FrameHandler& handler;
-+ FrameHandler& handler;
- const uint16_t maxFrameSize;
- uint expectedFrameCount;
- uint frameCount;
+--
+1.7.4.4
+
+From caec0216a72bf1c6bd8094b03337f0181f5ba07d Mon Sep 17 00:00:00 2001
+From: Ted Ross <tross at redhat.com>
+Date: Tue, 20 Sep 2011 11:09:10 -0400
+Subject: [PATCH 12/14] In CMake build, only build the posix event notifier
+ (qmf2) for linux, not Windows.
+
+---
+ qpid/cpp/src/CMakeLists.txt | 16 +++++++++++++---
+ 1 files changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
+index 2986a90..0be42b8 100644
+--- a/qpid/cpp/src/CMakeLists.txt
++++ b/qpid/cpp/src/CMakeLists.txt
+@@ -1093,7 +1093,6 @@ install_pdb (qmf ${QPID_COMPONENT_QMF})
+ ../include/qmf/exceptions.h
+ ../include/qmf/Handle.h
+ ../include/qmf/ImportExport.h
+- ../include/qmf/posix/EventNotifier.h
+ ../include/qmf/Query.h
+ ../include/qmf/Schema.h
+ ../include/qmf/SchemaId.h
+@@ -1125,8 +1124,6 @@ install_pdb (qmf ${QPID_COMPONENT_QMF})
+ qmf/DataImpl.h
+ qmf/EventNotifierImpl.h
+ qmf/EventNotifierImpl.cpp
+- qmf/PosixEventNotifier.cpp
+- qmf/PosixEventNotifierImpl.cpp
+ qmf/exceptions.cpp
+ qmf/Expression.cpp
+ qmf/Expression.h
+@@ -1149,6 +1146,19 @@ install_pdb (qmf ${QPID_COMPONENT_QMF})
+ qmf/SubscriptionImpl.h
+ )
+
++if(NOT WIN32)
++ set (qmf2_HEADERS
++ ${qmf2_HEADERS}
++ ../include/qmf/posix/EventNotifier.h
++ )
++
++ set (qmf2_SOURCES
++ ${qmf2_SOURCES}
++ qmf/PosixEventNotifier.cpp
++ qmf/PosixEventNotifierImpl.cpp
++ )
++endif (NOT WIN32)
++
+ add_msvc_version (qmf2 library dll)
+ add_library (qmf2 SHARED ${qmf2_SOURCES})
+ target_link_libraries (qmf2 qpidmessaging qpidtypes qpidclient qpidcommon)
+--
+1.7.4.4
+
+From 258294f134d42cf131e2bcbcb5d77482664efece Mon Sep 17 00:00:00 2001
+From: Nuno Santos <nsantos at apache.org>
+Date: Thu, 8 Sep 2011 20:45:33 +0000
+Subject: [PATCH 13/14] QPID-3437: qpid-config address option confusing in
+ help
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1166897 13f79535-47bb-0310-9956-ffa450edef68
+(cherry picked from commit 3ee5b3a8b77426987bff6b65f147b27a99b027c3)
+---
+ qpid/tools/src/py/qpid-config | 7 +------
+ 1 files changed, 1 insertions(+), 6 deletions(-)
+
+diff --git a/qpid/tools/src/py/qpid-config b/qpid/tools/src/py/qpid-config
+index b6eb055..4ed1ea7 100755
+--- a/qpid/tools/src/py/qpid-config
++++ b/qpid/tools/src/py/qpid-config
+@@ -39,11 +39,6 @@ Usage: qpid-config [OPTIONS]
+ qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]"""
+
+ description = """
+-ADDRESS syntax:
+-
+- [username/password@] hostname [:<port>]
+- [username/password@] ip-address [:<port>]
+-
+ Examples:
+
+ $ qpid-config add queue q
+@@ -159,7 +154,7 @@ def OptionsAndArguments(argv):
+ group1 = OptionGroup(parser, "General Options")
+ group1.add_option("-t", "--timeout", action="store", type="int", default=10, metavar="<secs>", help="Maximum time to wait for broker connection (in seconds)")
+ group1.add_option("-b", "--bindings", action="store_true", help="Show bindings in queue or exchange list")
+- group1.add_option("-a", "--broker-addr", action="store", type="string", default="localhost:5672", metavar="<address>", help="Address of qpidd broker")
++ group1.add_option("-a", "--broker-addr", action="store", type="string", default="localhost:5672", metavar="<address>", help="Address of qpidd broker with syntax: [username/password@] hostname | ip-address [:<port>]")
+ group1.add_option("--sasl-mechanism", action="store", type="string", metavar="<mech>", 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_group(group1)
+
+--
+1.7.4.4
+
+From 0b178e6d01d6a3c67fa55086394cf53132909cce Mon Sep 17 00:00:00 2001
+From: Nuno Santos <nsantos at apache.org>
+Date: Thu, 8 Sep 2011 20:27:49 +0000
+Subject: [PATCH 14/14] make 'qpid-config queues/exchanges
+ <queue/exchange_name>' return proper error code, for
+ scripting purposes
+
+git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1166888 13f79535-47bb-0310-9956-ffa450edef68
+(cherry picked from commit 7d5bce20c5ca6bc3869cbe2f6a73f1968c7a5abb)
+---
+ qpid/tools/src/py/qpid-config | 18 ++++++++++++++++--
+ 1 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/qpid/tools/src/py/qpid-config b/qpid/tools/src/py/qpid-config
+index 4ed1ea7..4af3c84 100755
+--- a/qpid/tools/src/py/qpid-config
++++ b/qpid/tools/src/py/qpid-config
+@@ -97,6 +97,7 @@ class Config:
+ self._flowStopSize = None
+ self._flowResumeSize = None
+ self._extra_arguments = []
++ self._returnCode = 0
+
+ config = Config()
+
+@@ -354,9 +355,16 @@ class BrokerManager:
+ caption1 = "Type "
+ caption2 = "Exchange Name"
+ maxNameLen = len(caption2)
++ found = False
+ for ex in exchanges:
+ if self.match(ex.name, filter):
+ if len(ex.name) > maxNameLen: maxNameLen = len(ex.name)
++ found = True
++ if not found:
++ global config
++ config._returnCode = 1
++ return
++
+ print "%s%-*s Attributes" % (caption1, maxNameLen, caption2)
+ line = ""
+ for i in range(((maxNameLen + len(caption1)) / 5) + 5):
+@@ -393,12 +401,18 @@ class BrokerManager:
+
+ def QueueList(self, filter):
+ queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
+-
+ caption = "Queue Name"
+ maxNameLen = len(caption)
++ found = False
+ for q in queues:
+ if self.match(q.name, filter):
+ if len(q.name) > maxNameLen: maxNameLen = len(q.name)
++ found = True
++ if not found:
++ global config
++ config._returnCode = 1
++ return
++
+ print "%-*s Attributes" % (maxNameLen, caption)
+ line = ""
+ for i in range((maxNameLen / 5) + 5):
+@@ -670,7 +684,7 @@ def main(argv=None):
+ print "Failed: %s: %s" % (e.__class__.__name__, e)
+ return 1
+
+- return 0
++ return config._returnCode
+
+ if __name__ == "__main__":
+ sys.exit(main())
+--
+1.7.4.4
+
diff --git a/qpid-cpp.spec b/qpid-cpp.spec
index f488537..9f4a60a 100644
--- a/qpid-cpp.spec
+++ b/qpid-cpp.spec
@@ -4,6 +4,7 @@
#
%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
+%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
%{!?ruby_sitelib: %global ruby_sitelib %(/usr/bin/ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"] ')}
%{!?ruby_sitearch: %global ruby_sitearch %(/usr/bin/ruby -rrbconfig -e 'puts Config::CONFIG["sitearchdir"] ')}
@@ -22,11 +23,11 @@
%global MRG_non_core 1
# Release numbers
-%global qpid_release 0.10
-%global qpid_svnrev 1091571
-%global store_svnrev 4446
+%global qpid_release 0.12
+%global qpid_svnrev 1154981
+%global store_svnrev 4463
# Change this release number for each build of the same qpid_svnrev, otherwise set back to 1.
-%global release_num 4
+%global release_num 2
# NOTE: these flags should not both be set at the same time!
# RHEL-6 builds should have all flags set to 0.
@@ -103,12 +104,9 @@ URL: http://qpid.apache.org
Source0: qpid-%{version}.tar.gz
Source1: store-%{qpid_release}.%{store_svnrev}.tar.gz
-Patch1: store-4411.patch
-
%if %{fedora}
-Patch2: qpid-3159.patch
-Patch6: boost_filesystem_v2.patch
-Patch7: mutable.patch
+Patch0: configure.patch
+Patch1: fedora.patch
%endif
%if %{rhel_4}
@@ -451,7 +449,7 @@ components.
%_libdir/libqmfengine.so
%_libdir/libqmfconsole.so
%_bindir/qmf-gen
-%{python_sitelib}/qmfgen
+%{python_sitearch}/qmfgen
%post -n qpid-qmf-devel
/sbin/ldconfig
@@ -479,14 +477,14 @@ for python.
%files -n python-qpid-qmf
%defattr(-,root,root,-)
%{python_sitelib}/qmf
-%{python_sitelib}/cqpid.py*
-%{python_sitelib}/_cqpid.so
-%{python_sitelib}/qmf.py*
-%{python_sitelib}/qmfengine.py*
-%{python_sitelib}/_qmfengine.so
-%{python_sitelib}/qmf2.py*
-%{python_sitelib}/cqmf2.py*
-%{python_sitelib}/_cqmf2.so
+%{python_sitearch}/cqpid.py*
+%{python_sitearch}/_cqpid.so
+%{python_sitearch}/qmf.py*
+%{python_sitearch}/qmfengine.py*
+%{python_sitearch}/_qmfengine.so
+%{python_sitearch}/qmf2.py*
+%{python_sitearch}/cqmf2.py*
+%{python_sitearch}/_cqmf2.so
%{_bindir}/qpid-python-test
%exclude %{python_sitelib}/mllib
%exclude %{python_sitelib}/qpid
@@ -734,9 +732,10 @@ with Berkeley DB.
%defattr(-,root,root,-)
%doc ../store-%{qpid_release}.%{store_svnrev}/README
%_libdir/qpid/daemon/msgstore.so*
-%_libexecdir/qpid/jerr.py*
-%_libexecdir/qpid/jrnl.py*
-%_libexecdir/qpid/janal.py*
+%{python_sitearch}/qpidstore/__init__.py*
+%{python_sitearch}/qpidstore/jerr.py*
+%{python_sitearch}/qpidstore/jrnl.py*
+%{python_sitearch}/qpidstore/janal.py*
%_libexecdir/qpid/resize
%_libexecdir/qpid/store_chk
%attr(0775,qpidd,qpidd) %dir %_localstatedir/rhm
@@ -842,16 +841,10 @@ popd
%endif
%if %{fedora}
-%patch2 -p2
-###%patch6
-%patch7
+%patch0 -p0
+%patch1 -p2
%endif
-# apply store patch
-pushd ../store-%{qpid_release}.%{store_svnrev}
-###%patch1
-popd
-
%global perftests "qpid-perftest qpid-topic-listener qpid-topic-publisher qpid-latency-test qpid-client-test qpid-txtest"
%global rh_qpid_tests_failover "failover_soak run_failover_soak"
@@ -865,7 +858,7 @@ pushd cpp
CXXFLAGS="%{optflags} -DNDEBUG -O3" \
%configure --disable-static --without-cpg --without-graphviz --without-help2man --without-rdma
%else
-CXXFLAGS="%{optflags} -DNDEBUG -O3" \
+CXXFLAGS="%{optflags} -DNDEBUG -O3 -Wno-unused-result" \
%configure --disable-static --with-cpg --without-graphviz --without-help2man --with-swig
%endif
ECHO=echo make %{LIB_VERSION_MAKE_PARAMS} %{?_smp_mflags}
@@ -990,13 +983,13 @@ rm -rf %{buildroot}%_datadir/qpidc/examples/xml-exchange
%if ! %{rhel_4}
%if %{python_qmf}
-install -d %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qpid/python/cqpid.py %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qpid/python/.libs/_cqpid.so %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf/python/*.py %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf/python/.libs/_qmfengine.so %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf2/python/*.py %{buildroot}%{python_sitelib}
-install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf2/python/.libs/_cqmf2.so %{buildroot}%{python_sitelib}
+install -d %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qpid/python/cqpid.py %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qpid/python/.libs/_cqpid.so %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf/python/*.py %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf/python/.libs/_qmfengine.so %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf2/python/*.py %{buildroot}%{python_sitearch}
+install -pm 644 %{_builddir}/qpid-%{version}/cpp/bindings/qmf2/python/.libs/_cqmf2.so %{buildroot}%{python_sitearch}
%endif
%if %{ruby_qmf}
@@ -1061,7 +1054,7 @@ rm -f %{buildroot}%_localstatedir/lib/qpidd/qpidd.sasldb
rm -rf %{buildroot}%_includedir/qmf
rm -rf %{buildroot}%_includedir/qpid
rm -rf %{buildroot}%_datadir/qpidc/examples/messaging
-rm -rf %{buildroot}%{python_sitelib}/qmfgen
+rm -rf %{buildroot}%{python_sitearch}/qmfgen
rm -f %{buildroot}%_bindir/qpid-perftest
rm -f %{buildroot}%_bindir/qpid-topic-listener
rm -f %{buildroot}%_bindir/qpid-topic-publisher
@@ -1083,7 +1076,7 @@ rm -f %{buildroot}%_libdir/libqpidcommon.so
#rm -rf %{buildroot}%_includedir/qmf
#rm -rf %{buildroot}%_includedir/qpid
#rm -rf %{buildroot}%_datadir/qpidc/examples/messaging
-#rm -rf %{buildroot}%{python_sitelib}/qmfgen
+#rm -rf %{buildroot}%{python_sitearch}/qmfgen
#rm -f %{buildroot}%_bindir/perftest
#rm -f %{buildroot}%_bindir/topic_listener
#rm -f %{buildroot}%_bindir/topic_publisher
@@ -1109,9 +1102,10 @@ rm -f %{buildroot}%_libdir/qpid/daemon/cluster.so
rm -f %{buildroot}%_libdir/qpid/daemon/msgstore.so
rm -f %{buildroot}%_libdir/qpid/daemon/ssl.so
rm -f %{buildroot}%_libdir/qpid/daemon/xml.so
-rm -f %{buildroot}%_libexecdir/qpid/jerr.py
-rm -f %{buildroot}%_libexecdir/qpid/jrnl.py
-rm -f %{buildroot}%_libexecdir/qpid/janal.py
+rm -f %{buildroot}%{python_sitearch}/qpidstore/__init__.py*
+rm -f %{buildroot}%{python_sitearch}/qpidstore/jerr.py
+rm -f %{buildroot}%{python_sitearch}/qpidstore/jrnl.py
+rm -f %{buildroot}%{python_sitearch}/qpidstore/janal.py
rm -f %{buildroot}%_libexecdir/qpid/resize
rm -f %{buildroot}%_libexecdir/qpid/store_chk
%endif
@@ -1147,6 +1141,12 @@ rm -rf %{buildroot}
%postun -p /sbin/ldconfig
%changelog
+* Tue Sep 20 2011 Nuno Santos <nsantos at nsantos-laptop> - 0.12-2.1
+- Updated patch for qmf-related issues fixed post-0.12
+
+* Tue Aug 30 2011 Nuno Santos <nsantos at redhat.com> - 0.12-1.1
+- Rebased to sync with upstream's official 0.12 release
+
* Sun Aug 14 2011 Rex Dieter <rdieter at fedoraproject.org> - 0.10-4.1
- Rebuilt for rpm (#728707)
diff --git a/sources b/sources
index bac7d79..8da7c8b 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-7b0e4a9a0a3e9681685ffec4bac64d16 store-0.10.4446.tar.gz
-75f7e1076fddc08baaee386f9af61897 qpid-0.10.tar.gz
+19eb7a39985aef1574ec2244a22204a4 qpid-0.12.tar.gz
+663a2fffe206ff218264f99000e29db4 store-0.12.4463.tar.gz
More information about the scm-commits
mailing list