1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.io;
18
19 import javax.xml.namespace.QName;
20
21 import org.opensaml.xml.Configuration;
22 import org.opensaml.xml.Namespace;
23 import org.opensaml.xml.XMLObject;
24 import org.opensaml.xml.XMLObjectBuilder;
25 import org.opensaml.xml.XMLObjectBuilderFactory;
26 import org.opensaml.xml.schema.XSBooleanValue;
27 import org.opensaml.xml.util.DatatypeHelper;
28 import org.opensaml.xml.util.XMLConstants;
29 import org.opensaml.xml.util.XMLHelper;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.w3c.dom.Attr;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.NamedNodeMap;
35 import org.w3c.dom.Node;
36 import org.w3c.dom.NodeList;
37 import org.w3c.dom.Text;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public abstract class AbstractXMLObjectUnmarshaller implements Unmarshaller {
53
54
55 private final Logger log = LoggerFactory.getLogger(AbstractXMLObjectUnmarshaller.class);
56
57
58 private QName targetQName;
59
60
61 private XMLObjectBuilderFactory xmlObjectBuilderFactory;
62
63
64 private UnmarshallerFactory unmarshallerFactory;
65
66
67
68
69 protected AbstractXMLObjectUnmarshaller() {
70 xmlObjectBuilderFactory = Configuration.getBuilderFactory();
71 unmarshallerFactory = Configuration.getUnmarshallerFactory();
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85 protected AbstractXMLObjectUnmarshaller(String targetNamespaceURI, String targetLocalName) {
86 targetQName = XMLHelper.constructQName(targetNamespaceURI, targetLocalName, null);
87
88 xmlObjectBuilderFactory = Configuration.getBuilderFactory();
89 unmarshallerFactory = Configuration.getUnmarshallerFactory();
90 }
91
92
93 public XMLObject unmarshall(Element domElement) throws UnmarshallingException {
94 log.trace("Starting to unmarshall DOM element {}", XMLHelper.getNodeQName(domElement));
95
96 checkElementIsTarget(domElement);
97
98 XMLObject xmlObject = buildXMLObject(domElement);
99
100 log.trace("Unmarshalling attributes of DOM Element {}", XMLHelper.getNodeQName(domElement));
101 NamedNodeMap attributes = domElement.getAttributes();
102 Node attribute;
103 for (int i = 0; i < attributes.getLength(); i++) {
104 attribute = attributes.item(i);
105
106
107 if (attribute.getNodeType() == Node.ATTRIBUTE_NODE) {
108 unmarshallAttribute(xmlObject, (Attr) attribute);
109 }
110 }
111
112 log.trace("Unmarshalling other child nodes of DOM Element {}", XMLHelper.getNodeQName(domElement));
113 NodeList childNodes = domElement.getChildNodes();
114 Node childNode;
115 for (int i = 0; i < childNodes.getLength(); i++) {
116 childNode = childNodes.item(i);
117
118 if (childNode.getNodeType() == Node.ATTRIBUTE_NODE) {
119 unmarshallAttribute(xmlObject, (Attr) childNode);
120 } else if (childNode.getNodeType() == Node.ELEMENT_NODE) {
121 unmarshallChildElement(xmlObject, (Element) childNode);
122 } else if (childNode.getNodeType() == Node.TEXT_NODE) {
123 unmarshallTextContent(xmlObject, (Text) childNode);
124 }
125 }
126
127 xmlObject.setDOM(domElement);
128 return xmlObject;
129 }
130
131
132
133
134
135
136
137
138
139 protected void checkElementIsTarget(Element domElement) throws UnmarshallingException {
140 QName elementName = XMLHelper.getNodeQName(domElement);
141
142 if (targetQName == null) {
143 log.trace(
144 "Targeted QName checking is not available for this unmarshaller, DOM Element {} was not verified",
145 elementName);
146 return;
147 }
148
149 log.trace("Checking that {} meets target criteria.", elementName);
150
151 QName type = XMLHelper.getXSIType(domElement);
152
153 if (type != null && type.equals(targetQName)) {
154 log.trace("{} schema type matches target.", elementName);
155 return;
156 } else {
157 if (elementName.equals(targetQName)) {
158 log.trace("{} element name matches target.", elementName);
159 return;
160 } else {
161 String errorMsg = "This unmarshaller only operates on " + targetQName + " elements not " + elementName;
162 log.error(errorMsg);
163 throw new UnmarshallingException(errorMsg);
164 }
165 }
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 protected XMLObject buildXMLObject(Element domElement) throws UnmarshallingException {
184 log.trace("Building XMLObject for {}", XMLHelper.getNodeQName(domElement));
185 XMLObjectBuilder xmlObjectBuilder;
186
187 xmlObjectBuilder = xmlObjectBuilderFactory.getBuilder(domElement);
188 if (xmlObjectBuilder == null) {
189 xmlObjectBuilder = xmlObjectBuilderFactory.getBuilder(Configuration.getDefaultProviderQName());
190 if (xmlObjectBuilder == null) {
191 String errorMsg = "Unable to located builder for " + XMLHelper.getNodeQName(domElement);
192 log.error(errorMsg);
193 throw new UnmarshallingException(errorMsg);
194 } else {
195 log.trace("No builder was registered for {} but the default builder {} was available, using it.",
196 XMLHelper.getNodeQName(domElement), xmlObjectBuilder.getClass().getName());
197 }
198 }
199
200 return xmlObjectBuilder.buildObject(domElement);
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215 protected void unmarshallAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException {
216 QName attribName = XMLHelper.getNodeQName(attribute);
217 log.trace("Pre-processing attribute {}", attribName);
218 String attributeNamespace = DatatypeHelper.safeTrimOrNullString(attribute.getNamespaceURI());
219
220 if (DatatypeHelper.safeEquals(attributeNamespace, XMLConstants.XMLNS_NS)) {
221 unmarshallNamespaceAttribute(xmlObject, attribute);
222 } else if (DatatypeHelper.safeEquals(attributeNamespace, XMLConstants.XSI_NS)) {
223 unmarshallSchemaInstanceAttributes(xmlObject, attribute);
224 } else {
225 log.trace("Attribute {} is neither a schema type nor namespace, calling processAttribute()", XMLHelper
226 .getNodeQName(attribute));
227 String attributeNSURI = attribute.getNamespaceURI();
228 String attributeNSPrefix;
229 if (attributeNSURI != null) {
230 attributeNSPrefix = attribute.lookupPrefix(attributeNSURI);
231 if (attributeNSPrefix == null && XMLConstants.XML_NS.equals(attributeNSURI)) {
232 attributeNSPrefix = XMLConstants.XML_PREFIX;
233 }
234 xmlObject.getNamespaceManager().registerAttributeName(attribName);
235 }
236
237 checkIDAttribute(attribute);
238
239 processAttribute(xmlObject, attribute);
240 }
241 }
242
243
244
245
246
247
248
249 protected void unmarshallNamespaceAttribute(XMLObject xmlObject, Attr attribute) {
250 log.trace("{} is a namespace declaration, adding it to the list of namespaces on the XMLObject", XMLHelper
251 .getNodeQName(attribute));
252 Namespace namespace;
253 if(DatatypeHelper.safeEquals(attribute.getLocalName(), XMLConstants.XMLNS_PREFIX)){
254 namespace = new Namespace(attribute.getValue(), null);
255 }else{
256 namespace = new Namespace(attribute.getValue(), attribute.getLocalName());
257 }
258 namespace.setAlwaysDeclare(true);
259 xmlObject.getNamespaceManager().registerNamespaceDeclaration(namespace);
260 }
261
262
263
264
265
266
267
268 protected void unmarshallSchemaInstanceAttributes(XMLObject xmlObject, Attr attribute) {
269 QName attribName = XMLHelper.getNodeQName(attribute);
270 if (XMLConstants.XSI_TYPE_ATTRIB_NAME.equals(attribName)) {
271 log.trace("Saw XMLObject {} with an xsi:type of: {}", xmlObject.getElementQName(), attribute.getValue());
272 } else if (XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.equals(attribName)) {
273 log.trace("Saw XMLObject {} with an xsi:schemaLocation of: {}", xmlObject.getElementQName(),
274 attribute.getValue());
275 xmlObject.setSchemaLocation(attribute.getValue());
276 } else if (XMLConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB_NAME.equals(attribName)) {
277 log.trace("Saw XMLObject {} with an xsi:noNamespaceSchemaLocation of: {}", xmlObject.getElementQName(),
278 attribute.getValue());
279 xmlObject.setNoNamespaceSchemaLocation(attribute.getValue());
280 } else if (XMLConstants.XSI_NIL_ATTRIB_NAME.equals(attribName)) {
281 log.trace("Saw XMLObject {} with an xsi:nil of: {}", xmlObject.getElementQName(),
282 attribute.getValue());
283 xmlObject.setNil(XSBooleanValue.valueOf(attribute.getValue()));
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296 protected void checkIDAttribute(Attr attribute) {
297 QName attribName = XMLHelper.getNodeQName(attribute);
298 if (Configuration.isIDAttribute(attribName) && !attribute.isId()) {
299 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
300 }
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314 protected void unmarshallChildElement(XMLObject xmlObject, Element childElement) throws UnmarshallingException {
315 log.trace("Unmarshalling child elements of XMLObject {}", xmlObject.getElementQName());
316
317 Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(childElement);
318
319 if (unmarshaller == null) {
320 unmarshaller = unmarshallerFactory.getUnmarshaller(Configuration.getDefaultProviderQName());
321 if (unmarshaller == null) {
322 String errorMsg = "No unmarshaller available for " + XMLHelper.getNodeQName(childElement)
323 + ", child of " + xmlObject.getElementQName();
324 log.error(errorMsg);
325 throw new UnmarshallingException(errorMsg);
326 } else {
327 log.trace("No unmarshaller was registered for {}, child of {}. Using default unmarshaller.", XMLHelper
328 .getNodeQName(childElement), xmlObject.getElementQName());
329 }
330 }
331
332 log.trace("Unmarshalling child element {}with unmarshaller {}", XMLHelper.getNodeQName(childElement),
333 unmarshaller.getClass().getName());
334 processChildElement(xmlObject, unmarshaller.unmarshall(childElement));
335 }
336
337
338
339
340
341
342
343
344
345
346
347 protected void unmarshallTextContent(XMLObject xmlObject, Text content) throws UnmarshallingException {
348 String textContent = DatatypeHelper.safeTrimOrNullString(content.getWholeText());
349 if (textContent != null) {
350 processElementContent(xmlObject, textContent);
351 }
352 }
353
354
355
356
357
358
359
360
361
362 protected abstract void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject)
363 throws UnmarshallingException;
364
365
366
367
368
369
370
371
372
373 protected abstract void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException;
374
375
376
377
378
379
380
381 protected abstract void processElementContent(XMLObject xmlObject, String elementContent);
382 }