diff options
| author | Andrew Stitcher <astitcher@apache.org> | 2013-03-04 21:08:45 +0000 |
|---|---|---|
| committer | Andrew Stitcher <astitcher@apache.org> | 2013-03-04 21:08:45 +0000 |
| commit | dfada942aa6795a44bcf6988fc300d0767c994e8 (patch) | |
| tree | 07e59fa97f4a2d3a83e1e5a06786101251439497 /cpp/src/qpid/broker/Selector.cpp | |
| parent | 5ebf2fd5b0e7ada7089437efa95e37c6f473fcfc (diff) | |
| download | qpid-python-dfada942aa6795a44bcf6988fc300d0767c994e8.tar.gz | |
QPID-4558: Selectors for C++ broker
- Added numeric and boolean values
* To literals and identifier values
* To the code that extracts values from message properties
- Added the full set of comparison operators
- Implemented full "unknown" semantics for all
operators.
- Implemented extended "is null" and "is not null" operators
that allow expressions as well as just identifiers.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1452525 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/qpid/broker/Selector.cpp')
| -rw-r--r-- | cpp/src/qpid/broker/Selector.cpp | 165 |
1 files changed, 104 insertions, 61 deletions
diff --git a/cpp/src/qpid/broker/Selector.cpp b/cpp/src/qpid/broker/Selector.cpp index 0880285692..62d2c43005 100644 --- a/cpp/src/qpid/broker/Selector.cpp +++ b/cpp/src/qpid/broker/Selector.cpp @@ -23,56 +23,23 @@ #include "qpid/broker/Message.h" #include "qpid/broker/SelectorExpression.h" +#include "qpid/broker/SelectorValue.h" #include "qpid/log/Statement.h" +#include "qpid/types/Variant.h" #include <string> #include <sstream> +#include "qpid/sys/unordered_map.h" #include <boost/make_shared.hpp> #include <boost/lexical_cast.hpp> +#include <boost/ptr_container/ptr_vector.hpp> namespace qpid { namespace broker { using std::string; - -Selector::Selector(const string& e) : - parse(parseTopBoolExpression(e)), - expression(e) -{ - bool debugOut; - QPID_LOG_TEST(debug, debugOut); - if (debugOut) { - std::stringstream ss; - parse->repr(ss); - QPID_LOG(debug, "Selector parsed[" << e << "] into: " << ss.str()); - } -} - -Selector::~Selector() -{ -} - -bool Selector::eval(const SelectorEnv& env) -{ - return parse->eval(env); -} - -bool Selector::filter(const Message& msg) -{ - return eval(MessageSelectorEnv(msg)); -} - -MessageSelectorEnv::MessageSelectorEnv(const Message& m) : - msg(m) -{ -} - -bool MessageSelectorEnv::present(const string& identifier) const -{ - // If the value we get is void then most likely the property wasn't present - return !msg.getProperty(identifier).isVoid(); -} +using qpid::sys::unordered_map; /** * Identifier (amqp.) | JMS... | amqp 1.0 equivalent @@ -89,48 +56,124 @@ bool MessageSelectorEnv::present(const string& identifier) const * creation_time | Timestamp | creation-time properties section * jms_type | Type | jms-type message-annotations section */ +const string EMPTY; +const string PERSISTENT("PERSISTENT"); +const string NON_PERSISTENT("NON_PERSISTENT"); -string specialValue(const Message& msg, const string& id) +const Value specialValue(const Message& msg, const string& id) { // TODO: Just use a simple if chain for now - improve this later if ( id=="delivery_mode" ) { - return msg.getEncoding().isPersistent() ? "PERSISTENT" : "NON_PERSISTENT"; + return msg.getEncoding().isPersistent() ? PERSISTENT : NON_PERSISTENT; } else if ( id=="redelivered" ) { - return msg.getDeliveryCount()>0 ? "TRUE" : "FALSE"; + return msg.getDeliveryCount()>0 ? true : false; } else if ( id=="priority" ) { - return boost::lexical_cast<string>(static_cast<uint32_t>(msg.getEncoding().getPriority())); + return int64_t(msg.getPriority()); } else if ( id=="correlation_id" ) { - return ""; // Needs an indirection in getEncoding(). + return EMPTY; // Needs an indirection in getEncoding(). } else if ( id=="message_id" ) { - return ""; // Needs an indirection in getEncoding(). + return EMPTY; // Needs an indirection in getEncoding(). } else if ( id=="to" ) { - return msg.getRoutingKey(); // This is good for 0-10, not sure about 1.0 + return EMPTY; // This is good for 0-10, not sure about 1.0 } else if ( id=="reply_to" ) { - return ""; // Needs an indirection in getEncoding(). + return EMPTY; // Needs an indirection in getEncoding(). } else if ( id=="absolute_expiry_time" ) { - return ""; // Needs an indirection in getEncoding(). + return EMPTY; // Needs an indirection in getEncoding(). } else if ( id=="creation_time" ) { - return ""; // Needs an indirection in getEncoding(). + return EMPTY; // Needs an indirection in getEncoding(). } else if ( id=="jms_type" ) { - return msg.getAnnotation("jms-type"); - } else return ""; + return EMPTY; + } else return Value(); } -string MessageSelectorEnv::value(const string& identifier) const +class MessageSelectorEnv : public SelectorEnv { + const Message& msg; + mutable boost::ptr_vector<string> returnedStrings; + mutable unordered_map<string, Value> returnedValues; + + const Value& value(const string&) const; + +public: + MessageSelectorEnv(const Message&); +}; + +MessageSelectorEnv::MessageSelectorEnv(const Message& m) : +msg(m) +{ +} + +const Value& MessageSelectorEnv::value(const string& identifier) const +{ + if (returnedValues.find(identifier)==returnedValues.end()) { + Value v; + + // Check for amqp prefix and strip it if present + if (identifier.substr(0, 5) == "amqp.") { + v = specialValue(msg, identifier.substr(5)); + } else { + // Just return property as string + //v = &msg.getPropertyAsString(identifier); + qpid::types::Variant var = msg.getProperty(identifier); + switch (var.getType()) { + case types::VAR_VOID: + v = Value(); break; + case types::VAR_STRING: { + string& s = var.getString(); + returnedStrings.push_back(new string(s)); + v = returnedStrings[returnedStrings.size()-1]; + break; + } + case types::VAR_UINT64: + // TODO: Need to take care of values too high to be int64_t + case types::VAR_UINT32: + case types::VAR_UINT16: + case types::VAR_UINT8: + case types::VAR_INT64: + case types::VAR_INT32: + case types::VAR_INT16: + case types::VAR_INT8: + v = var.asInt64(); break; + case types::VAR_FLOAT: + case types::VAR_DOUBLE: + v = var.asDouble(); break; + case types::VAR_BOOL: + v = var.asBool(); break; + default: + v = Value(); break; + } + } + QPID_LOG(debug, "Selector identifier: " << identifier << "->" << v); + returnedValues[identifier] = v; + } + return returnedValues[identifier]; +} + +Selector::Selector(const string& e) : + parse(TopExpression::parse(e)), + expression(e) { - string v; - - // Check for amqp prefix and strip it if present - if (identifier.substr(0, 5) == "amqp.") { - v = specialValue(msg, identifier.substr(5)); - } else { - // Just return property as string - v = msg.getPropertyAsString(identifier); + bool debugOut; + QPID_LOG_TEST(debug, debugOut); + if (debugOut) { + std::stringstream ss; + parse->repr(ss); + QPID_LOG(debug, "Selector parsed[" << e << "] into: " << ss.str()); } - QPID_LOG(debug, "Selector identifier: " << identifier << "->" << v); - return v; } +Selector::~Selector() +{ +} + +bool Selector::eval(const SelectorEnv& env) +{ + return parse->eval(env); +} + +bool Selector::filter(const Message& msg) +{ + return eval(MessageSelectorEnv(msg)); +} namespace { const boost::shared_ptr<Selector> NULL_SELECTOR = boost::shared_ptr<Selector>(); |
