Merge "AbstractConfigTest - exposed BundleContext and ServiceRegistration mock."
[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) throws XMLStreamException {
125         checkArgument(startElement != null, "Start Element cannot be NULL!");
126         String data = null;
127
128         if (eventReader.hasNext()) {
129             final XMLEvent innerEvent = eventReader.peek();
130             if (innerEvent.isCharacters()) {
131                 final Characters chars = innerEvent.asCharacters();
132                 if (!chars.isWhiteSpace()) {
133                     data = innerEvent.asCharacters().getData();
134                 }
135             } else if (innerEvent.isEndElement()) {
136                 data = "";
137             }
138         }
139         
140         return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data);
141     }
142     
143     private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
144         checkArgument(startElement != null, "Start Element cannot be NULL!");
145         return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
146     }
147     
148     private String getLocalNameFrom(StartElement startElement) {
149         return startElement.getName().getLocalPart();
150     }
151     
152     private URI getNamespaceFrom(StartElement startElement) {
153         String namespaceURI = startElement.getName().getNamespaceURI();
154         return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
155     }
156     
157 }