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