Merge "BUG-432: migrate users of Registration as appropriate"
[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.ContainerNode;
8 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
9 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
10 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
11 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
12 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
13 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
14 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
15 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
16 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
17 import org.opendaylight.yangtools.yang.model.api.Module;
18 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
19 import org.w3c.dom.Document;
20 import org.w3c.dom.Element;
21
22 import javax.xml.parsers.DocumentBuilderFactory;
23 import javax.xml.transform.OutputKeys;
24 import javax.xml.transform.Transformer;
25 import javax.xml.transform.TransformerException;
26 import javax.xml.transform.TransformerFactory;
27 import javax.xml.transform.TransformerFactoryConfigurationError;
28 import javax.xml.transform.dom.DOMSource;
29 import javax.xml.transform.stream.StreamResult;
30 import java.io.ByteArrayInputStream;
31 import java.io.StringWriter;
32 import java.util.Collections;
33 import java.util.List;
34
35 /*
36  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
37  *
38  * This program and the accompanying materials are made available under the terms of the Eclipse
39  * Public License v1.0 which accompanies this distribution, and is available at
40  * http://www.eclipse.org/legal/epl-v10.html
41  */
42 /*
43  *
44  * <code>EncoderDecoderUtil</code> helps in wrapping the NormalizedNode into a SimpleNormalizedNode
45  * protobuf message containing the XML representation of the NormalizeNode
46  *
47  * @author: syedbahm
48  */
49 public class EncoderDecoderUtil {
50   static DocumentBuilderFactory factory;
51   static {
52     factory = DocumentBuilderFactory.newInstance();
53     factory.setNamespaceAware(true);
54     factory.setCoalescing(true);
55     factory.setIgnoringElementContentWhitespace(true);
56     factory.setIgnoringComments(true);
57   }
58
59   private static DataSchemaNode findChildNode(Iterable<DataSchemaNode> children,
60       String name) {
61     List<DataNodeContainer> containers = Lists.newArrayList();
62
63     for (DataSchemaNode dataSchemaNode : children) {
64       if (dataSchemaNode.getQName().getLocalName().equals(name))
65         return dataSchemaNode;
66       if (dataSchemaNode instanceof DataNodeContainer) {
67         containers.add((DataNodeContainer) dataSchemaNode);
68       } else if (dataSchemaNode instanceof ChoiceNode) {
69         containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
70       }
71     }
72
73     for (DataNodeContainer container : containers) {
74       DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
75       if (retVal != null) {
76         return retVal;
77       }
78     }
79
80     return null;
81   }
82
83   private static DataSchemaNode getSchemaNode(SchemaContext context, QName qname) {
84
85     for (Module module : context.findModuleByNamespace(qname.getNamespace())) {
86       // we will take the first child as the start of the
87       if (module.getChildNodes() != null || !module.getChildNodes().isEmpty()) {
88
89         DataSchemaNode found =
90             findChildNode(module.getChildNodes(), qname.getLocalName());
91         return found;
92       }
93     }
94     return null;
95   }
96
97   private static String toString(Element xml) {
98     try {
99       Transformer transformer =
100           TransformerFactory.newInstance().newTransformer();
101       transformer.setOutputProperty(OutputKeys.INDENT, "yes");
102
103       StreamResult result = new StreamResult(new StringWriter());
104       DOMSource source = new DOMSource(xml);
105       transformer.transform(source, result);
106
107       return result.getWriter().toString();
108     } catch (IllegalArgumentException | TransformerFactoryConfigurationError
109         | TransformerException e) {
110       throw new RuntimeException("Unable to serialize xml element " + xml, e);
111     }
112   }
113
114   /**
115    * Helps in generation of NormalizedNodeXml message for the supplied NormalizedNode
116    *
117    * @param sc --SchemaContext
118    * @param normalizedNode -- Normalized Node to be encoded
119    * @return SimpleNormalizedNodeMessage.NormalizedNodeXml
120    */
121   public static SimpleNormalizedNodeMessage.NormalizedNodeXml encode(
122       SchemaContext sc, NormalizedNode<?, ?> normalizedNode) {
123     Preconditions.checkArgument(sc != null, "Schema context found null");
124     Preconditions.checkArgument(normalizedNode != null,
125         "normalized node found null");
126     ContainerSchemaNode containerNode =
127         (ContainerSchemaNode) getSchemaNode(sc, normalizedNode.getIdentifier()
128             .getNodeType());
129     Preconditions.checkState(containerNode != null,
130         "Couldn't find schema node for " + normalizedNode.getIdentifier());
131     Iterable<Element> els =
132         DomFromNormalizedNodeSerializerFactory
133             .getInstance(XmlDocumentUtils.getDocument(),
134                 DomUtils.defaultValueCodecProvider())
135             .getContainerNodeSerializer()
136             .serialize(containerNode, (ContainerNode) normalizedNode);
137     String xmlString = toString(els.iterator().next());
138     SimpleNormalizedNodeMessage.NormalizedNodeXml.Builder builder =
139         SimpleNormalizedNodeMessage.NormalizedNodeXml.newBuilder();
140     builder.setXmlString(xmlString);
141     builder.setNodeIdentifier(((ContainerNode) normalizedNode).getIdentifier()
142         .getNodeType().toString());
143     return builder.build();
144
145   }
146
147   /**
148    * Utilizes the SimpleNormalizedNodeMessage.NormalizedNodeXml to convert into NormalizedNode
149    *
150    * @param sc -- schema context
151    * @param normalizedNodeXml -- containing the normalized Node XML
152    * @return NormalizedNode return
153    * @throws Exception
154    */
155
156   public static NormalizedNode decode(SchemaContext sc,
157       SimpleNormalizedNodeMessage.NormalizedNodeXml normalizedNodeXml)
158       throws Exception {
159     Preconditions.checkArgument(sc != null, "schema context seems to be null");
160     Preconditions.checkArgument(normalizedNodeXml != null,
161         "SimpleNormalizedNodeMessage.NormalizedNodeXml found to be null");
162     QName qname = QName.create(normalizedNodeXml.getNodeIdentifier());
163
164     // here we will try to get back the NormalizedNode
165     ContainerSchemaNode containerSchemaNode =
166         (ContainerSchemaNode) getSchemaNode(sc, qname);
167
168     // now we need to read the XML
169
170     Document doc =
171         factory.newDocumentBuilder().parse(
172             new ByteArrayInputStream(normalizedNodeXml.getXmlString().getBytes(
173                 "utf-8")));
174     doc.getDocumentElement().normalize();
175
176     ContainerNode result =
177         DomToNormalizedNodeParserFactory
178             .getInstance(DomUtils.defaultValueCodecProvider())
179             .getContainerNodeParser()
180             .parse(Collections.singletonList(doc.getDocumentElement()),
181                 containerSchemaNode);
182
183     return (NormalizedNode) result;
184
185   }
186
187
188
189 }