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