blob: 608209e6f6cad6c51e921c79f333bc3118ec6633 [file] [log] [blame]
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -07001/*
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.odtn.utils;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19import static java.nio.charset.StandardCharsets.UTF_8;
20import static org.slf4j.LoggerFactory.getLogger;
21
22import java.io.IOException;
23import java.io.InputStreamReader;
24import java.io.StringWriter;
25
26import javax.xml.parsers.DocumentBuilderFactory;
27import javax.xml.parsers.ParserConfigurationException;
28import javax.xml.transform.OutputKeys;
29import javax.xml.transform.Transformer;
30import javax.xml.transform.TransformerException;
31import javax.xml.transform.TransformerFactory;
32import javax.xml.transform.dom.DOMSource;
33import javax.xml.transform.stream.StreamResult;
34
Ray Milkeyd84f89b2018-08-17 14:54:17 -070035import org.osgi.service.component.annotations.Activate;
36import org.osgi.service.component.annotations.Component;
37import org.osgi.service.component.annotations.Deactivate;
38import org.osgi.service.component.annotations.Reference;
39import org.osgi.service.component.annotations.ReferenceCardinality;
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -070040import org.onlab.osgi.DefaultServiceDirectory;
41import org.onosproject.yang.model.DataNode;
42import org.onosproject.yang.model.DefaultModelObjectData;
43import org.onosproject.yang.model.DefaultResourceData;
44import org.onosproject.yang.model.InnerNode;
45import org.onosproject.yang.model.ModelConverter;
46import org.onosproject.yang.model.ModelObject;
47import org.onosproject.yang.model.ModelObjectData;
48import org.onosproject.yang.model.ResourceData;
49import org.onosproject.yang.model.ResourceId;
50import org.onosproject.yang.runtime.CompositeData;
51import org.onosproject.yang.runtime.CompositeStream;
52import org.onosproject.yang.runtime.DefaultCompositeData;
53import org.onosproject.yang.runtime.DefaultRuntimeContext;
54import org.onosproject.yang.runtime.RuntimeContext;
55import org.onosproject.yang.runtime.YangRuntimeService;
56import org.slf4j.Logger;
57import org.w3c.dom.Document;
58import org.xml.sax.InputSource;
59import org.xml.sax.SAXException;
60
61import com.fasterxml.jackson.core.JsonProcessingException;
62import com.fasterxml.jackson.databind.JsonNode;
63import com.fasterxml.jackson.databind.ObjectMapper;
64import com.fasterxml.jackson.databind.SerializationFeature;
65import com.google.common.annotations.Beta;
Yuta HIGUCHId0f8d892018-04-09 12:14:00 -070066import com.google.common.io.CharSource;
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -070067import com.google.common.io.CharStreams;
68
69@Beta
70@Component(immediate = true)
71public class YangToolUtil {
72 private static final Logger log = getLogger(YangToolUtil.class);
73
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -070075 protected YangRuntimeService yangRuntimeService;
76 protected static YangRuntimeService yrs;
77
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -070079 protected ModelConverter modelConverter;
80 protected static ModelConverter converter;
81
82 @Activate
83 protected void activate() {
84 yrs = yangRuntimeService;
85 converter = modelConverter;
86 log.info("Started");
87 }
88
89 @Deactivate
90 protected void deactivate() {
91 log.info("Stopped");
92 }
93
94 protected static void initStaticContext() {
95 if (yrs == null) {
96 yrs = DefaultServiceDirectory.getService(YangRuntimeService.class);
97 }
98 if (converter == null) {
99 converter = DefaultServiceDirectory.getService(ModelConverter.class);
100 }
101 }
102
103 /**
104 * Converts XML Document into CharSequence.
105 *
106 * @param xmlInput to convert
107 * @return CharSequence
108 */
109 public static CharSequence toCharSequence(Document xmlInput) {
110 return toCharSequence(xmlInput, true);
111 }
112
113 /**
114 * Converts XML Document into CharSequence.
115 *
116 * @param xmlInput to convert
117 * @param omitXmlDecl or not
118 * @return CharSequence
119 */
120 public static CharSequence toCharSequence(Document xmlInput, boolean omitXmlDecl) {
121 try {
122 TransformerFactory tf = TransformerFactory.newInstance();
123 Transformer transformer = tf.newTransformer();
124 if (omitXmlDecl) {
125 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
126 }
127 StringWriter writer = new StringWriter();
128 transformer.transform(new DOMSource(xmlInput), new StreamResult(writer));
129 return writer.getBuffer();
130 } catch (TransformerException e) {
131 log.error("Exception thrown", e);
132 return null;
133 }
134 }
135
136 /**
137 * Converts JsonNode into CharSequence.
138 *
139 * @param jsonInput to convert
140 * @return CharSequence
141 */
142 public static CharSequence toCharSequence(JsonNode jsonInput) {
143 checkNotNull(jsonInput);
144 ObjectMapper mapper = new ObjectMapper();
145 // TODO following pretty printing option should be removed
146 mapper.enable(SerializationFeature.INDENT_OUTPUT);
147
148 try {
149 return mapper.writerWithDefaultPrettyPrinter()
Yuta HIGUCHId0f8d892018-04-09 12:14:00 -0700150 .writeValueAsString(jsonInput);
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -0700151 } catch (JsonProcessingException e) {
152 log.error("Exception thrown", e);
153 return null;
154 }
155 }
156
157 /**
158 * Converts UTF-8 CompositeStream into CharSequence.
159 *
160 * @param utf8Input to convert
161 * @return CharSequence
162 */
163 public static CharSequence toCharSequence(CompositeStream utf8Input) {
164 StringBuilder s = new StringBuilder();
165 try {
166 CharStreams.copy(new InputStreamReader(utf8Input.resourceData(), UTF_8), s);
167 return s;
168 } catch (IOException e) {
169 log.error("Exception thrown", e);
170 return null;
171 }
172 }
173
174 /**
175 * Converts JSON CompositeStream into JsonNode.
176 *
177 * @param jsonInput to convert
178 * @return JsonNode
179 */
180 public static JsonNode toJsonNode(CompositeStream jsonInput) {
181 ObjectMapper mapper = new ObjectMapper();
182 try {
183 return mapper.readTree(jsonInput.resourceData());
184 } catch (IOException e) {
185 log.error("Exception thrown", e);
186 return null;
187 }
188 }
189
190 /**
191 * Converts XML CompositeStream into XML Document.
192 *
193 * @param xmlInput to convert
194 * @return Document
195 */
196 public static Document toDocument(CompositeStream xmlInput) {
197 try {
198 return DocumentBuilderFactory.newInstance()
199 .newDocumentBuilder()
200 .parse(new InputSource(new InputStreamReader(xmlInput.resourceData(), UTF_8)));
201 } catch (ParserConfigurationException | SAXException | IOException e) {
202 log.error("Exception thrown", e);
203 return null;
204 }
205 }
206
207 /**
Yuta HIGUCHId0f8d892018-04-09 12:14:00 -0700208 * Converts XML source into XML Document.
209 *
210 * @param xmlInput to convert
211 * @return Document
212 */
213 public static Document toDocument(CharSource xmlInput) {
214 try {
215 return DocumentBuilderFactory.newInstance()
216 .newDocumentBuilder()
217 .parse(new InputSource(xmlInput.openStream()));
218 } catch (ParserConfigurationException | SAXException | IOException e) {
219 log.error("Exception thrown", e);
220 return null;
221 }
222 }
223
224 /**
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -0700225 * Converts CompositeData into XML CompositeStream.
226 *
227 * @param input CompositeData to convert
228 * @return XML CompositeStream
229 */
230 public static CompositeStream toXmlCompositeStream(CompositeData input) {
231 initStaticContext();
232 RuntimeContext yrtContext = new DefaultRuntimeContext.Builder()
233 .setDataFormat("xml")
234 // Following does not have any effect?
235 //.addAnnotation(XMLNS_XC_ANNOTATION)
236 .build();
237 CompositeStream xml = yrs.encode(input, yrtContext);
238 return xml;
239 }
240
241 /**
242 * Converts CompositeData into JSON CompositeStream.
243 *
244 * @param input CompositeData to convert
245 * @return JSON CompositeStream
246 */
247 public static CompositeStream toJsonCompositeStream(CompositeData input) {
248 initStaticContext();
249 RuntimeContext yrtContext = new DefaultRuntimeContext.Builder()
250 .setDataFormat("JSON")
251 .build();
252 CompositeStream xml = yrs.encode(input, yrtContext);
253 return xml;
254 }
255
256 /**
257 * Converts ResourceData into CompositeData.
258 *
259 * @param input ResourceData to convert
260 * @return CompositeData
261 */
262 public static CompositeData toCompositeData(ResourceData input) {
263 CompositeData.Builder builder =
264 DefaultCompositeData.builder();
265 builder.resourceData(input);
266 // remove, merge, replace, ...
267 //builder.addAnnotatedNodeInfo(info)
268
269 return builder.build();
270 }
271
272 /**
273 * Converts DataNode into ResourceData.
274 *
275 * @param resourceId pointing to parent of {@code dataNode}, YANG-wise.
276 * @param dataNode to convert, must be InnerNode
277 * @return ResourceData
278 */
279 public static ResourceData toResourceData(ResourceId resourceId, DataNode dataNode) {
280 DefaultResourceData.Builder builder = DefaultResourceData.builder();
281 builder.resourceId(checkNotNull(resourceId));
282 if (dataNode instanceof InnerNode) {
Yuta HIGUCHIf84c91a2018-06-03 22:19:38 -0700283 builder.addDataNode(dataNode);
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -0700284 } else {
285 log.error("Unexpected DataNode encountered {}", dataNode);
286 }
287 return builder.build();
288 }
289
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -0700290 /**
291 * Converts ModelObject into a DataNode.
292 *
293 * @param input ModelOject
294 * @return DataNode
295 */
296 public static DataNode toDataNode(ModelObject input) {
hirokib8ddc3f2018-06-02 08:29:42 -0700297 // FIXME this converter will work with root-level nodes only.
Yuta HIGUCHI48f4cb72018-03-29 20:30:56 -0700298 initStaticContext();
299 ModelObjectData modelData = DefaultModelObjectData.builder()
300 .addModelObject(input)
301 .identifier(null)
302 .build();
303
304 ResourceData rnode = converter.createDataNode(modelData);
305 if (rnode.dataNodes().isEmpty()) {
306 log.error("input did not result in any datanode. {}", input);
307 return null;
308 }
309 return rnode.dataNodes().get(0);
310 }
311}