Merge "Fixed for bug : 1171 - issue while creating subnet"
[controller.git] / opendaylight / md-sal / sal-protocolbuffer-encoding / src / main / java / org / opendaylight / controller / cluster / datastore / util / EncoderDecoderUtil.java
1 package org.opendaylight.controller.cluster.datastore.util;
2
3 import com.google.common.base.Preconditions;
4 import com.google.common.collect.Lists;
5 import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage;
6 import org.opendaylight.yangtools.yang.common.QName;
7 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
8 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
9 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
10 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
11 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
12 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
13 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
14 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
15 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
16 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
17 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
18 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
19 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
20 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
21 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.Module;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.w3c.dom.Document;
30 import org.w3c.dom.Element;
31
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.transform.OutputKeys;
34 import javax.xml.transform.Transformer;
35 import javax.xml.transform.TransformerException;
36 import javax.xml.transform.TransformerFactory;
37 import javax.xml.transform.TransformerFactoryConfigurationError;
38 import javax.xml.transform.dom.DOMSource;
39 import javax.xml.transform.stream.StreamResult;
40 import java.io.ByteArrayInputStream;
41 import java.io.StringWriter;
42 import java.util.Collection;
43 import java.util.Collections;
44 import java.util.Iterator;
45 import java.util.List;
46
47 /*
48  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
49  *
50  * This program and the accompanying materials are made available under the terms of the Eclipse
51  * Public License v1.0 which accompanies this distribution, and is available at
52  * http://www.eclipse.org/legal/epl-v10.html
53  */
54 /*
55  *
56  * <code>EncoderDecoderUtil</code> helps in wrapping the NormalizedNode into a SimpleNormalizedNode
57  * protobuf message containing the XML representation of the NormalizeNode
58  *
59  * @author: syedbahm
60  */
61 public class EncoderDecoderUtil {
62     static DocumentBuilderFactory factory;
63
64     private static DomFromNormalizedNodeSerializerFactory serializerFactory =
65         DomFromNormalizedNodeSerializerFactory
66             .getInstance(XmlDocumentUtils.getDocument(),
67                 DomUtils.defaultValueCodecProvider());
68
69     private static DomToNormalizedNodeParserFactory parserFactory =
70         DomToNormalizedNodeParserFactory
71             .getInstance(DomUtils.defaultValueCodecProvider());
72
73     static {
74         factory = DocumentBuilderFactory.newInstance();
75         factory.setNamespaceAware(true);
76         factory.setCoalescing(true);
77         factory.setIgnoringElementContentWhitespace(true);
78         factory.setIgnoringComments(true);
79     }
80
81     private static DataSchemaNode findChildNode(Collection<DataSchemaNode> children,
82         String name) {
83         List<DataNodeContainer> containers = Lists.newArrayList();
84
85         for (DataSchemaNode dataSchemaNode : children) {
86             if (dataSchemaNode.getQName().getLocalName().equals(name))
87                 return dataSchemaNode;
88             if (dataSchemaNode instanceof DataNodeContainer) {
89                 containers.add((DataNodeContainer) dataSchemaNode);
90             } else if (dataSchemaNode instanceof ChoiceNode) {
91                 containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
92             }
93         }
94
95         for (DataNodeContainer container : containers) {
96             DataSchemaNode retVal =
97                 findChildNode(container.getChildNodes(), name);
98             if (retVal != null) {
99                 return retVal;
100             }
101         }
102
103         return null;
104     }
105
106     private static DataSchemaNode getSchemaNode(SchemaContext context,
107         QName qname) {
108
109         for (Module module : context
110             .findModuleByNamespace(qname.getNamespace())) {
111             // we will take the first child as the start of the
112             if (module.getChildNodes() != null || !module.getChildNodes()
113                 .isEmpty()) {
114
115                 DataSchemaNode found =
116                     findChildNode(module.getChildNodes(), qname.getLocalName());
117                 return found;
118             }
119         }
120         return null;
121     }
122
123     private static String toString(Element xml) {
124         try {
125             Transformer transformer =
126                 TransformerFactory.newInstance().newTransformer();
127             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
128
129             StreamResult result = new StreamResult(new StringWriter());
130             DOMSource source = new DOMSource(xml);
131             transformer.transform(source, result);
132
133             return result.getWriter().toString();
134         } catch (IllegalArgumentException | TransformerFactoryConfigurationError
135             | TransformerException e) {
136             throw new RuntimeException("Unable to serialize xml element " + xml,
137                 e);
138         }
139     }
140
141   private static String toString(Iterable<Element> xmlIterable) {
142     try {
143       Transformer transformer =
144           TransformerFactory.newInstance().newTransformer();
145       transformer.setOutputProperty(OutputKeys.INDENT, "yes");
146
147       StreamResult result = new StreamResult(new StringWriter());
148       Iterator iterator = xmlIterable.iterator();
149       DOMSource source;
150       if(iterator.hasNext()) {
151         source = new DOMSource((org.w3c.dom.Node) iterator.next());
152         transformer.transform(source, result);
153         transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
154       }
155
156       while(iterator.hasNext()) {
157         source = new DOMSource((org.w3c.dom.Node) iterator.next());
158         transformer.transform(source, result);
159       }
160       System.out.println(result.getWriter().toString());
161       return result.getWriter().toString();
162     } catch (IllegalArgumentException | TransformerFactoryConfigurationError
163         | TransformerException e) {
164       throw new RuntimeException("Unable to serialize xml element(s) " + xmlIterable.toString(),
165           e);
166     }
167   }
168
169     private static Iterable<Element> serialize(DataSchemaNode schemaNode, NormalizedNode normalizedNode){
170         if(schemaNode instanceof ContainerSchemaNode){      //1
171             return serializerFactory
172                 .getContainerNodeSerializer()
173                 .serialize((ContainerSchemaNode) schemaNode,
174                     (ContainerNode) normalizedNode);
175         } else if(schemaNode instanceof ChoiceNode){        //2
176             return serializerFactory
177                 .getChoiceNodeSerializer()
178                 .serialize((ChoiceNode) schemaNode,
179                     (org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) normalizedNode);
180         } else if(schemaNode instanceof LeafSchemaNode){    //3
181             return serializerFactory
182                 .getLeafNodeSerializer()
183                 .serialize((LeafSchemaNode) schemaNode, (LeafNode) normalizedNode);
184         } else if(schemaNode instanceof ListSchemaNode){    //4
185             return serializerFactory
186                 .getMapNodeSerializer()
187                 .serialize((ListSchemaNode) schemaNode, (MapNode) normalizedNode);
188         } else if(schemaNode instanceof LeafListSchemaNode){    //5
189             return serializerFactory
190                 .getLeafSetNodeSerializer()
191                 .serialize((LeafListSchemaNode) schemaNode, (LeafSetNode) normalizedNode);
192         } else if(schemaNode instanceof AugmentationSchema){//6
193             return serializerFactory
194                 .getAugmentationNodeSerializer()
195                 .serialize((AugmentationSchema) schemaNode, (AugmentationNode) normalizedNode);
196         } else if(schemaNode instanceof ListSchemaNode && normalizedNode instanceof LeafSetEntryNode){    //7
197             return serializerFactory
198                 .getLeafSetEntryNodeSerializer()
199                 .serialize((LeafListSchemaNode) schemaNode, (LeafSetEntryNode) normalizedNode);
200         } else if(schemaNode instanceof ListSchemaNode){    //8
201             return serializerFactory
202                 .getMapEntryNodeSerializer()
203                 .serialize((ListSchemaNode) schemaNode, (MapEntryNode) normalizedNode);
204         }
205
206
207
208         throw new UnsupportedOperationException(schemaNode.getClass().toString());
209     }
210
211     private static NormalizedNode parse(Document doc, DataSchemaNode schemaNode){
212         if(schemaNode instanceof ContainerSchemaNode){
213             return parserFactory
214                 .getContainerNodeParser()
215                 .parse(Collections.singletonList(doc.getDocumentElement()),
216                     (ContainerSchemaNode) schemaNode);
217
218         } else if(schemaNode instanceof ChoiceNode){
219             return parserFactory
220                 .getChoiceNodeParser()
221                 .parse(Collections.singletonList(doc.getDocumentElement()),
222                     (ChoiceNode) schemaNode);
223         } else if(schemaNode instanceof LeafNode){
224             return parserFactory
225                 .getLeafNodeParser()
226                 .parse(Collections.singletonList(doc.getDocumentElement()),
227                     (LeafSchemaNode) schemaNode);
228         } else if(schemaNode instanceof ListSchemaNode){
229             return parserFactory
230                 .getMapNodeParser()
231                 .parse(Collections.singletonList(doc.getDocumentElement()),
232                     (ListSchemaNode) schemaNode);
233         } else if(schemaNode instanceof LeafListSchemaNode){
234             return parserFactory
235                 .getLeafSetNodeParser()
236                 .parse(Collections.singletonList(doc.getDocumentElement()),
237                     (LeafListSchemaNode) schemaNode);
238         } else if(schemaNode instanceof AugmentationSchema){
239             return parserFactory
240                 .getAugmentationNodeParser()
241                 .parse(Collections.singletonList(doc.getDocumentElement()),
242                     (AugmentationSchema) schemaNode);
243         } else if(schemaNode instanceof ListSchemaNode){
244             return parserFactory
245                 .getMapEntryNodeParser()
246                 .parse(Collections.singletonList(doc.getDocumentElement()),
247                     (ListSchemaNode) schemaNode);
248
249         }
250
251         throw new UnsupportedOperationException(schemaNode.getClass().toString());
252     }
253
254
255     /**
256      * Helps in generation of NormalizedNodeXml message for the supplied NormalizedNode
257      *
258      * @param sc             --SchemaContext
259      * @param normalizedNode -- Normalized Node to be encoded
260      * @return SimpleNormalizedNodeMessage.NormalizedNodeXml
261      */
262     public static SimpleNormalizedNodeMessage.NormalizedNodeXml encode(
263         SchemaContext sc, NormalizedNode<?, ?> normalizedNode) {
264
265         Preconditions.checkArgument(sc != null, "Schema context found null");
266
267         Preconditions.checkArgument(normalizedNode != null,
268             "normalized node found null");
269
270         DataSchemaNode schemaNode = getSchemaNode(sc,
271             normalizedNode.getIdentifier()
272                 .getNodeType()
273         );
274
275         Preconditions.checkState(schemaNode != null,
276             "Couldn't find schema node for " + normalizedNode.getIdentifier());
277
278         Iterable<Element> els = serialize(schemaNode, normalizedNode);
279
280         String xmlString = toString(els.iterator().next());
281         SimpleNormalizedNodeMessage.NormalizedNodeXml.Builder builder =
282             SimpleNormalizedNodeMessage.NormalizedNodeXml.newBuilder();
283         builder.setXmlString(xmlString);
284         builder
285             .setNodeIdentifier(normalizedNode.getIdentifier()
286                 .getNodeType().toString());
287         return builder.build();
288
289     }
290
291     /**
292      * Utilizes the SimpleNormalizedNodeMessage.NormalizedNodeXml to convert into NormalizedNode
293      *
294      * @param sc                -- schema context
295      * @param normalizedNodeXml -- containing the normalized Node XML
296      * @return NormalizedNode return
297      * @throws Exception
298      */
299
300     public static NormalizedNode decode(SchemaContext sc,
301         SimpleNormalizedNodeMessage.NormalizedNodeXml normalizedNodeXml)
302         throws Exception {
303
304         Preconditions
305             .checkArgument(sc != null, "schema context seems to be null");
306
307         Preconditions.checkArgument(normalizedNodeXml != null,
308             "SimpleNormalizedNodeMessage.NormalizedNodeXml found to be null");
309         QName qname = QName.create(normalizedNodeXml.getNodeIdentifier());
310
311         // here we will try to get back the NormalizedNode
312         DataSchemaNode schemaNode = getSchemaNode(sc, qname);
313
314         // now we need to read the XML
315         Document doc =
316             factory.newDocumentBuilder().parse(
317                 new ByteArrayInputStream(
318                     normalizedNodeXml.getXmlString().getBytes(
319                         "utf-8"))
320             );
321
322         doc.getDocumentElement().normalize();
323
324
325         return parse(doc, schemaNode);
326     }
327
328
329
330 }