Merged marshalling/unmarshalling methods into core interface.
[shibboleth/cpp-xmltooling.git] / xmltooling / io / AbstractXMLObjectUnmarshaller.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  * AbstractXMLObjectUnmarshaller.cpp\r
19  * \r
20  * A thread-safe abstract unmarshaller.\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "exceptions.h"\r
25 #include "XMLObjectBuilder.h"\r
26 #include "io/AbstractXMLObjectUnmarshaller.h"\r
27 #include "util/NDC.h"\r
28 #include "util/XMLConstants.h"\r
29 #include "util/XMLHelper.h"\r
30 \r
31 #include <xercesc/util/XMLUniDefs.hpp>\r
32 #include <log4cpp/Category.hh>\r
33 \r
34 using namespace xmltooling;\r
35 using namespace log4cpp;\r
36 using namespace std;\r
37 \r
38 #define XT_log (*static_cast<Category*>(m_log))\r
39 \r
40 XMLObject* AbstractXMLObjectUnmarshaller::unmarshall(DOMElement* element, bool bindDocument)\r
41 {\r
42 #ifdef _DEBUG\r
43     xmltooling::NDC ndc("unmarshall");\r
44 #endif\r
45 \r
46     if (XT_log.isDebugEnabled()) {\r
47         auto_ptr_char dname(element->getNodeName());\r
48         XT_log.debug("unmarshalling DOM element (%s)", dname.get());\r
49     }\r
50 \r
51     if (element->hasAttributes()) {\r
52         unmarshallAttributes(element);\r
53     }\r
54 \r
55     unmarshallChildElements(element);\r
56 \r
57     /* TODO: Signing\r
58     if (xmlObject instanceof SignableXMLObject) {\r
59         verifySignature(domElement, xmlObject);\r
60     }\r
61     */\r
62 \r
63     setDOM(element,bindDocument);\r
64     return this;\r
65 }\r
66 \r
67 void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domElement)\r
68 {\r
69 #ifdef _DEBUG\r
70     xmltooling::NDC ndc("unmarshallAttributes");\r
71 #endif\r
72     static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull};\r
73 \r
74     if (XT_log.isDebugEnabled()) {\r
75         auto_ptr_char dname(domElement->getNodeName());\r
76         XT_log.debug("unmarshalling attributes for DOM element (%s)", dname.get());\r
77     }\r
78 \r
79     DOMNamedNodeMap* attributes = domElement->getAttributes();\r
80     if (!attributes) {\r
81         XT_log.debug("no attributes to unmarshall");\r
82         return;\r
83     }\r
84 \r
85     DOMNode* childNode;\r
86     DOMAttr* attribute;\r
87     for (XMLSize_t i=0; i<attributes->getLength(); i++) {\r
88         childNode = attributes->item(i);\r
89 \r
90         // The child node should always be an attribute, but just in case\r
91         if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {\r
92             XT_log.debug("encountered child node of type %d in attribute list, ignoring it", childNode->getNodeType());\r
93             continue;\r
94         }\r
95 \r
96         attribute = static_cast<DOMAttr*>(childNode);\r
97         \r
98         const XMLCh* nsuri=attribute->getNamespaceURI();\r
99         if (XMLString::equals(nsuri,XMLConstants::XMLNS_NS)) {\r
100             if (XMLString::equals(attribute->getLocalName(),XMLConstants::XMLNS_PREFIX)) {\r
101                 XT_log.debug("found default namespace declaration, adding it to the list of namespaces on the XMLObject");\r
102                 addNamespace(Namespace(attribute->getValue(), NULL, true));\r
103                 continue;\r
104             }\r
105             else {\r
106                 XT_log.debug("found namespace declaration, adding it to the list of namespaces on the XMLObject");\r
107                 addNamespace(Namespace(attribute->getValue(), attribute->getLocalName(), true));\r
108                 continue;\r
109             }\r
110         }\r
111         else if (XMLString::equals(nsuri,XMLConstants::XSI_NS) && XMLString::equals(attribute->getLocalName(),type)) {\r
112             XT_log.debug("found xsi:type declaration, setting the schema type of the XMLObject");\r
113             auto_ptr<QName> xsitype(XMLHelper::getAttributeValueAsQName(attribute));\r
114             setSchemaType(xsitype.get());\r
115             continue;\r
116         }\r
117         else if (nsuri && !XMLString::equals(nsuri,XMLConstants::XML_NS)) {\r
118             XT_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject");\r
119             addNamespace(Namespace(nsuri, attribute->getPrefix()));\r
120         }\r
121 \r
122         XT_log.debug("processing generic attribute");\r
123         processAttribute(attribute);\r
124     }\r
125 }\r
126 \r
127 void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* domElement)\r
128 {\r
129 #ifdef _DEBUG\r
130     xmltooling::NDC ndc("unmarshallChildElements");\r
131 #endif\r
132 \r
133     if (XT_log.isDebugEnabled()) {\r
134         auto_ptr_char dname(domElement->getNodeName());\r
135         XT_log.debug("unmarshalling child elements of DOM element (%s)", dname.get());\r
136     }\r
137 \r
138     DOMNodeList* childNodes = domElement->getChildNodes();\r
139     DOMNode* childNode;\r
140     if (!childNodes || childNodes->getLength()==0) {\r
141         XT_log.debug("element had no children");\r
142         return;\r
143     }\r
144 \r
145     XMLToolingConfig& config=XMLToolingConfig::getConfig();\r
146     for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {\r
147         childNode = childNodes->item(i);\r
148         if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {\r
149             const XMLObjectBuilder* builder = XMLObjectBuilder::getBuilder(static_cast<DOMElement*>(childNode));\r
150             if (!builder) {\r
151                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
152                 XT_log.error("no default builder installed, found unknown child element (%s)", cname->toString().c_str());\r
153                 throw UnmarshallingException("Unmarshaller found unknown child element, but no default builder was found.");\r
154             }\r
155 \r
156             if (XT_log.isDebugEnabled()) {\r
157                 auto_ptr<QName> cname(XMLHelper::getNodeQName(childNode));\r
158                 XT_log.debug("unmarshalling child element (%s)", cname->toString().c_str());\r
159             }\r
160 \r
161             // Retain ownership of the unmarshalled child until it's processed by the parent.\r
162             auto_ptr<XMLObject> childObject(builder->buildObject(static_cast<DOMElement*>(childNode)));\r
163             childObject->unmarshall(static_cast<DOMElement*>(childNode));\r
164             processChildElement(childObject.get(), static_cast<DOMElement*>(childNode));\r
165             childObject.release();\r
166         }\r
167         else if (childNode->getNodeType() == DOMNode::TEXT_NODE) {\r
168             XT_log.debug("processing element content");\r
169             processElementContent(childNode->getNodeValue());\r
170         }\r
171     }\r
172 }\r