a53281492f23f28bd3e912c51cb8ae1ba1a752fa
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / rest / impl / XmlReader.java
1 package org.opendaylight.controller.sal.rest.impl;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4
5 import java.io.InputStream;
6 import java.net.URI;
7 import java.util.Stack;
8
9 import javax.xml.stream.XMLEventReader;
10 import javax.xml.stream.XMLInputFactory;
11 import javax.xml.stream.XMLStreamException;
12 import javax.xml.stream.events.Characters;
13 import javax.xml.stream.events.StartElement;
14 import javax.xml.stream.events.XMLEvent;
15
16 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
17 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
18 import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
19 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
20 import org.opendaylight.yangtools.yang.data.api.Node;
21
22 public class XmlReader {
23
24     private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
25     private XMLEventReader eventReader;
26
27     public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException {
28         eventReader = xmlInputFactory.createXMLEventReader(entityStream);
29
30         if (eventReader.hasNext()) {
31             XMLEvent element = eventReader.peek();
32             if (element.isStartDocument()) {
33                 eventReader.nextEvent();
34             }
35         }
36
37         if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) {
38             throw new UnsupportedFormatException("Root element of XML has to be composite element.");
39         }
40
41         final Stack<NodeWrapper<?>> processingQueue = new Stack<>();
42         CompositeNodeWrapper root = null;
43         NodeWrapper<?> element = null;
44         while (eventReader.hasNext()) {
45             final XMLEvent event = eventReader.nextEvent();
46
47             if (event.isStartElement()) {
48                 final StartElement startElement = event.asStartElement();
49                 CompositeNodeWrapper compParentNode = null;
50                 if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) {
51                     compParentNode = (CompositeNodeWrapper) processingQueue.peek();
52                 }
53                 NodeWrapper<?> newNode = null;
54                 if (isCompositeNodeEvent(event)) {
55                     if (root == null) {
56                         root = resolveCompositeNodeFromStartElement(startElement);
57                         newNode = root;
58                     } else {
59                         newNode = resolveCompositeNodeFromStartElement(startElement);
60                     }
61                 } else if (isSimpleNodeEvent(event)) {
62                     if (root == null) {
63                         throw new UnsupportedFormatException("Root element of XML has to be composite element.");
64                     }
65                     newNode = resolveSimpleNodeFromStartElement(startElement);
66                 }
67
68                 if (newNode != null) {
69                     processingQueue.push(newNode);
70                     if (compParentNode != null) {
71                         compParentNode.addValue(newNode);
72                     }
73                 }
74             } else if (event.isEndElement()) {
75                 element = processingQueue.pop();
76             }
77         }
78
79         if (!root.getLocalName().equals(element.getLocalName())) {
80             throw new UnsupportedFormatException("XML should contain only one root element");
81         }
82
83         return root;
84     }
85
86     private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException {
87         checkArgument(event != null, "XML Event cannot be NULL!");
88         if (event.isStartElement()) {
89             if (eventReader.hasNext()) {
90                 final XMLEvent innerEvent;
91                 innerEvent = eventReader.peek();
92                 if (innerEvent.isCharacters()) {
93                     final Characters chars = innerEvent.asCharacters();
94                     if (!chars.isWhiteSpace()) {
95                         return true;
96                     }
97                 } else if (innerEvent.isEndElement()) {
98                     return true;
99                 }
100             }
101         }
102         return false;
103     }
104
105     private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException {
106         checkArgument(event != null, "XML Event cannot be NULL!");
107         if (event.isStartElement()) {
108             if (eventReader.hasNext()) {
109                 XMLEvent innerEvent;
110                 innerEvent = eventReader.peek();
111                 if (innerEvent.isCharacters()) {
112                     Characters chars = innerEvent.asCharacters();
113                     if (chars.isWhiteSpace()) {
114                         eventReader.nextEvent();
115                         innerEvent = eventReader.peek();
116                     }
117                 }
118                 if (innerEvent.isStartElement()) {
119                     return true;
120                 }
121             }
122         }
123         return false;
124     }
125
126     private NodeWrapper<? extends Node<?>> resolveSimpleNodeFromStartElement(final StartElement startElement)
127             throws XMLStreamException {
128         checkArgument(startElement != null, "Start Element cannot be NULL!");
129         String data = null;
130
131         if (eventReader.hasNext()) {
132             final XMLEvent innerEvent = eventReader.peek();
133             if (innerEvent.isCharacters()) {
134                 final Characters chars = innerEvent.asCharacters();
135                 if (!chars.isWhiteSpace()) {
136                     data = innerEvent.asCharacters().getData();
137                 }
138             } else if (innerEvent.isEndElement()) {
139                 if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) {
140                     data = null;
141                 } else {
142                     data = "";
143                 }
144             }
145         }
146         if(data == null) {
147             return new EmptyNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
148         }
149         return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data);
150     }
151
152     private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
153         checkArgument(startElement != null, "Start Element cannot be NULL!");
154         return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
155     }
156
157     private String getLocalNameFrom(StartElement startElement) {
158         return startElement.getName().getLocalPart();
159     }
160
161     private URI getNamespaceFrom(StartElement startElement) {
162         String namespaceURI = startElement.getName().getNamespaceURI();
163         return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
164     }
165
166 }