Introduction to the Library
The OpenSAML 2.0 library provides a mechanism for reading and writing SAML through C++ objects. It is designed along the same lines as the Java version (see OSTwoUsrManJavaLibIntro).
Differences from Java
While the general design is the same, there are some differences. The C++ library does not include any reference counting or garbage collection, so object lifetime is the responsibility of the calling application. Objects are always used through pointers or references and can be copied only through explicit clone methods.
XML structures are trees, of course, and SAML objects also organize into trees. Once an object is added or set as the child of some other object, it is owned by that parent object, and must not be deleted except by deleting the parent. This is true even when accessor methods provide non-const access to the child. The lone exception to this rule is the special
XMLObject::detach()= method, which allows a root object's child to be turned into a new tree root, freeing the parent.
Another difference from Java is that DOM management is much more complex in C++ due to the fact that Xerces assigns ownership of DOM nodes and manages their lifetime based on DOM documents. This means applications must take care when using DOMDocument objects and ensure that they are freed appropriately. Usually this is best done by binding a document to a given SAML object during the marshalling or unmarshalling process. The API documentation takes care to note how this can be done. By default, marshalling and unmarshalling will often do the right thing, but the caller can override behavior in special cases.
Most other differences are minor API issues or adaptations that allow SAML object collections to be manipulated properly with STL-aware algorithms instead of with Java-style collection approaches. The internal implementation is also quite different, but this is generally of concern only to extension developers.
How it Works
Next refer to "Creating SAML Objects from an XML Source" for information on how to perform the parse/unmarshall step or "Creating SAML Objects from Scratch" for information on how to build SAML Objects from scratch.
Initializing and shutting down the Library
Library initialization takes place using the
SAMLConfig::init() method. SAMLConfig is a singleton that is accessed using the
SAMLConfig::getInstance() method, like so:
Shutdown occurs with the
The library can be cleanly initialized, shutdown, and then initialized again.
Configuring the Library
Configuration is another main difference. In Java, an XML configuration file is used to map types and elements to implementation classes. In C++, objects cannot be constructed from class name alone (no reflection support), which means that runtime registration of implementations is required anyway. Having a configuration file would simply add another layer of indirection.
During library initialization, all of the built-in implementation classes and builders are registered against the schema types and element names that are supported. Following this step, applications can register their own classes for new types and elements, or replace the built-in implementations with their own.
Default Object Provider
The XML-Tooling layer includes a fail-safe implementation class that is used when an unrecognized element or type is encountered when unmarshalling a DOM. By default this implementation class is designed NOT to expose the actual information found in the DOM, but merely maintain its XML integrity when required to marshall or unmarshall itself. Essentially it will be "invisible" to the application and its parent except as a generic XMLObject.
An alternative implementation is available that does detailed DOM processing and exposes the DOM content in a friendly fashion through the
ElementProxy interface. This can be registered at runtime as follows:
The original, more efficient, default can be restored with:
At runtime, you'll never actually be able to do anything useful with the XMLObject interface alone. You'll generally either get type-safe pointers to useful interfaces, or you'll have to cast from XMLObject to the interface you need. With the efficient default builder, any cast you perform will fail, leaving the information itself "intact" but not accessible. With the more advanced version, you can cast to
ElementProxy to read or modify the data.