From ec1bb7110f50d2e30b7d636b9f863846d5e22676 Mon Sep 17 00:00:00 2001 From: Ted Ross Date: Fri, 14 May 2010 14:01:35 +0000 Subject: QPID-2589 - Patch from Chuck Rolke that exposes structured message content (map/list). git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@944263 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/bindings/qpid/dotnet/src/Message.cpp | 466 +++++++++++++++++++++++++++++++ cpp/bindings/qpid/dotnet/src/Message.h | 63 ++++- 2 files changed, 528 insertions(+), 1 deletion(-) (limited to 'cpp') diff --git a/cpp/bindings/qpid/dotnet/src/Message.cpp b/cpp/bindings/qpid/dotnet/src/Message.cpp index 90ca4e8915..a3e966ec48 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.cpp +++ b/cpp/bindings/qpid/dotnet/src/Message.cpp @@ -20,10 +20,13 @@ #include #include #include +#include #include #include +#include #include "qpid/messaging/Message.h" +#include "qpid/types/Variant.h" #include "QpidMarshal.h" #include "Message.h" @@ -39,16 +42,75 @@ namespace messaging { // This constructor is used to create a message from bytes to put into the message Message::Message(System::String ^ bytes) : + aVMap(gcnew VMap()), + aVList(gcnew VList()), + pVMapType(aVMap.GetType()), + pVListType(aVList.GetType()), messagep(new ::qpid::messaging::Message(QpidMarshal::ToNative(bytes))) { } // This constructor creates a message from a native received message Message::Message(::qpid::messaging::Message * msgp) : + aVMap(gcnew VMap()), + aVList(gcnew VList()), + pVMapType(aVMap.GetType()), + pVListType(aVList.GetType()), messagep(msgp) { } + + Message::Message(System::Object ^ objp) : + aVMap(gcnew VMap()), + aVList(gcnew VList()), + pVMapType(aVMap.GetType()), + pVListType(aVList.GetType()), + messagep(new ::qpid::messaging::Message(QpidMarshal::ToNative(""))) + { + ::qpid::types::Variant * variantp = 0; + std::string * variantsp = 0; + + if (objIsMap(objp)) + { + // Create a mapped message using given dictionary + + // Allocate a map + ::qpid::types::Variant::Map newMap; + + // Add the map variables to the map + Encode(newMap, (VMap ^)objp); + + // Set message content type + messagep->setContentType("ampq/map"); + + // Insert the map into the message + ::qpid::messaging::encode(newMap, *messagep, QpidMarshal::ToNative("amqp/map")); + } + else if (objIsList(objp)) + { + // Create a list message using given list + + // Allocate a list + ::qpid::types::Variant::List newList; + + // Add the list variables to the list + Encode(newList, (VList ^)objp); + + // Set message content type + messagep->setContentType("ampq/list"); + + // Insert the list into the message + ::qpid::messaging::encode(newList, *messagep, QpidMarshal::ToNative("amqp/list")); + } + else + { + // Create a binary string message + messagep->setContent(QpidMarshal::ToNative(objp->ToString())); + } + } + + // Destructor Message::~Message() { @@ -79,6 +141,199 @@ namespace messaging { } } + + // + // The given object is a Dictionary. + // Add its elements to the qpid map. + // + void Message::Encode(::qpid::types::Variant::Map & theMapp, + VMap ^ theObjp) + { + // iterate the items, converting each to a variant and adding to the map + for each (System::Collections::Generic::KeyValuePair kvp in theObjp) + { + if (objIsMap(kvp.Value)) + { + // Recurse on inner map + // Allocate a map + ::qpid::types::Variant::Map newMap; + + // Add the map variables to the map + Encode(newMap, (VMap ^)kvp.Value); + + // Create a variant entry for the inner map + std::auto_ptr<::qpid::types::Variant> newVariantp(new ::qpid::types::Variant(newMap)); + + // Get map's name + std::string entryName = QpidMarshal::ToNative(kvp.Key); + + // Add inner map to outer map + theMapp.insert(std::make_pair(entryName, *newVariantp)); + } + else if (objIsList(kvp.Value)) + { + // Recurse on inner list + // Allocate a list + ::qpid::types::Variant::List newList; + + // Add the List variables to the list + Encode(newList, (VList ^)kvp.Value); + + // Create a variant entry for the inner map + ::qpid::types::Variant::List newVariant(newList); + + //std::auto_ptr<::qpid::types::Variant> newVariantp(new ::qpid::types::Variant(newList)); + + // Get list's name + std::string entryName = QpidMarshal::ToNative(kvp.Key); + + // Add inner list to outer map + theMapp.insert(std::make_pair(entryName, newVariant)); + } + else + { + // Add a simple native type to map + ::qpid::types::Variant entryValue; + EncodeObject(kvp.Value, entryValue); + std::string entryName = QpidMarshal::ToNative(kvp.Key); + theMapp.insert(std::make_pair(entryName, entryValue)); + } + } + } + + + + // + // The given object is a List. + // Add its elements to the qpid list. + // + void Message::Encode(::qpid::types::Variant::List & theListp, + VList ^ theObjp) + { + // iterate the items, converting each to a variant and adding to the map + for each (System::Object ^ listObj in theObjp) + { + if (objIsMap(listObj)) + { + // Recurse on inner map + // Allocate a map + ::qpid::types::Variant::Map newMap; + + // Add the map variables to the map + Encode(newMap, (VMap ^)listObj); + + // Create a variant entry for the inner map + std::auto_ptr<::qpid::types::Variant> newVariantp(new ::qpid::types::Variant(newMap)); + + // Add inner map to outer list + theListp.push_back(*newVariantp); + } + else if (objIsList(listObj)) + { + // Recurse on inner list + // Allocate a list + ::qpid::types::Variant::List newList; + + // Add the List variables to the list + Encode(newList, (VList ^)listObj); + + // Create a variant entry for the inner list + std::auto_ptr<::qpid::types::Variant> newVariantp(new ::qpid::types::Variant(newList)); + + // Add inner list to outer list + theListp.push_back(*newVariantp); + } + else + { + // Add a simple native type to list + ::qpid::types::Variant entryValue; + EncodeObject(listObj, entryValue); + theListp.push_back(entryValue); + } + } + } + + + + // + // Returns a variant representing simple native type object. + // Not to be called for Map/List objects. + // + void Message::EncodeObject(System::Object ^ theObjp, + ::qpid::types::Variant & targetp) + { + System::Type ^ typeP = (*theObjp).GetType(); + System::TypeCode typeCode = System::Type::GetTypeCode( typeP ); + + switch (typeCode) + { + case System::TypeCode::Boolean : + targetp = System::Convert::ToBoolean(theObjp); + break; + + case System::TypeCode::Byte : + targetp = System::Convert::ToByte(theObjp); + break; + + case System::TypeCode::UInt16 : + targetp = System::Convert::ToUInt16(theObjp); + break; + + case System::TypeCode::UInt32 : + targetp = System::Convert::ToUInt32(theObjp); + break; + + case System::TypeCode::UInt64 : + targetp = System::Convert::ToUInt64(theObjp); + break; + + case System::TypeCode::Char : + case System::TypeCode::SByte : + targetp = System::Convert::ToSByte(theObjp); + break; + + case System::TypeCode::Int16 : + targetp = System::Convert::ToInt16(theObjp); + break; + + case System::TypeCode::Int32 : + targetp = System::Convert::ToInt32(theObjp); + break; + + case System::TypeCode::Int64 : + targetp = System::Convert::ToInt64(theObjp); + break; + + case System::TypeCode::Single : + targetp = System::Convert::ToSingle(theObjp); + break; + + case System::TypeCode::Double : + targetp = System::Convert::ToDouble(theObjp); + break; + + case System::TypeCode::String : + { + std::string rString; + System::String ^ rpString; + + rpString = System::Convert::ToString(theObjp); + rString = QpidMarshal::ToNative(rpString); + targetp = rString; + } + break; + + + default: + + throw gcnew System::NotImplementedException(); + + } + } + + + // Properties... + //void Message::setReplyTo(System::String ^ address) //{ // messagep->setReplyTo(QpidMarshal::ToNative(address)); @@ -199,4 +454,215 @@ namespace messaging { return gcnew String(messagep->getContent().c_str()); } + + // + // User wants to extract a Dictionary from the message + // + void Message::getContent(System::Collections::Generic::Dictionary< + System::String^, + System::Object^> ^ dict) + { + // Extract the message map from the message + ::qpid::types::Variant::Map map; + + ::qpid::messaging::decode(*messagep, map, QpidMarshal::ToNative("amqp/map")); + + Decode(dict, map); + } + + + // Given a user Dictionary and a qpid map, + // extract the qpid elements and put them into the dictionary. + // + void Message::Decode(VMap ^ dict, ::qpid::types::Variant::Map & map) + { + // For each object in the message map, + // create a .NET object and add it to the dictionary. + for (::qpid::types::Variant::Map::const_iterator i = map.begin(); i != map.end(); ++i) { + // Get the name + System::String ^ elementName = gcnew String(i->first.c_str()); + + ::qpid::types::Variant variant = i->second; + ::qpid::types::VariantType vType = variant.getType(); + + switch (vType) + { + case ::qpid::types::VAR_BOOL: + dict[elementName] = variant.asBool(); + break; + + case ::qpid::types::VAR_UINT8: + dict[elementName] = variant.asUint8(); + break; + + case ::qpid::types::VAR_UINT16: + dict[elementName] = variant.asUint16(); + break; + + case ::qpid::types::VAR_UINT32: + dict[elementName] = variant.asUint32(); + break; + + case ::qpid::types::VAR_UINT64: + dict[elementName] = variant.asUint64(); + break; + + case ::qpid::types::VAR_INT8: + dict[elementName] = variant.asInt8(); + break; + + case ::qpid::types::VAR_INT16: + dict[elementName] = variant.asInt16(); + break; + + case ::qpid::types::VAR_INT32: + dict[elementName] = variant.asInt32(); + break; + + case ::qpid::types::VAR_INT64: + dict[elementName] = variant.asInt64(); + break; + + case ::qpid::types::VAR_FLOAT: + dict[elementName] = variant.asFloat(); + break; + + case ::qpid::types::VAR_DOUBLE: + dict[elementName] = variant.asDouble(); + break; + + case ::qpid::types::VAR_STRING: + { + System::String ^ elementValue = gcnew System::String(variant.asString().c_str()); + dict[elementName] = elementValue; + break; + } + case ::qpid::types::VAR_MAP: + { + VMap ^ newDict = gcnew VMap(); + + Decode (newDict, variant.asMap()); + + dict[elementName] = newDict; + break; + } + + case ::qpid::types::VAR_LIST: + { + VList ^ newList = gcnew VList(); + + Decode (newList, variant.asList()); + + dict[elementName] = newList; + break; + } + + case ::qpid::types::VAR_UUID: + break; + } + } + } + + + // + // User wants to extract a list from the message + // + void Message::getContent(System::Collections::Generic::List< + System::Object^> ^ list) + { + // Extract the message map from the message + ::qpid::types::Variant::List vList; + + ::qpid::messaging::decode(*messagep, vList, QpidMarshal::ToNative("amqp/list")); + + Decode(list, vList); + } + + + void Message::Decode(VList ^ vList, ::qpid::types::Variant::List & qpidList) + { + // For each object in the message map, + // create a .NET object and add it to the dictionary. + for (::qpid::types::Variant::List::const_iterator i = qpidList.begin(); i != qpidList.end(); ++i) + { + ::qpid::types::Variant variant = *i; + ::qpid::types::VariantType vType = variant.getType(); + + switch (vType) + { + case ::qpid::types::VAR_BOOL: + (*vList).Add(variant.asBool()); + break; + + case ::qpid::types::VAR_UINT8: + (*vList).Add(variant.asUint8()); + break; + + case ::qpid::types::VAR_UINT16: + (*vList).Add(variant.asUint16()); + break; + + case ::qpid::types::VAR_UINT32: + (*vList).Add(variant.asUint32()); + break; + + case ::qpid::types::VAR_UINT64: + (*vList).Add(variant.asUint64()); + break; + + case ::qpid::types::VAR_INT8: + (*vList).Add(variant.asInt8()); + break; + + case ::qpid::types::VAR_INT16: + (*vList).Add(variant.asInt16()); + break; + + case ::qpid::types::VAR_INT32: + (*vList).Add(variant.asInt32()); + break; + + case ::qpid::types::VAR_INT64: + (*vList).Add(variant.asInt64()); + break; + + case ::qpid::types::VAR_FLOAT: + (*vList).Add(variant.asFloat()); + break; + + case ::qpid::types::VAR_DOUBLE: + (*vList).Add(variant.asDouble()); + break; + + case ::qpid::types::VAR_STRING: + { + System::String ^ elementValue = gcnew System::String(variant.asString().c_str()); + (*vList).Add(elementValue); + break; + } + case ::qpid::types::VAR_MAP: + { + VMap ^ newDict = gcnew VMap(); + + Decode (newDict, variant.asMap()); + + (*vList).Add(newDict); + break; + } + + case ::qpid::types::VAR_LIST: + { + VList ^ newList = gcnew VList(); + + Decode (newList, variant.asList()); + + (*vList).Add(newList); + break; + } + + case ::qpid::types::VAR_UUID: + break; + } + } + } }}}} diff --git a/cpp/bindings/qpid/dotnet/src/Message.h b/cpp/bindings/qpid/dotnet/src/Message.h index 2219112d3f..c308fdf29f 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.h +++ b/cpp/bindings/qpid/dotnet/src/Message.h @@ -31,11 +31,19 @@ namespace apache { namespace qpid { namespace messaging { +typedef System::Collections::Generic::Dictionary< + System::String^, + System::Object^> + VMap; + +typedef System::Collections::Generic::List< + System::Object^> + VList; + /// /// Message is a managed wrapper for a ::qpid::messaging::Message /// - public ref class Message { @@ -43,11 +51,57 @@ namespace messaging { // Kept object deletion code void Cleanup(); + bool objIsMap (System::Object ^ op) + { + return (*op).GetType() == pVMapType; + } + + bool objIsList(System::Object ^ op) + { + return (*op).GetType() == pVListType; + } + + // The given object is a Dictionary. + // Add its elements to the qpid map. + void Encode(::qpid::types::Variant::Map & theMapp, + VMap ^ theObjp); + + // The given object is a List. + // Add its elements to the qpid list. + void Encode(::qpid::types::Variant::List & theListp, + VList ^ theObjp); + + // Returns a variant representing simple native type object. + // Not to be called for Map/List objects. + void EncodeObject(System::Object ^ theObjp, + ::qpid::types::Variant & targetp); + + + void Decode(VMap ^ dict, ::qpid::types::Variant::Map & map); + + void Decode(VList ^ vList, ::qpid::types::Variant::List & qpidList); + + + // map and list for type comparison + VMap aVMap; + VList aVList; + System::Type ^ pVMapType; + System::Type ^ pVListType; + public: + // Create from String Message(System::String ^ bytes); + + // Create from object + Message(System::Object ^ obj); + + // Create reference copy Message(::qpid::messaging::Message * msgp); + ~Message(); !Message(); + + // Copy constructor Message(const Message % rhs); // The kept object in the Messaging C++ DLL @@ -88,5 +142,12 @@ namespace messaging { void setContent(System::String ^ content); System::String ^ getContent(); + + void getContent(System::Collections::Generic::Dictionary< + System::String^, + System::Object^> ^ dict); + + void getContent(System::Collections::Generic::List< + System::Object^> ^); }; }}}} -- cgit v1.2.1