X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fio%2FAbstractXMLObjectMarshaller.cpp;h=a33016cca3d899e4f95a8240ca4994f3c4ce35a4;hb=77769b2e300d1295b8a5d717d9ede50e27d70cea;hp=d5c4ac01f5b97861a398a40254a33f24343130b7;hpb=676c0279ec7584dbb046c84ed9768c726afc009d;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.cpp b/xmltooling/io/AbstractXMLObjectMarshaller.cpp index d5c4ac0..a33016c 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectMarshaller.cpp @@ -21,9 +21,11 @@ */ #include "internal.h" -#include "DOMCachingXMLObject.h" #include "exceptions.h" #include "io/AbstractXMLObjectMarshaller.h" +#ifndef XMLTOOLING_NO_XMLSEC + #include "signature/Signature.h" +#endif #include "util/NDC.h" #include "util/XMLConstants.h" #include "util/XMLHelper.h" @@ -33,45 +35,47 @@ #include #include +#ifndef XMLTOOLING_NO_XMLSEC + using namespace xmlsignature; +#endif using namespace xmltooling; using namespace log4cpp; using namespace std; #define XT_log (*static_cast(m_log)) -AbstractXMLObjectMarshaller::AbstractXMLObjectMarshaller() - : m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Marshaller")) {} - -DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const +DOMElement* AbstractXMLObjectMarshaller::marshall( + DOMDocument* document +#ifndef XMLTOOLING_NO_XMLSEC + ,const std::vector* sigs +#endif + ) const { #ifdef _DEBUG xmltooling::NDC ndc("marshall"); #endif if (XT_log.isDebugEnabled()) { - XT_log.debug("starting to marshalling %s", xmlObject->getElementQName().toString().c_str()); + XT_log.debug("starting to marshal %s", getElementQName().toString().c_str()); } - DOMCachingXMLObject* dc=dynamic_cast(xmlObject); - if (dc) { - DOMElement* cachedDOM=dc->getDOM(); - if (cachedDOM) { - if (!document || document==cachedDOM->getOwnerDocument()) { - XT_log.debug("XMLObject has a usable cached DOM, reusing it"); - if (document) - setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); - dc->releaseParentDOM(true); - return cachedDOM; - } - - // We have a DOM but it doesn't match the document we were given. This both sucks and blows. - // Without an adoptNode option to maintain the child pointers, we have to either import the - // DOM while somehow reassigning all the nested references (which amounts to a complete - // *unmarshall* operation), or we just release the existing DOM and hope that we can get - // it back. This depends on all objects being able to preserve their DOM at all costs. - dc->releaseChildrenDOM(true); - dc->releaseDOM(); + DOMElement* cachedDOM=getDOM(); + if (cachedDOM) { + if (!document || document==cachedDOM->getOwnerDocument()) { + XT_log.debug("XMLObject has a usable cached DOM, reusing it"); + if (document) + setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM); + releaseParentDOM(true); + return cachedDOM; } + + // We have a DOM but it doesn't match the document we were given. This both sucks and blows. + // Without an adoptNode option to maintain the child pointers, we have to either import the + // DOM while somehow reassigning all the nested references (which amounts to a complete + // *unmarshall* operation), or we just release the existing DOM and hope that we can get + // it back. This depends on all objects being able to preserve their DOM at all costs. + releaseChildrenDOM(true); + releaseDOM(); } // If we get here, we didn't have a usable DOM (and/or we released the one we had). @@ -81,108 +85,114 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocum document=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument(); bindDocument=true; } + + XercesJanitor janitor(bindDocument ? document : NULL); - try { - XT_log.debug("creating root element to marshall"); - DOMElement* domElement = document->createElementNS( - xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart() - ); - setDocumentElement(document, domElement); - marshallInto(*xmlObject, domElement); - - //Recache the DOM. - if (dc) { - XT_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not "); - dc->setDOM(domElement, bindDocument); - dc->releaseParentDOM(true); - } + XT_log.debug("creating root element to marshall"); + DOMElement* domElement = document->createElementNS( + getElementQName().getNamespaceURI(), getElementQName().getLocalPart() + ); + setDocumentElement(document, domElement); +#ifndef XMLTOOLING_NO_XMLSEC + marshallInto(domElement, sigs); +#else + marshallInto(domElement); +#endif + //Recache the DOM. + XT_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not "); + setDOM(domElement, bindDocument); + janitor.release(); // safely transferred + releaseParentDOM(true); - return domElement; - } - catch (...) { - // Delete the document if need be, and rethrow. - if (bindDocument) { - document->release(); - } - throw; - } + return domElement; } -DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement) const +DOMElement* AbstractXMLObjectMarshaller::marshall( + DOMElement* parentElement +#ifndef XMLTOOLING_NO_XMLSEC + ,const std::vector* sigs +#endif + ) const { #ifdef _DEBUG xmltooling::NDC ndc("marshall"); #endif if (XT_log.isDebugEnabled()) { - XT_log.debug("starting to marshalling %s", xmlObject->getElementQName().toString().c_str()); + XT_log.debug("starting to marshalling %s", getElementQName().toString().c_str()); } - DOMCachingXMLObject* dc=dynamic_cast(xmlObject); - if (dc) { - DOMElement* cachedDOM=dc->getDOM(); - if (cachedDOM) { - if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) { - XT_log.debug("XMLObject has a usable cached DOM, reusing it"); - if (parentElement!=cachedDOM->getParentNode()) { - parentElement->appendChild(cachedDOM); - dc->releaseParentDOM(true); - } - return cachedDOM; + DOMElement* cachedDOM=getDOM(); + if (cachedDOM) { + if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) { + XT_log.debug("XMLObject has a usable cached DOM, reusing it"); + if (parentElement!=cachedDOM->getParentNode()) { + parentElement->appendChild(cachedDOM); + releaseParentDOM(true); } - - // We have a DOM but it doesn't match the document we were given. This both sucks and blows. - // Without an adoptNode option to maintain the child pointers, we have to either import the - // DOM while somehow reassigning all the nested references (which amounts to a complete - // *unmarshall* operation), or we just release the existing DOM and hope that we can get - // it back. This depends on all objects being able to preserve their DOM at all costs. - dc->releaseChildrenDOM(true); - dc->releaseDOM(); + return cachedDOM; } + + // We have a DOM but it doesn't match the document we were given. This both sucks and blows. + // Without an adoptNode option to maintain the child pointers, we have to either import the + // DOM while somehow reassigning all the nested references (which amounts to a complete + // *unmarshall* operation), or we just release the existing DOM and hope that we can get + // it back. This depends on all objects being able to preserve their DOM at all costs. + releaseChildrenDOM(true); + releaseDOM(); } // If we get here, we didn't have a usable DOM (and/or we released the one we had). XT_log.debug("creating root element to marshall"); DOMElement* domElement = parentElement->getOwnerDocument()->createElementNS( - xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart() + getElementQName().getNamespaceURI(), getElementQName().getLocalPart() ); parentElement->appendChild(domElement); - marshallInto(*xmlObject, domElement); +#ifndef XMLTOOLING_NO_XMLSEC + marshallInto(domElement, sigs); +#else + marshallInto(domElement); +#endif //Recache the DOM. - if (dc) { - XT_log.debug("caching DOM for XMLObject"); - dc->setDOM(domElement, false); - dc->releaseParentDOM(true); - } + XT_log.debug("caching DOM for XMLObject"); + setDOM(domElement, false); + releaseParentDOM(true); return domElement; } - -void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const + +void AbstractXMLObjectMarshaller::marshallInto( + DOMElement* targetElement +#ifndef XMLTOOLING_NO_XMLSEC + ,const std::vector* sigs +#endif + ) const { - if (xmlObject.getElementQName().hasPrefix()) - targetElement->setPrefix(xmlObject.getElementQName().getPrefix()); - marshallElementType(xmlObject, targetElement); - marshallNamespaces(xmlObject, targetElement); - marshallAttributes(xmlObject, targetElement); - marshallChildElements(xmlObject, targetElement); - marshallElementContent(xmlObject, targetElement); + if (getElementQName().hasPrefix()) + targetElement->setPrefix(getElementQName().getPrefix()); - /* TODO Signing/Encryption - if (xmlObject instanceof SignableXMLObject) { - signElement(targetElement, xmlObject); + if (m_schemaLocation) { + static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n); + if (targetElement->getParentNode()==NULL || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE) + targetElement->setAttributeNS(XMLConstants::XSI_NS,schemaLocation,m_schemaLocation); } - if (xmlObject instanceof EncryptableXMLObject) { - encryptElement(targetElement, xmlObject); + marshallElementType(targetElement); + marshallNamespaces(targetElement); + marshallAttributes(targetElement); + marshallContent(targetElement); + +#ifndef XMLTOOLING_NO_XMLSEC + if (sigs) { + for_each(sigs->begin(),sigs->end(),mem_fun(&Signature::sign)); } - */ +#endif } -void AbstractXMLObjectMarshaller::marshallElementType(XMLObject& xmlObject, DOMElement* domElement) const +void AbstractXMLObjectMarshaller::marshallElementType(DOMElement* domElement) const { - const QName* type = xmlObject.getSchemaType(); + const QName* type = getSchemaType(); if (type) { XT_log.debug("setting xsi:type attribute for XMLObject"); @@ -210,7 +220,7 @@ void AbstractXMLObjectMarshaller::marshallElementType(XMLObject& xmlObject, DOME XMLString::release(&xsivalue); XT_log.debug("Adding XSI namespace to list of namespaces used by XMLObject"); - xmlObject.addNamespace(Namespace(XMLConstants::XSI_NS, XMLConstants::XSI_PREFIX)); + addNamespace(Namespace(XMLConstants::XSI_NS, XMLConstants::XSI_PREFIX)); } } @@ -272,40 +282,28 @@ public: } }; -void AbstractXMLObjectMarshaller::marshallNamespaces(const XMLObject& xmlObject, DOMElement* domElement) const +void AbstractXMLObjectMarshaller::marshallNamespaces(DOMElement* domElement) const { XT_log.debug("marshalling namespace attributes for XMLObject"); - const set& namespaces = xmlObject.getNamespaces(); + const set& namespaces = getNamespaces(); for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement)); } -class _marshallchild : public binary_function { - void* m_log; -public: - _marshallchild(void* log) : m_log(log) {} - void operator()(XMLObject* obj, DOMElement* element) const { - if (!obj) - return; - if (XT_log.isDebugEnabled()) { - XT_log.debug("getting marshaller for child XMLObject: %s", obj->getElementQName().toString().c_str()); - } - - const Marshaller* marshaller = Marshaller::getMarshaller(obj); - if (!marshaller) { - XT_log.error( - "no default unmarshaller installed, unknown child object: %s", - obj->getElementQName().toString().c_str() - ); - throw MarshallingException("Marshaller found unknown child element, but no default marshaller was found."); - } - element->appendChild(marshaller->marshall(obj, element)); - } -}; - -void AbstractXMLObjectMarshaller::marshallChildElements(const XMLObject& xmlObject, DOMElement* domElement) const +void AbstractXMLObjectMarshaller::marshallContent(DOMElement* domElement) const { - XT_log.debug("marshalling child elements for XMLObject"); - - const list& children=xmlObject.getOrderedChildren(); - for_each(children.begin(),children.end(),bind2nd(_marshallchild(m_log),domElement)); + XT_log.debug("marshalling text and child elements for XMLObject"); + + const XMLCh* val; + unsigned int pos=0; + const list& children=getOrderedChildren(); + for (list::const_iterator i=children.begin(); i!=children.end(); ++i, ++pos) { + val = getTextContent(pos); + if (val && *val) + domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val)); + if (*i) + (*i)->marshall(domElement); + } + val = getTextContent(pos); + if (val && *val) + domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val)); }