Major revamp of credential and trust handling code, PKIX engine still needs work.
[shibboleth/cpp-xmltooling.git] / xmltooling / impl / UnknownElement.cpp
1 /*
2 *  Copyright 2001-2007 Internet2
3  * 
4 * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * UnknownElement.cpp
19  * 
20  * Basic implementation suitable for use as default for unrecognized content
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "impl/UnknownElement.h"
26 #include "util/NDC.h"
27 #include "util/XMLHelper.h"
28
29 #include <log4cpp/Category.hh>
30 #include <xercesc/framework/MemBufInputSource.hpp>
31 #include <xercesc/framework/Wrapper4InputSource.hpp>
32 #include <xercesc/util/XMLUniDefs.hpp>
33
34 using namespace xmltooling;
35 using namespace log4cpp;
36 using namespace std;
37 using xmlsignature::Signature;
38
39 void UnknownElementImpl::releaseDOM() const
40 {
41 #ifdef _DEBUG
42     xmltooling::NDC ndc("releaseDOM");
43 #endif
44     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLObject");
45     log.debug("releasing DOM for unknown content, preserving current DOM in XML form");
46
47     // We're losing our DOM, so assuming we have one, we preserve it.
48     serialize(m_xml);
49
50     // This takes care of the generic housekeeping now that we've preserved things.
51     AbstractDOMCachingXMLObject::releaseDOM();
52 }
53
54 XMLObject* UnknownElementImpl::clone() const
55 {
56     UnknownElementImpl* ret=new UnknownElementImpl();
57
58     // If there's no XML locally, serialize this object into the new one.
59     // Otherwise just copy it over.
60     if (m_xml.empty())
61         serialize(ret->m_xml);
62     else
63         ret->m_xml=m_xml;
64
65     return ret;
66 }
67
68 void UnknownElementImpl::serialize(string& s) const
69 {
70     if (getDOM())
71         XMLHelper::serialize(getDOM(),s);
72 }
73
74 DOMElement* UnknownElementImpl::marshall(
75     DOMDocument* document
76 #ifndef XMLTOOLING_NO_XMLSEC
77     ,const vector<Signature*>* sigs
78     ,const Credential* credential
79 #endif
80     ) const
81 {
82 #ifdef _DEBUG
83     xmltooling::NDC ndc("marshall");
84 #endif
85     
86     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLObject");
87     log.debug("marshalling unknown content");
88
89     DOMElement* cachedDOM=getDOM();
90     if (cachedDOM) {
91         if (!document || document==cachedDOM->getOwnerDocument()) {
92             log.debug("XMLObject has a usable cached DOM, reusing it");
93             if (document)
94                 setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);
95             releaseParentDOM(true);
96             return cachedDOM;
97         }
98         
99         // We have a DOM but it doesn't match the document we were given, so we import
100         // it into the new document.
101         cachedDOM=static_cast<DOMElement*>(document->importNode(cachedDOM, true));
102
103         // Recache the DOM.
104         setDocumentElement(document, cachedDOM);
105         log.debug("caching imported DOM for XMLObject");
106         setDOM(cachedDOM, false);
107         releaseParentDOM(true);
108         return cachedDOM;
109     }
110     
111     // If we get here, we didn't have a usable DOM.
112     // We need to reparse the XML we saved off into a new DOM.
113     bool bindDocument=false;
114     MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"UnknownElementImpl");
115     Wrapper4InputSource dsrc(&src,false);
116     log.debug("parsing XML back into DOM tree");
117     DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
118     if (document) {
119         // The caller insists on using his own document, so we now have to import the thing
120         // into it. Then we're just dumping the one we built.
121         log.debug("reimporting new DOM into caller-supplied document");
122         cachedDOM=static_cast<DOMElement*>(document->importNode(internalDoc->getDocumentElement(), true));
123         internalDoc->release();
124     }
125     else {
126         // We just bind the document we built to the object as the result.
127         cachedDOM=static_cast<DOMElement*>(internalDoc->getDocumentElement());
128         document=internalDoc;
129         bindDocument=true;
130     }
131
132     // Recache the DOM and clear the serialized copy.
133     setDocumentElement(document, cachedDOM);
134     log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not ");
135     setDOM(cachedDOM, bindDocument);
136     releaseParentDOM(true);
137     m_xml.erase();
138     return cachedDOM;
139 }
140
141
142 DOMElement* UnknownElementImpl::marshall(
143     DOMElement* parentElement
144 #ifndef XMLTOOLING_NO_XMLSEC
145     ,const vector<Signature*>* sigs
146     ,const Credential* credential
147 #endif
148     ) const
149 {
150 #ifdef _DEBUG
151     xmltooling::NDC ndc("marshall");
152 #endif
153     
154     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLObject");
155     log.debug("marshalling unknown content");
156
157     DOMElement* cachedDOM=getDOM();
158     if (cachedDOM) {
159         if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {
160             log.debug("XMLObject has a usable cached DOM, reusing it");
161             parentElement->appendChild(cachedDOM);
162             releaseParentDOM(true);
163             return cachedDOM;
164         }
165         
166         // We have a DOM but it doesn't match the document we were given, so we import
167         // it into the new document.
168         cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(cachedDOM, true));
169
170         // Recache the DOM.
171         parentElement->appendChild(cachedDOM);
172         log.debug("caching imported DOM for XMLObject");
173         setDOM(cachedDOM, false);
174         releaseParentDOM(true);
175         return cachedDOM;
176     }
177     
178     // If we get here, we didn't have a usable DOM (and/or we flushed the one we had).
179     // We need to reparse the XML we saved off into a new DOM.
180     MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"UnknownElementImpl");
181     Wrapper4InputSource dsrc(&src,false);
182     log.debug("parsing XML back into DOM tree");
183     DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
184     
185     log.debug("reimporting new DOM into caller-supplied document");
186     cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(internalDoc->getDocumentElement(), true));
187     internalDoc->release();
188
189     // Recache the DOM and clear the serialized copy.
190     parentElement->appendChild(cachedDOM);
191     log.debug("caching DOM for XMLObject");
192     setDOM(cachedDOM, false);
193     releaseParentDOM(true);
194     m_xml.erase();
195     return cachedDOM;
196 }
197
198 XMLObject* UnknownElementImpl::unmarshall(DOMElement* element, bool bindDocument)
199 {
200     setDOM(element, bindDocument);
201     return this;
202 }
203
204 XMLObject* UnknownElementBuilder::buildObject(
205     const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType
206     ) const {
207     return new UnknownElementImpl(nsURI,localName,prefix);
208 }
209