groovy node-tree integration
[controller.git] / opendaylight / sal / yang-prototype / yang / yang-data-impl / src / main / java / org / opendaylight / controller / yang / data / impl / NodeUtils.java
1 /*\r
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
3  *\r
4  * This program and the accompanying materials are made available under the\r
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
6  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
7  */\r
8 package org.opendaylight.controller.yang.data.impl;\r
9 \r
10 import java.util.AbstractMap.SimpleEntry;\r
11 import java.util.ArrayList;\r
12 import java.util.HashMap;\r
13 import java.util.List;\r
14 import java.util.Map;\r
15 import java.util.Stack;\r
16 import java.util.Vector;\r
17 \r
18 import javax.xml.parsers.DocumentBuilder;\r
19 import javax.xml.parsers.DocumentBuilderFactory;\r
20 import javax.xml.parsers.ParserConfigurationException;\r
21 import javax.xml.xpath.XPath;\r
22 import javax.xml.xpath.XPathConstants;\r
23 import javax.xml.xpath.XPathExpression;\r
24 import javax.xml.xpath.XPathExpressionException;\r
25 import javax.xml.xpath.XPathFactory;\r
26 \r
27 import org.opendaylight.controller.yang.common.QName;\r
28 import org.opendaylight.controller.yang.data.api.CompositeNode;\r
29 import org.opendaylight.controller.yang.data.api.ModifyAction;\r
30 import org.opendaylight.controller.yang.data.api.Node;\r
31 import org.opendaylight.controller.yang.data.api.NodeModification;\r
32 import org.opendaylight.controller.yang.data.api.SimpleNode;\r
33 import org.opendaylight.controller.yang.model.api.DataNodeContainer;\r
34 import org.opendaylight.controller.yang.model.api.DataSchemaNode;\r
35 import org.opendaylight.controller.yang.model.api.ListSchemaNode;\r
36 import org.opendaylight.controller.yang.model.api.SchemaContext;\r
37 import org.slf4j.Logger;\r
38 import org.slf4j.LoggerFactory;\r
39 import org.w3c.dom.Element;\r
40 \r
41 import com.google.common.base.Joiner;\r
42 import com.google.common.collect.Lists;\r
43 \r
44 \r
45 /**\r
46  * @author michal.rehak\r
47  *\r
48  */\r
49 public abstract class NodeUtils {\r
50     \r
51     private static final Logger LOG = LoggerFactory.getLogger(NodeUtils.class);\r
52     \r
53     /**\r
54      * \r
55      */\r
56     private static final String USER_KEY_NODE = "node";\r
57     \r
58     /**\r
59      * @param node\r
60      * @return node path up till root node\r
61      */\r
62     public static String buildPath(Node<?> node) {\r
63         Vector<String> breadCrumbs = new Vector<>();\r
64         Node<?> tmpNode = node;\r
65         while (tmpNode != null) {\r
66             breadCrumbs.insertElementAt(tmpNode.getNodeType().getLocalName(), 0);\r
67             tmpNode = tmpNode.getParent();\r
68         }\r
69         \r
70         return Joiner.on(".").join(breadCrumbs);\r
71     }\r
72 \r
73     \r
74     /**\r
75      * @param treeRootNode\r
76      * @return dom tree, containing same node structure, yang nodes are associated \r
77      * to dom nodes as user data\r
78      */\r
79     public static org.w3c.dom.Document buildShadowDomTree(CompositeNode treeRootNode) {
80         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
81         org.w3c.dom.Document doc = null;\r
82         try {\r
83             DocumentBuilder bob = dbf.newDocumentBuilder();\r
84             doc = bob.newDocument();\r
85         } catch (ParserConfigurationException e) {\r
86             LOG.error("documentBuilder problem", e);\r
87             return null;\r
88         }\r
89         \r
90         \r
91         Stack<SimpleEntry<org.w3c.dom.Node, Node<?>>> jobQueue = new Stack<>();\r
92         jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(doc, treeRootNode));\r
93         \r
94         while (!jobQueue.isEmpty()) {\r
95             SimpleEntry<org.w3c.dom.Node, Node<?>> job = jobQueue.pop();\r
96             org.w3c.dom.Node jointPlace = job.getKey();\r
97             Node<?> item = job.getValue();\r
98             QName nodeType = item.getNodeType();\r
99             Element itemEl = doc.createElementNS(nodeType.getNamespace().toString(), \r
100                     item.getNodeType().getLocalName());\r
101             itemEl.setUserData(USER_KEY_NODE, item, null);\r
102             if (item instanceof SimpleNode<?>) {\r
103                 Object value = ((SimpleNode<?>) item).getValue();\r
104                 itemEl.setTextContent(String.valueOf(value));\r
105                 //itemEl.setAttribute("type", value.getClass().getSimpleName());\r
106             }\r
107             if (item instanceof NodeModification) {\r
108                 ModifyAction modificationAction = ((NodeModification) item).getModificationAction();\r
109                 if (modificationAction != null) {\r
110                     itemEl.setAttribute("modifyAction", modificationAction.toString());\r
111                 }\r
112             }\r
113             \r
114             jointPlace.appendChild(itemEl);\r
115             \r
116             if (item instanceof CompositeNode) {\r
117                 for (Node<?> child : ((CompositeNode) item).getChildren()) {\r
118                     jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(itemEl, child));\r
119                 }\r
120             }\r
121         }\r
122         \r
123         return doc;\r
124     }\r
125     \r
126     /**\r
127      * @param doc\r
128      * @param xpathEx\r
129      * @return user data value on found node\r
130      * @throws XPathExpressionException\r
131      */\r
132     @SuppressWarnings("unchecked")\r
133     public static <T> T findNodeByXpath(org.w3c.dom.Document doc, String xpathEx) \r
134             throws XPathExpressionException {\r
135         T userNode = null;\r
136         XPathFactory xPathfactory = XPathFactory.newInstance();\r
137         XPath xpath = xPathfactory.newXPath();\r
138         XPathExpression expr = xpath.compile(xpathEx);\r
139         \r
140         org.w3c.dom.Node result = (org.w3c.dom.Node) expr.evaluate(doc, XPathConstants.NODE);\r
141         if (result != null) {\r
142             userNode = (T) result.getUserData(USER_KEY_NODE);\r
143         } \r
144         \r
145         return userNode;\r
146     }\r
147 \r
148 \r
149     /**\r
150      * build NodeMap, where key = qName; value = node\r
151      * \r
152      * @param value\r
153      * @return map of children, where key = qName and value is list of children groupped by qName  \r
154      */\r
155     public static Map<QName, List<Node<?>>> buildNodeMap(List<Node<?>> value) {\r
156         Map<QName, List<Node<?>>> nodeMapTmp = new HashMap<>();\r
157         if (value == null || value.isEmpty()) {\r
158             throw new IllegalStateException(\r
159                     "nodeList should not be null or empty");\r
160         }\r
161         for (Node<?> node : value) {\r
162             List<Node<?>> qList = nodeMapTmp.get(node.getNodeType());\r
163             if (qList == null) {\r
164                 qList = new ArrayList<>();\r
165                 nodeMapTmp.put(node.getNodeType(), qList);\r
166             }\r
167             qList.add(node);\r
168         }\r
169         return nodeMapTmp;\r
170     }\r
171 \r
172 \r
173     /**\r
174      * @param context\r
175      * @return map of lists, where key = path; value = {@link DataSchemaNode}\r
176      */\r
177     public static Map<String, ListSchemaNode> buildMapOfListNodes(\r
178             SchemaContext context) {\r
179         Map<String, ListSchemaNode> mapOfLists = new HashMap<>();\r
180         \r
181         Stack<DataSchemaNode> jobQueue = new Stack<>();\r
182         jobQueue.addAll(context.getDataDefinitions());\r
183         \r
184         while (!jobQueue.isEmpty()) {\r
185             DataSchemaNode dataSchema = jobQueue.pop();\r
186             if (dataSchema instanceof ListSchemaNode) {\r
187                 mapOfLists.put(schemaPathToPath(dataSchema.getPath().getPath()), (ListSchemaNode) dataSchema);\r
188             }\r
189             \r
190             if (dataSchema instanceof DataNodeContainer) {\r
191                 jobQueue.addAll(((DataNodeContainer) dataSchema).getChildNodes());\r
192             }\r
193         }\r
194         \r
195         return mapOfLists;\r
196     }\r
197     \r
198     /**\r
199      * @param path\r
200      * @return\r
201      */\r
202     private static String schemaPathToPath(List<QName> qNamesPath) {\r
203         List<String> pathSeed = new ArrayList<>();\r
204         for (QName qNameItem : qNamesPath) {\r
205             pathSeed.add(qNameItem.getLocalName());\r
206         }\r
207         return Joiner.on(".").join(pathSeed);\r
208     }\r
209 \r
210     /**\r
211      * add given node to it's parent's list of children\r
212      * @param newNode\r
213      */\r
214     public static void fixParentRelation(Node<?> newNode) {\r
215         if (newNode.getParent() != null) {\r
216             List<Node<?>> siblings = newNode.getParent().getChildren();\r
217             if (!siblings.contains(newNode)) {\r
218                 siblings.add(newNode);\r
219             }\r
220         }\r
221     }\r
222     \r
223     /**\r
224      * crawl all children of given node and assign it as their parent\r
225      * @param parentNode\r
226      */\r
227     public static void fixChildrenRelation(CompositeNode parentNode) {\r
228         if (parentNode.getChildren() != null) {\r
229             for (Node<?> child : parentNode.getChildren()) {\r
230                 if (child instanceof AbstractNodeTO<?>) {\r
231                     ((AbstractNodeTO<?>) child).setParent(parentNode);\r
232                 }\r
233             }\r
234         }\r
235     }\r
236 \r
237 \r
238     /**\r
239      * @param keys\r
240      * @param dataMap\r
241      * @return list of values of map, found by given keys \r
242      */\r
243     public static <T, K> List<K> collectMapValues(List<T> keys,\r
244             Map<T, K> dataMap) {\r
245         List<K> valueSubList = new ArrayList<>();\r
246         for (T key : keys) {\r
247             valueSubList.add(dataMap.get(key));\r
248         }\r
249         \r
250         return valueSubList;\r
251     }\r
252     \r
253     /**\r
254      * @param nodes\r
255      * @return list of children in list of appropriate type\r
256      */\r
257     public static List<Node<?>> buildChildrenList(Node<?>...nodes) {\r
258         return Lists.newArrayList(nodes);\r
259     }\r
260 \r
261 }\r