MxM Data Object interchange
A desirable aspect of MxM engines is the ability to interchange data between them, even between engines wrote by different software houses or development teams.
All MxM interfaces extends a single base class, the MXMObject: when possible, the defined methods accepts or returns other interfaces, but sometimes they exchange pure MXMObjects, usually when no specific interface is defined for that kind of object, as of certificates, asymmetric keys, symmetric transported keys, and so on.
Basic interchange informations are available through the basics MXMObject’s methods:
1) const void * getData() const: this method returns an agnostic pointer to object representation
2) size_t getDataSize() const: this one tells the size of such representation
3) string getContentType() const: this one can inform us on the type, the semantics, of the data pointer
A very basic and non-interoperable, but safe, scenario, is one where we just implement getContentType to return a string identifying the “developer entity”, to clearly identify objects we know and discard objects from other vendors: objects coming from ourselves will be easily brought back to its original runtime format via dynamic_cast.
A simple level of interoperability can be achieved about XML data objects, those representing the DRM data dictionary: in this case, we can return the XML object serialization as a string from the getData method, and specify another kind of content type ( xml, fairly obviously ).
A class with such interchange functionality should be able to “load” itself from:
1) a MXMObject returning data with xml content type
2) a XML data object with the runtime type this class manages
3) a XML file or string containing the xml serialization of a data object with the runtime type this class manages
and sholud return, beside the XML serialization, the correspondent runtime representation as a data object. This loading procedure relies on the ability to serialize a data object to XML and deserialize it back to a C++ class instance, when no runtime model is shared between sender and receiver of the method invocation.
Note that such kind of classes are pervasive in the MxM middleware: almost all those parsers and creators are classes that provide shortcut interface methods to reach or populate properties of XML data objects, hiding them via incapsulation.
We refer to XML data objects as level 0 classes, and to their shells, usually implementing both creation and parsing interfaces, as level 1 classes, so method naming will reflect this habit; additionally, content type strings will be wrapped between separator characters (we chose the full stop), so that multiple content types can be composed in one single string without ambiguity.
The interchangeability at XML level via XML data object representation is formalized via a template class, whose template type is the XML data object type itself: this way, we can declare classes interchanging a specific XML data object type
template< class DataObject >
: virtual public MXMObject
//! userialize from stream
virtual DataObject* unserializeXML( istream & ) const = 0;
//! userialize from file
virtual DataObject* unserializeFile( const string & ) const = 0;
//! serialize mxm_dataobject to xml
virtual string serializeLevel0( const DataObject & ) const = 0;
[ omissis ]
//! updates internal xml representation
//! xml string representation
virtual const void* getData() const;
//! xml string representation size
virtual size_t getDataSize() const;
virtual string getContentType() const;
//! loads a mxm_dataobject
void loadLevel0( const DataObject & ) throw( MXMException );
//! if content type has ‘xml’, deserializes
void loadLevel0( const MXMObject & ) throw( MXMException );
//! deserializes the file
void loadLevel0( const string & fname ) throw( MXMException );
//! deserializes the string
void loadXML( const string & xml ) throw( MXMException );
//! get data object representation
DataObject & getLevel0() throw( MXMException );
DataObject const & getLevel0() const throw( MXMException );
The public interface of this class exactly implements the desired functionality exposed above, while the content type is fixed to .xml. .
Actual transformations are performed by the three pure virtual methods, delegated to serialize (to string) and de-serialize (from string or stream). Implementation of these methods is trivial, and always relies on serialization / de-serialization functions provided by the mxm_dataobject library.
The updateXML method updates internal xml representation referred by getData and getDataSize; this method must be explicitly called by child constructors and by methods that update the hidden dataobject.