blob: 2d25637d2ad8396e4f60ec0c99d684a32bc967a8 [file] [log] [blame]
Yuta HIGUCHId1c413b2018-02-20 14:52:00 -08001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.netconf;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.io.IOException;
21import javax.xml.bind.JAXBContext;
22import javax.xml.bind.JAXBElement;
23import javax.xml.bind.JAXBException;
24import javax.xml.bind.Unmarshaller;
25import javax.xml.namespace.QName;
26import javax.xml.stream.XMLEventReader;
27import javax.xml.stream.XMLInputFactory;
28import javax.xml.stream.XMLStreamException;
29import javax.xml.stream.XMLStreamReader;
30import javax.xml.transform.OutputKeys;
31import javax.xml.transform.Source;
32import javax.xml.transform.Transformer;
33import javax.xml.transform.TransformerException;
34import javax.xml.transform.TransformerFactory;
35import javax.xml.transform.dom.DOMSource;
36import javax.xml.transform.stax.StAXSource;
37import javax.xml.transform.stream.StreamResult;
38
39import org.onosproject.netconf.rpc.RpcErrorType;
40import org.slf4j.Logger;
41import org.w3c.dom.Node;
42
43import com.google.common.annotations.Beta;
44import com.google.common.io.CharSource;
45import com.google.common.io.CharStreams;
46
47@Beta
48public final class NetconfRpcParserUtil {
49
50 private static final Logger log = getLogger(NetconfRpcParserUtil.class);
51
52 /**
53 * Parse first rpc-reply contained in the input.
54 *
55 * @param xml input
56 * @return {@link NetconfRpcReply} or null on error
57 */
58 public static NetconfRpcReply parseRpcReply(CharSequence xml) {
59 XMLInputFactory xif = XMLInputFactory.newFactory();
60 try {
61 XMLStreamReader xsr = xif.createXMLStreamReader(CharSource.wrap(xml).openStream());
62 return parseRpcReply(xsr);
63 } catch (XMLStreamException | IOException e) {
64 log.error("Exception thrown creating XMLStreamReader", e);
65 return null;
66 }
67 }
68
69 /**
70 * Parse first rpc-reply contained in the input.
71 *
72 * @param xsr input
73 * @return {@link NetconfRpcReply} or null on error
74 */
75 public static NetconfRpcReply parseRpcReply(XMLStreamReader xsr) {
76 try {
77 for ( ; xsr.hasNext(); xsr.next()) {
78 if (xsr.isStartElement() &&
79 xsr.getName().getLocalPart().equals("rpc-reply")) {
80
81 NetconfRpcReply.Builder builder = NetconfRpcReply.builder();
82 String msgId = xsr.getAttributeValue(null, "message-id");
83 builder.withMessageId(msgId);
84 xsr.nextTag();
85
86 return parseRpcReplyBody(builder, xsr);
87 }
88 }
89 } catch (XMLStreamException e) {
90 log.error("Exception thrown parsing rpc-reply", e);
91 }
92 return null;
93 }
94
95 private static NetconfRpcReply parseRpcReplyBody(NetconfRpcReply.Builder builder,
96 XMLStreamReader xsr) {
97
98 try {
99 for ( ; xsr.hasNext(); xsr.next()) {
100 if (xsr.isStartElement()) {
101 switch (xsr.getName().getLocalPart()) {
102 case "ok":
103 try {
104 // skip to end of tag event
105 xsr.getElementText();
106 } catch (XMLStreamException e) {
107 log.warn("Failed parsing ok", e);
108 }
109 // ok should be the only element
110 return builder.buildOk();
111
112 case "rpc-error":
113 try {
114 JAXBContext context = JAXBContext.newInstance(RpcErrorType.class);
115 Unmarshaller unmarshaller = context.createUnmarshaller();
116 JAXBElement<RpcErrorType> error = unmarshaller.unmarshal(xsr, RpcErrorType.class);
117 builder.addError(NetconfRpcError.wrap(error.getValue()));
118 } catch (JAXBException e) {
119 log.warn("Failed parsing rpc-error", e);
120 }
121 break;
122
123 default: // =rpc-response
124 QName qName = xsr.getName();
125 try {
126 TransformerFactory tf = TransformerFactory.newInstance();
127 Transformer t = tf.newTransformer();
128
129 t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
130 StringBuilder sb = new StringBuilder();
131 t.transform(new StAXSource(xsr),
132 new StreamResult(CharStreams.asWriter(sb)));
133 builder.addResponses(sb.toString());
134 } catch (TransformerException e) {
135 log.warn("Failed parsing {}", qName, e);
136 }
137 break;
138 }
139 }
140 }
141 } catch (XMLStreamException e) {
142 log.error("Exception thrown parsing rpc-reply body", e);
143 }
144
145 return builder.build();
146
147 }
148
149 /**
150 * Converts XML object into a String.
151 *
152 * @param xml Object (e.g., DOM {@link Node})
153 * @return String representation of {@code xml} or empty on error.
154 */
155 @Beta
156 public static String toString(Object xml) {
157 TransformerFactory tf = TransformerFactory.newInstance();
158 try {
159 Transformer t = tf.newTransformer();
160 t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
161 Source xmlSource = null;
162 if (xml instanceof Node) {
163 xmlSource = new DOMSource((Node) xml);
164 } else if (xml instanceof XMLEventReader) {
165 xmlSource = new StAXSource((XMLEventReader) xml);
166 } else if (xml instanceof XMLStreamReader) {
167 xmlSource = new StAXSource((XMLStreamReader) xml);
168 } else {
169 log.warn("Unknown XML object type: {}, {}", xml.getClass(), xml);
170 return "";
171 }
172
173 StringBuilder sb = new StringBuilder();
174 t.transform(xmlSource, new StreamResult(CharStreams.asWriter(sb)));
175 return sb.toString();
176 } catch (TransformerException | XMLStreamException e) {
177 log.error("Exception thrown", e);
178 return "";
179 }
180 }
181
182 private NetconfRpcParserUtil() {}
183
184}