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