diff options
author | Ted Ross <tross@apache.org> | 2010-01-05 19:45:28 +0000 |
---|---|---|
committer | Ted Ross <tross@apache.org> | 2010-01-05 19:45:28 +0000 |
commit | 25d63a161d11d504e51ead2f76e761f561503b69 (patch) | |
tree | 8f018d410a0d9ba554afc61f0f603407ffd1ecb6 | |
parent | f41fee09de1f40adc1323e7d811a5a76bc0b6edc (diff) | |
download | qpid-python-25d63a161d11d504e51ead2f76e761f561503b69.tar.gz |
Added handling of MAP values for the wrapped QMF interfaces.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@896191 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | qpid/cpp/bindings/qmf/python/qmf.py | 234 | ||||
-rw-r--r-- | qpid/cpp/bindings/qmf/ruby/qmf.rb | 188 | ||||
-rw-r--r-- | qpid/cpp/bindings/qmf/ruby/ruby.i | 2 | ||||
-rwxr-xr-x | qpid/cpp/bindings/qmf/tests/agent_ruby.rb | 27 | ||||
-rw-r--r-- | qpid/cpp/bindings/qmf/tests/python_agent.py | 46 | ||||
-rwxr-xr-x | qpid/cpp/bindings/qmf/tests/ruby_console_test.rb | 38 | ||||
-rwxr-xr-x | qpid/cpp/bindings/qmf/tests/run_interop_tests | 12 | ||||
-rw-r--r-- | qpid/cpp/include/qpid/framing/FieldValue.h | 2 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/engine/ValueImpl.cpp | 120 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/engine/ValueImpl.h | 10 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/FieldValue.cpp | 2 |
11 files changed, 477 insertions, 204 deletions
diff --git a/qpid/cpp/bindings/qmf/python/qmf.py b/qpid/cpp/bindings/qmf/python/qmf.py index 233f1c83d8..c00c777878 100644 --- a/qpid/cpp/bindings/qmf/python/qmf.py +++ b/qpid/cpp/bindings/qmf/python/qmf.py @@ -35,6 +35,118 @@ from qmfengine import (TYPE_ABSTIME, TYPE_ARRAY, TYPE_BOOL, TYPE_DELTATIME, from qmfengine import (O_EQ, O_NE, O_LT, O_LE, O_GT, O_GE, O_RE_MATCH, O_RE_NOMATCH, E_NOT, E_AND, E_OR, E_XOR) + +def qmf_to_native(val): + typecode = val.getType() + if typecode == TYPE_UINT8: return val.asUint() + elif typecode == TYPE_UINT16: return val.asUint() + elif typecode == TYPE_UINT32: return val.asUint() + elif typecode == TYPE_UINT64: return val.asUint64() + elif typecode == TYPE_SSTR: return val.asString() + elif typecode == TYPE_LSTR: return val.asString() + elif typecode == TYPE_ABSTIME: return val.asInt64() + elif typecode == TYPE_DELTATIME: return val.asUint64() + elif typecode == TYPE_REF: return ObjectId(val.asObjectId()) + elif typecode == TYPE_BOOL: return val.asBool() + elif typecode == TYPE_FLOAT: return val.asFloat() + elif typecode == TYPE_DOUBLE: return val.asDouble() + elif typecode == TYPE_UUID: return val.asUuid() + elif typecode == TYPE_INT8: return val.asInt() + elif typecode == TYPE_INT16: return val.asInt() + elif typecode == TYPE_INT32: return val.asInt() + elif typecode == TYPE_INT64: return val.asInt64() + elif typecode == TYPE_MAP: return value_to_dict(val) + else: + # when TYPE_OBJECT + # when TYPE_LIST + # when TYPE_ARRAY + logging.error( "Unsupported type for get_attr? '%s'" % str(val.getType()) ) + return None + + +def native_to_qmf(target, value): + val = None + typecode = None + if target.__class__ == qmfengine.Value: + val = target + typecode = val.getType() + else: + typecode = target + val = qmfengine.Value(typecode) + + if typecode == TYPE_UINT8: val.setUint(value) + elif typecode == TYPE_UINT16: val.setUint(value) + elif typecode == TYPE_UINT32: val.setUint(value) + elif typecode == TYPE_UINT64: val.setUint64(value) + elif typecode == TYPE_SSTR: + if value: val.setString(value) + else: val.setString('') + elif typecode == TYPE_LSTR: + if value: val.setString(value) + else: val.setString('') + elif typecode == TYPE_ABSTIME: val.setInt64(value) + elif typecode == TYPE_DELTATIME: val.setUint64(value) + elif typecode == TYPE_REF: val.setObjectId(value.impl) + elif typecode == TYPE_BOOL: val.setBool(value) + elif typecode == TYPE_FLOAT: val.setFloat(value) + elif typecode == TYPE_DOUBLE: val.setDouble(value) + elif typecode == TYPE_UUID: val.setUuid(value) + elif typecode == TYPE_INT8: val.setInt(value) + elif typecode == TYPE_INT16: val.setInt(value) + elif typecode == TYPE_INT32: val.setInt(value) + elif typecode == TYPE_INT64: val.setInt64(value) + elif typecode == TYPE_MAP: dict_to_value(val, value) + else: + # when TYPE_MAP + # when TYPE_OBJECT + # when TYPE_LIST + # when TYPE_ARRAY + logging.error("Unsupported type for get_attr? '%s'" % str(val.getType())) + return None + return val + + +def pick_qmf_type(value): + if value.__class__ == int: + if value >= 0: + if value < 0x100000000: return TYPE_UINT32 + return TYPE_UINT64 + else: + if value > -0xffffffff: return TYPE_INT32 + return TYPE_INT64 + + if value.__class__ == long: + if value >= 0: return TYPE_UINT64 + return TYPE_INT64 + + if value.__class__ == str: + if len(value) < 256: return TYPE_SSTR + return TYPE_LSTR + + if value.__class__ == float: return TYPE_DOUBLE + if value.__class__ == bool: return TYPE_BOOL + if value == None: return TYPE_BOOL + if value.__class__ == dict: return TYPE_MAP + + raise "QMF type not known for native type %s" % value.__class__ + + +def value_to_dict(val): + if not val.isMap(): raise "value_to_dict must be given a map value" + mymap = {} + for i in range(val.keyCount()): + key = val.key(i) + mymap[key] = qmf_to_native(val.byKey(key)) + return mymap + + +def dict_to_value(val, mymap): + for key, value in mymap.items(): + if key.__class__ != str: raise "QMF map key must be a string" + typecode = pick_qmf_type(value) + val.insert(key, native_to_qmf(typecode, value)) + + ##============================================================================== ## CONNECTION ##============================================================================== @@ -293,64 +405,12 @@ class QmfObject(object): def get_attr(self, name): val = self._value(name) - vType = val.getType() - if vType == TYPE_UINT8: return val.asUint() - elif vType == TYPE_UINT16: return val.asUint() - elif vType == TYPE_UINT32: return val.asUint() - elif vType == TYPE_UINT64: return val.asUint64() - elif vType == TYPE_SSTR: return val.asString() - elif vType == TYPE_LSTR: return val.asString() - elif vType == TYPE_ABSTIME: return val.asInt64() - elif vType == TYPE_DELTATIME: return val.asUint64() - elif vType == TYPE_REF: return ObjectId(val.asObjectId()) - elif vType == TYPE_BOOL: return val.asBool() - elif vType == TYPE_FLOAT: return val.asFloat() - elif vType == TYPE_DOUBLE: return val.asDouble() - elif vType == TYPE_UUID: return val.asUuid() - elif vType == TYPE_INT8: return val.asInt() - elif vType == TYPE_INT16: return val.asInt() - elif vType == TYPE_INT32: return val.asInt() - elif vType == TYPE_INT64: return val.asInt64() - else: - # when TYPE_MAP - # when TYPE_OBJECT - # when TYPE_LIST - # when TYPE_ARRAY - logging.error( "Unsupported type for get_attr? '%s'" % str(val.getType()) ) - return None + return qmf_to_native(val) def set_attr(self, name, v): val = self._value(name) - vType = val.getType() - if vType == TYPE_UINT8: return val.setUint(v) - elif vType == TYPE_UINT16: return val.setUint(v) - elif vType == TYPE_UINT32: return val.setUint(v) - elif vType == TYPE_UINT64: return val.setUint64(v) - elif vType == TYPE_SSTR: - if v: return val.setString(v) - else: return val.setString('') - elif vType == TYPE_LSTR: - if v: return val.setString(v) - else: return val.setString('') - elif vType == TYPE_ABSTIME: return val.setInt64(v) - elif vType == TYPE_DELTATIME: return val.setUint64(v) - elif vType == TYPE_REF: return val.setObjectId(v.impl) - elif vType == TYPE_BOOL: return val.setBool(v) - elif vType == TYPE_FLOAT: return val.setFloat(v) - elif vType == TYPE_DOUBLE: return val.setDouble(v) - elif vType == TYPE_UUID: return val.setUuid(v) - elif vType == TYPE_INT8: return val.setInt(v) - elif vType == TYPE_INT16: return val.setInt(v) - elif vType == TYPE_INT32: return val.setInt(v) - elif vType == TYPE_INT64: return val.setInt64(v) - else: - # when TYPE_MAP - # when TYPE_OBJECT - # when TYPE_LIST - # when TYPE_ARRAY - logging.error("Unsupported type for get_attr? '%s'" % str(val.getType())) - return None + native_to_qmf(val, v) def __getitem__(self, name): @@ -577,7 +637,8 @@ class Arguments(object): key_count = self.map.keyCount() a = 0 while a < key_count: - self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a)) + key = self.map.key(a) + self._by_hash[key] = qmf_to_native(self.map.byKey(key)) a += 1 @@ -615,70 +676,9 @@ class Arguments(object): return super.__setattr__(self, name, value) - def by_key(self, key): - val = self.map.byKey(key) - vType = val.getType() - if vType == TYPE_UINT8: return val.asUint() - elif vType == TYPE_UINT16: return val.asUint() - elif vType == TYPE_UINT32: return val.asUint() - elif vType == TYPE_UINT64: return val.asUint64() - elif vType == TYPE_SSTR: return val.asString() - elif vType == TYPE_LSTR: return val.asString() - elif vType == TYPE_ABSTIME: return val.asInt64() - elif vType == TYPE_DELTATIME: return val.asUint64() - elif vType == TYPE_REF: return ObjectId(val.asObjectId()) - elif vType == TYPE_BOOL: return val.asBool() - elif vType == TYPE_FLOAT: return val.asFloat() - elif vType == TYPE_DOUBLE: return val.asDouble() - elif vType == TYPE_UUID: return val.asUuid() - elif vType == TYPE_INT8: return val.asInt() - elif vType == TYPE_INT16: return val.asInt() - elif vType == TYPE_INT32: return val.asInt() - elif vType == TYPE_INT64: return val.asInt64() - else: - # when TYPE_MAP - # when TYPE_OBJECT - # when TYPE_LIST - # when TYPE_ARRAY - logging.error( "Unsupported Type for Get? '%s'" % str(val.getType())) - return None - - def set(self, key, value): val = self.map.byKey(key) - vType = val.getType() - if vType == TYPE_UINT8: return val.setUint(value) - elif vType == TYPE_UINT16: return val.setUint(value) - elif vType == TYPE_UINT32: return val.setUint(value) - elif vType == TYPE_UINT64: return val.setUint64(value) - elif vType == TYPE_SSTR: - if value: - return val.setString(value) - else: - return val.setString('') - elif vType == TYPE_LSTR: - if value: - return val.setString(value) - else: - return val.setString('') - elif vType == TYPE_ABSTIME: return val.setInt64(value) - elif vType == TYPE_DELTATIME: return val.setUint64(value) - elif vType == TYPE_REF: return val.setObjectId(value.impl) - elif vType == TYPE_BOOL: return val.setBool(value) - elif vType == TYPE_FLOAT: return val.setFloat(value) - elif vType == TYPE_DOUBLE: return val.setDouble(value) - elif vType == TYPE_UUID: return val.setUuid(value) - elif vType == TYPE_INT8: return val.setInt(value) - elif vType == TYPE_INT16: return val.setInt(value) - elif vType == TYPE_INT32: return val.setInt(value) - elif vType == TYPE_INT64: return val.setInt64(value) - else: - # when TYPE_MAP - # when TYPE_OBJECT - # when TYPE_LIST - # when TYPE_ARRAY - logging.error("Unsupported Type for Set? '%s'" % str(val.getType())) - return None + native_to_qmf(val, value) diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb index 857dd64aeb..ea085d1be2 100644 --- a/qpid/cpp/bindings/qmf/ruby/qmf.rb +++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb @@ -31,6 +31,112 @@ module Qmf end end + class Util + def qmf_to_native(val) + case val.getType + when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint + when TYPE_UINT64 then val.asUint64 + when TYPE_SSTR, TYPE_LSTR then val.asString + when TYPE_ABSTIME then val.asInt64 + when TYPE_DELTATIME then val.asUint64 + when TYPE_REF then ObjectId.new(val.asObjectId) + when TYPE_BOOL then val.asBool + when TYPE_FLOAT then val.asFloat + when TYPE_DOUBLE then val.asDouble + when TYPE_UUID then val.asUuid + when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt + when TYPE_INT64 then val.asInt64 + when TYPE_MAP then value_to_dict(val) + when TYPE_OBJECT + when TYPE_LIST + when TYPE_ARRAY + end + end + + def native_to_qmf(target, value) + if target.class == Qmfengine::Value + val = target + typecode = val.getType + else + typecode = target + val = Qmfengine::Value.new(typecode) + end + + case typecode + when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value) + when TYPE_UINT64 then val.setUint64(value) + when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('') + when TYPE_ABSTIME then val.setInt64(value) + when TYPE_DELTATIME then val.setUint64(value) + when TYPE_REF then val.setObjectId(value.impl) + when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0) + when TYPE_FLOAT then val.setFloat(value) + when TYPE_DOUBLE then val.setDouble(value) + when TYPE_UUID then val.setUuid(value) + when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value) + when TYPE_INT64 then val.setInt64(value) + when TYPE_MAP then dict_to_value(val, value) + when TYPE_OBJECT + when TYPE_LIST + when TYPE_ARRAY + end + return val + end + + def pick_qmf_type(value) + if value.class == Fixnum + if value >= 0 + return TYPE_UINT32 if value < 0x100000000 + return TYPE_UINT64 + else + return TYPE_INT32 if value > -0xffffffff + return TYPE_INT64 + end + end + + if value.class == Bignum + return TYPE_UINT64 if value >= 0 + return TYPE_INT64 + end + + if value.class == String + return TYPE_SSTR if value.length < 256 + return TYPE_LSTR + end + + return TYPE_DOUBLE if value.class == Float + + return TYPE_BOOL if value.class == TrueClass + return TYPE_BOOL if value.class == FalseClass + return TYPE_BOOL if value.class == NilClass + + return TYPE_MAP if value.class == Hash + + raise ArgumentError, "QMF type not known for native type #{value.class}" + end + + def value_to_dict(val) + # Assume val is of type Qmfengine::Value + raise ArgumentError, "value_to_dict must be given a map value" if !val.isMap + map = {} + for i in 0...val.keyCount + key = val.key(i) + map[key] = qmf_to_native(val.byKey(key)) + end + return map + end + + def dict_to_value(val, map) + map.each do |key, value| + raise ArgumentError, "QMF map key must be a string" if key.class != String + typecode = pick_qmf_type(value) + val.insert(key, native_to_qmf(typecode, value)) + end + end + end + + $util = Util.new + ##============================================================================== ## CONNECTION ##============================================================================== @@ -246,46 +352,12 @@ module Qmf def get_attr(name) val = value(name) - case val.getType - when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint - when TYPE_UINT64 then val.asUint64 - when TYPE_SSTR, TYPE_LSTR then val.asString - when TYPE_ABSTIME then val.asInt64 - when TYPE_DELTATIME then val.asUint64 - when TYPE_REF then ObjectId.new(val.asObjectId) - when TYPE_BOOL then val.asBool - when TYPE_FLOAT then val.asFloat - when TYPE_DOUBLE then val.asDouble - when TYPE_UUID then val.asUuid - when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt - when TYPE_INT64 then val.asInt64 - when TYPE_MAP - when TYPE_OBJECT - when TYPE_LIST - when TYPE_ARRAY - end + $util.qmf_to_native(val) end def set_attr(name, v) val = value(name) - case val.getType - when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v) - when TYPE_UINT64 then val.setUint64(v) - when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('') - when TYPE_ABSTIME then val.setInt64(v) - when TYPE_DELTATIME then val.setUint64(v) - when TYPE_REF then val.setObjectId(v.impl) - when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0) - when TYPE_FLOAT then val.setFloat(v) - when TYPE_DOUBLE then val.setDouble(v) - when TYPE_UUID then val.setUuid(v) - when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v) - when TYPE_INT64 then val.setInt64(v) - when TYPE_MAP - when TYPE_OBJECT - when TYPE_LIST - when TYPE_ARRAY - end + $util.native_to_qmf(val, v) end def [](name) @@ -488,7 +560,8 @@ module Qmf key_count = @map.keyCount a = 0 while a < key_count - @by_hash[@map.key(a)] = by_key(@map.key(a)) + key = @map.key(a) + @by_hash[key] = $util.qmf_to_native(@map.byKey(key)) a += 1 end end @@ -514,48 +587,9 @@ module Qmf super.method_missing(name, args) end - def by_key(key) - val = @map.byKey(key) - case val.getType - when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint - when TYPE_UINT64 then val.asUint64 - when TYPE_SSTR, TYPE_LSTR then val.asString - when TYPE_ABSTIME then val.asInt64 - when TYPE_DELTATIME then val.asUint64 - when TYPE_REF then ObjectId.new(val.asObjectId) - when TYPE_BOOL then val.asBool - when TYPE_FLOAT then val.asFloat - when TYPE_DOUBLE then val.asDouble - when TYPE_UUID then val.asUuid - when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt - when TYPE_INT64 then val.asInt64 - when TYPE_MAP - when TYPE_OBJECT - when TYPE_LIST - when TYPE_ARRAY - end - end - def set(key, value) val = @map.byKey(key) - case val.getType - when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value) - when TYPE_UINT64 then val.setUint64(value) - when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('') - when TYPE_ABSTIME then val.setInt64(value) - when TYPE_DELTATIME then val.setUint64(value) - when TYPE_REF then val.setObjectId(value.impl) - when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0) - when TYPE_FLOAT then val.setFloat(value) - when TYPE_DOUBLE then val.setDouble(value) - when TYPE_UUID then val.setUuid(value) - when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value) - when TYPE_INT64 then val.setInt64(value) - when TYPE_MAP - when TYPE_OBJECT - when TYPE_LIST - when TYPE_ARRAY - end + $util.native_to_qmf(val, value) end end diff --git a/qpid/cpp/bindings/qmf/ruby/ruby.i b/qpid/cpp/bindings/qmf/ruby/ruby.i index b7fed403bd..0101861100 100644 --- a/qpid/cpp/bindings/qmf/ruby/ruby.i +++ b/qpid/cpp/bindings/qmf/ruby/ruby.i @@ -76,7 +76,7 @@ if (TYPE($input) == T_BIGNUM) $1 = NUM2ULL($input); else - $1 = (uint64_t) FIX2LONG($input); + $1 = (uint64_t) FIX2ULONG($input); } %typemap (out) uint64_t diff --git a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb index adf91a8b66..0be779994a 100755 --- a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb +++ b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb @@ -43,6 +43,8 @@ class Model @parent_class.add_property(Qmf::SchemaProperty.new("sstrval", Qmf::TYPE_SSTR)) @parent_class.add_property(Qmf::SchemaProperty.new("lstrval", Qmf::TYPE_LSTR)) + @parent_class.add_property(Qmf::SchemaProperty.new("mapval", Qmf::TYPE_MAP)) + @parent_class.add_statistic(Qmf::SchemaStatistic.new("queryCount", Qmf::TYPE_UINT32, :unit => "query", :desc => "Query count")) method = Qmf::SchemaMethod.new("echo", :desc => "Check responsiveness of the agent object") @@ -53,6 +55,11 @@ class Model method.add_argument(Qmf::SchemaArgument.new("test", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN)) @parent_class.add_method(method) + method = Qmf::SchemaMethod.new("set_map", :desc => "Set the map value in the object") + method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_MAP, :dir => Qmf::DIR_IN)) + method.add_argument(Qmf::SchemaArgument.new("output", Qmf::TYPE_MAP, :dir => Qmf::DIR_OUT)) + @parent_class.add_method(method) + method = Qmf::SchemaMethod.new("set_short_string", :desc => "Set the short string value in the object") method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN_OUT)) @parent_class.add_method(method) @@ -101,19 +108,37 @@ class App < Qmf::AgentHandler if name == "echo" @agent.method_response(context, 0, "OK", args) + elsif name == "set_map" + + map = args['value'] + + map['added'] = 'Added Text' + args['output'] = map + elsif name == "set_numerics" if args['test'] == "big" @parent.uint64val = 0x9494949449494949 @parent.uint32val = 0xa5a55a5a @parent.uint16val = 0xb66b - @parent.uint8val = 0xc7 + @parent.uint8val = 0xc7 @parent.int64val = 1000000000000000000 @parent.int32val = 1000000000 @parent.int16val = 10000 @parent.int8val = 100 + @parent.mapval = {'u64' => @parent.uint64val, + 'u32' => @parent.uint32val, + 'u16' => @parent.uint16val, + 'u8' => @parent.uint8val, + 'i64' => @parent.int64val, + 'i32' => @parent.int32val, + 'i16' => @parent.int16val, + 'i8' => @parent.int8val, + 'sstr' => "Short String", + 'map' => {'first' => 'FIRST', 'second' => 'SECOND'}} + elsif args['test'] == "small" @parent.uint64val = 4 @parent.uint32val = 5 diff --git a/qpid/cpp/bindings/qmf/tests/python_agent.py b/qpid/cpp/bindings/qmf/tests/python_agent.py index 0f5ffe5b8a..c42273d7b2 100644 --- a/qpid/cpp/bindings/qmf/tests/python_agent.py +++ b/qpid/cpp/bindings/qmf/tests/python_agent.py @@ -41,6 +41,12 @@ class Model: self.parent_class.add_property(qmf.SchemaProperty("int16val", qmf.TYPE_INT16)) self.parent_class.add_property(qmf.SchemaProperty("int8val", qmf.TYPE_INT8)) + self.parent_class.add_property(qmf.SchemaProperty("sstrval", qmf.TYPE_SSTR)) + self.parent_class.add_property(qmf.SchemaProperty("lstrval", qmf.TYPE_LSTR)) + + self.parent_class.add_property(qmf.SchemaProperty("mapval", qmf.TYPE_MAP)) + + self.parent_class.add_statistic(qmf.SchemaStatistic("queryCount", qmf.TYPE_UINT32, {"unit":"query", "desc":"Query count"})) _method = qmf.SchemaMethod("echo", {"desc":"Check responsiveness of the agent object"}) @@ -51,6 +57,19 @@ class Model: _method.add_argument(qmf.SchemaArgument("test", qmf.TYPE_SSTR, {"dir":qmf.DIR_IN})) self.parent_class.add_method(_method) + _method = qmf.SchemaMethod("set_map", {"desc":"Set the map value in the object"}) + _method.add_argument(qmf.SchemaArgument("value", qmf.TYPE_MAP, {"dir":qmf.DIR_IN})) + _method.add_argument(qmf.SchemaArgument("output", qmf.TYPE_MAP, {"dir":qmf.DIR_OUT})) + self.parent_class.add_method(_method) + + _method = qmf.SchemaMethod("set_short_string", {"desc":"Set the short string value in the object"}) + _method.add_argument(qmf.SchemaArgument("value", qmf.TYPE_SSTR, {"dir":qmf.DIR_IN_OUT})) + self.parent_class.add_method(_method) + + _method = qmf.SchemaMethod("set_long_string", {"desc":"Set the long string value in the object"}) + _method.add_argument(qmf.SchemaArgument("value", qmf.TYPE_LSTR, {"dir":qmf.DIR_IN_OUT})) + self.parent_class.add_method(_method) + _method = qmf.SchemaMethod("create_child", {"desc":"Create a new child object"}) _method.add_argument(qmf.SchemaArgument("child_name", qmf.TYPE_LSTR, {"dir":qmf.DIR_IN})) _method.add_argument(qmf.SchemaArgument("child_ref", qmf.TYPE_REF, {"dir":qmf.DIR_OUT})) @@ -97,6 +116,12 @@ class App(qmf.AgentHandler): if name == "echo": self._agent.method_response(context, 0, "OK", args) + elif name == "set_map": + map = args['value'] + map['added'] = "Added Text" + args['output'] = map + self._agent.method_response(context, 0, "OK", args) + elif name == "set_numerics": _retCode = 0 _retText = "OK" @@ -115,6 +140,17 @@ class App(qmf.AgentHandler): self._parent["int16val"] = 10000 self._parent.set_attr("int8val", 100) + self._parent.set_attr("mapval", {'u64' : self._parent['uint64val'], + 'u32' : self._parent['uint32val'], + 'u16' : self._parent['uint16val'], + 'u8' : self._parent['uint8val'], + 'i64' : self._parent['int64val'], + 'i32' : self._parent['int32val'], + 'i16' : self._parent['int16val'], + 'i8' : self._parent['int8val'], + 'sstr' : "Short String", + 'map' : {'first' : 'FIRST', 'second' : 'SECOND'}}) + ## Test the __getattr__ implementation: ## @todo: remove once python_client implements this ## form of property access @@ -150,6 +186,14 @@ class App(qmf.AgentHandler): self._agent.method_response(context, _retCode, _retText, args) + elif name == "set_short_string": + self._parent.set_attr('sstrval', args['value']) + self._agent.method_response(context, 0, "OK", args) + + elif name == "set_long_string": + self._parent.set_attr('lstrval', args['value']) + self._agent.method_response(context, 0, "OK", args) + elif name == "create_child": # # Instantiate an object based on the Child Schema Class @@ -199,7 +243,7 @@ class App(qmf.AgentHandler): ## @todo how do we force a test failure? # verify the properties() and statistics() object methods: - assert len(self._parent.properties()) == 10 + assert len(self._parent.properties()) == 13 assert len(self._parent.statistics()) == 1 self._parent.set_attr("name", "Parent One") diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb index c5c7b141dd..3a771aaafd 100755 --- a/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb +++ b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb @@ -177,6 +177,44 @@ class ConsoleTest < ConsoleTestBase end end + def test_C_basic_types_map + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + result = parent.set_numerics("big") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + map = parent.mapval + + assert_equal(map['u64'], 0x9494949449494949) + assert_equal(map['u32'], 0xA5A55A5A) + assert_equal(map['u16'], 0xB66B) + assert_equal(map['u8'], 0xC7) + + assert_equal(map['i64'], 1000000000000000000) + assert_equal(map['i32'], 1000000000) + assert_equal(map['i16'], 10000) + assert_equal(map['i8'], 100) + + assert_equal(map['sstr'], "Short String") + + submap = map['map'] + assert_equal(submap['first'], "FIRST") + assert_equal(submap['second'], "SECOND") + + result = parent.set_map({'first' => 'FIRST', 'sub' => {'subfirst' => 25}}) + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + rmap = result.args.output + assert_equal(rmap['first'], "FIRST") + assert_equal(rmap['sub']['subfirst'], 25) + assert_equal(rmap['added'], 'Added Text') + end + def test_D_userid_for_method parent = @qmfc.object(:class => "parent") assert(parent, "Number of parent objects") diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests index b5545d736d..1669fe0189 100755 --- a/qpid/cpp/bindings/qmf/tests/run_interop_tests +++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests @@ -101,6 +101,18 @@ if test -d ${PYTHON_DIR} ; then echo "FAIL qmf interop tests (Ruby Console/Ruby Agent)"; TESTS_FAILED=1 fi + + if test -d ${PYTHON_LIB_DIR} ; then + echo " Python Agent (external storage) vs. Ruby Console" + start_python_agent + ruby -I${MY_DIR} -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/ruby_console_test.rb localhost $BROKER_PORT $@ + RETCODE=$? + stop_python_agent + if test x$RETCODE != x0; then + echo "FAIL qmf interop tests (Ruby Console/Python Agent)"; + TESTS_FAILED=1 + fi + fi fi # Also against the Pure-Python console: diff --git a/qpid/cpp/include/qpid/framing/FieldValue.h b/qpid/cpp/include/qpid/framing/FieldValue.h index 60a887761f..7b4dee1529 100644 --- a/qpid/cpp/include/qpid/framing/FieldValue.h +++ b/qpid/cpp/include/qpid/framing/FieldValue.h @@ -83,7 +83,7 @@ class FieldValue { FieldValue(): data(0) {}; // Default assignment operator is fine void setType(uint8_t type); - QPID_COMMON_EXTERN uint8_t getType(); + QPID_COMMON_EXTERN uint8_t getType() const; Data& getData() { return *data; } uint32_t encodedSize() const { return 1 + data->encodedSize(); }; bool empty() const { return data.get() == 0; } diff --git a/qpid/cpp/src/qmf/engine/ValueImpl.cpp b/qpid/cpp/src/qmf/engine/ValueImpl.cpp index 1949d4b946..b1c027520f 100644 --- a/qpid/cpp/src/qmf/engine/ValueImpl.cpp +++ b/qpid/cpp/src/qmf/engine/ValueImpl.cpp @@ -19,16 +19,19 @@ #include "qmf/engine/ValueImpl.h" #include <qpid/framing/FieldTable.h> +#include <qpid/framing/FieldValue.h> using namespace std; using namespace qmf::engine; using qpid::framing::Buffer; +using qpid::framing::FieldTable; +using qpid::framing::FieldValue; ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t) { uint64_t first; uint64_t second; - qpid::framing::FieldTable ft; + FieldTable ft; switch (typecode) { case TYPE_UINT8 : value.u32 = (uint32_t) buf.getOctet(); break; @@ -55,6 +58,7 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t) case TYPE_MAP: ft.decode(buf); + initMap(ft); break; case TYPE_LIST: @@ -90,8 +94,111 @@ ValueImpl::~ValueImpl() { } +void ValueImpl::initMap(const FieldTable& ft) +{ + for (FieldTable::ValueMap::const_iterator iter = ft.begin(); + iter != ft.end(); iter++) { + const string& name(iter->first); + const FieldValue& fvalue(*iter->second); + uint8_t amqType = fvalue.getType(); + + if (amqType == 0x32) { + Value* subval(new Value(TYPE_UINT64)); + subval->setUint64(fvalue.get<int64_t>()); + insert(name.c_str(), subval); + } else if ((amqType & 0xCF) == 0x02) { + Value* subval(new Value(TYPE_UINT32)); + switch (amqType) { + case 0x02 : subval->setUint(fvalue.get<int>()); break; + case 0x12 : subval->setUint(fvalue.get<int>()); break; + case 0x22 : subval->setUint(fvalue.get<int>()); break; + } + insert(name.c_str(), subval); + } else if ((amqType & 0xCF) == 0x01) { + Value* subval(new Value(TYPE_INT64)); + subval->setInt64(fvalue.get<int64_t>()); + insert(name.c_str(), subval); + } else if (amqType == 0x85 || amqType == 0x95) { + Value* subval(new Value(TYPE_LSTR)); + subval->setString(fvalue.get<string>().c_str()); + insert(name.c_str(), subval); + } else if (amqType == 0x23 || amqType == 0x33) { + Value* subval(new Value(TYPE_DOUBLE)); + subval->setDouble(fvalue.get<double>()); + insert(name.c_str(), subval); + } else { + FieldTable subFt; + bool valid = qpid::framing::getEncodedValue<FieldTable>(iter->second, subFt); + if (valid) { + Value* subval(new Value(TYPE_MAP)); + subval->impl->initMap(subFt); + insert(name.c_str(), subval); + } + } + } +} + +void ValueImpl::mapToFieldTable(FieldTable& ft) const +{ + FieldTable subFt; + + for (map<string, Value>::const_iterator iter = mapVal.begin(); + iter != mapVal.end(); iter++) { + const string& name(iter->first); + const Value& subval(iter->second); + + switch (subval.getType()) { + case TYPE_UINT8: + case TYPE_UINT16: + case TYPE_UINT32: + ft.setUInt64(name, (uint64_t) subval.asUint()); + break; + case TYPE_UINT64: + case TYPE_DELTATIME: + ft.setUInt64(name, subval.asUint64()); + break; + case TYPE_SSTR: + case TYPE_LSTR: + ft.setString(name, subval.asString()); + break; + case TYPE_INT64: + case TYPE_ABSTIME: + ft.setInt64(name, subval.asInt64()); + break; + case TYPE_BOOL: + ft.setInt(name, subval.asBool() ? 1 : 0); + break; + case TYPE_FLOAT: + ft.setFloat(name, subval.asFloat()); + break; + case TYPE_DOUBLE: + ft.setDouble(name, subval.asDouble()); + break; + case TYPE_INT8: + case TYPE_INT16: + case TYPE_INT32: + ft.setInt(name, subval.asInt()); + break; + case TYPE_MAP: + subFt.clear(); + subval.impl->mapToFieldTable(subFt); + ft.setTable(name, subFt); + break; + case TYPE_LIST: + case TYPE_ARRAY: + case TYPE_OBJECT: + case TYPE_UUID: + case TYPE_REF: + default: + break; + } + } + } + void ValueImpl::encode(Buffer& buf) const { + FieldTable ft; + switch (typecode) { case TYPE_UINT8 : buf.putOctet((uint8_t) value.u32); break; case TYPE_UINT16 : buf.putShort((uint16_t) value.u32); break; @@ -110,7 +217,10 @@ void ValueImpl::encode(Buffer& buf) const case TYPE_INT64 : buf.putLongLong(value.s64); break; case TYPE_UUID : buf.putBin128(value.uuidVal); break; case TYPE_REF : refVal.impl->encode(buf); break; - case TYPE_MAP: // TODO + case TYPE_MAP: + mapToFieldTable(ft); + ft.encode(buf); + break; case TYPE_LIST: case TYPE_ARRAY: case TYPE_OBJECT: @@ -127,7 +237,7 @@ bool ValueImpl::keyInMap(const char* key) const Value* ValueImpl::byKey(const char* key) { if (keyInMap(key)) { - map<std::string, Value>::iterator iter = mapVal.find(key); + map<string, Value>::iterator iter = mapVal.find(key); if (iter != mapVal.end()) return &iter->second; } @@ -137,7 +247,7 @@ Value* ValueImpl::byKey(const char* key) const Value* ValueImpl::byKey(const char* key) const { if (keyInMap(key)) { - map<std::string, Value>::const_iterator iter = mapVal.find(key); + map<string, Value>::const_iterator iter = mapVal.find(key); if (iter != mapVal.end()) return &iter->second; } @@ -157,7 +267,7 @@ void ValueImpl::insert(const char* key, Value* val) const char* ValueImpl::key(uint32_t idx) const { - map<std::string, Value>::const_iterator iter = mapVal.begin(); + map<string, Value>::const_iterator iter = mapVal.begin(); for (uint32_t i = 0; i < idx; i++) { if (iter == mapVal.end()) break; diff --git a/qpid/cpp/src/qmf/engine/ValueImpl.h b/qpid/cpp/src/qmf/engine/ValueImpl.h index b6adae5d93..84b0e768e6 100644 --- a/qpid/cpp/src/qmf/engine/ValueImpl.h +++ b/qpid/cpp/src/qmf/engine/ValueImpl.h @@ -30,6 +30,12 @@ #include <vector> #include <boost/shared_ptr.hpp> +namespace qpid { +namespace framing { + class FieldTable; +} +} + namespace qmf { namespace engine { @@ -142,6 +148,10 @@ namespace engine { Value* arrayItem(uint32_t idx); void appendToArray(Value* val); void deleteArrayItem(uint32_t idx); + + private: + void mapToFieldTable(qpid::framing::FieldTable& ft) const; + void initMap(const qpid::framing::FieldTable& ft); }; } } diff --git a/qpid/cpp/src/qpid/framing/FieldValue.cpp b/qpid/cpp/src/qpid/framing/FieldValue.cpp index 5bac931b83..9c5c0c36a2 100644 --- a/qpid/cpp/src/qpid/framing/FieldValue.cpp +++ b/qpid/cpp/src/qpid/framing/FieldValue.cpp @@ -28,7 +28,7 @@ namespace qpid { namespace framing { -uint8_t FieldValue::getType() +uint8_t FieldValue::getType() const { return typeOctet; } |