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