first implementation of yang-data-api
[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.Document;\r
40 import org.w3c.dom.Element;\r
41 \r
42 import com.google.common.base.Joiner;\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     /**\r
52      * \r
53      */\r
54     private static final String USER_KEY_NODE = "node";\r
55     private static final Logger LOG = LoggerFactory.getLogger(NodeUtils.class);\r
56     \r
57     /**\r
58      * @param node\r
59      * @return node path up till root node\r
60      */\r
61     public static String buildPath(Node<?> node) {\r
62         Vector<String> breadCrumbs = new Vector<>();\r
63         Node<?> tmpNode = node;\r
64         while (tmpNode != null) {\r
65             breadCrumbs.insertElementAt(tmpNode.getNodeType().getLocalName(), 0);\r
66             tmpNode = tmpNode.getParent();\r
67         }\r
68         \r
69         return Joiner.on(".").join(breadCrumbs);\r
70     }\r
71 \r
72     \r
73     /**\r
74      * @param treeRootNode\r
75      * @return dom tree, containing same node structure, yang nodes are associated \r
76      * to dom nodes as user data\r
77      */\r
78     public static Document buildShadowDomTree(CompositeNode treeRootNode) {\r
79         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
80         Document doc = null;\r
81         try {\r
82             DocumentBuilder bob = dbf.newDocumentBuilder();\r
83             doc = bob.newDocument();\r
84         } catch (ParserConfigurationException e) {\r
85             LOG.error("documentBuilder problem", e);\r
86             return null;\r
87         }\r
88         \r
89         Stack<SimpleEntry<org.w3c.dom.Node, Node<?>>> jobQueue = new Stack<>();\r
90         jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(doc, treeRootNode));\r
91         \r
92         while (!jobQueue.isEmpty()) {\r
93             SimpleEntry<org.w3c.dom.Node, Node<?>> job = jobQueue.pop();\r
94             org.w3c.dom.Node jointPlace = job.getKey();\r
95             Node<?> item = job.getValue();\r
96             Element itemEl = doc.createElement(item.getNodeType().getLocalName());\r
97             itemEl.setUserData(USER_KEY_NODE, item, null);\r
98             if (item instanceof SimpleNode<?>) {\r
99                 Object value = ((SimpleNode<?>) item).getValue();\r
100                 itemEl.setTextContent(String.valueOf(value));\r
101                 itemEl.setAttribute("type", value.getClass().getSimpleName());\r
102             }\r
103             if (item instanceof NodeModification) {\r
104                 ModifyAction modificationAction = ((NodeModification) item).getModificationAction();\r
105                 if (modificationAction != null) {\r
106                     itemEl.setAttribute("modifyAction", modificationAction.toString());\r
107                 }\r
108             }\r
109             \r
110             jointPlace.appendChild(itemEl);\r
111             \r
112             if (item instanceof CompositeNode) {\r
113                 for (Node<?> child : ((CompositeNode) item).getChildren()) {\r
114                     jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(itemEl, child));\r
115                 }\r
116             }\r
117         }\r
118         \r
119         return doc;\r
120     }\r
121     \r
122     /**\r
123      * @param doc\r
124      * @param xpathEx\r
125      * @return user data value on found node\r
126      * @throws XPathExpressionException\r
127      */\r
128     @SuppressWarnings("unchecked")\r
129     public static <T> T findNodeByXpath(Document doc, String xpathEx) \r
130             throws XPathExpressionException {\r
131         T userNode = null;\r
132         XPathFactory xPathfactory = XPathFactory.newInstance();\r
133         XPath xpath = xPathfactory.newXPath();\r
134         XPathExpression expr = xpath.compile(xpathEx);\r
135         \r
136         org.w3c.dom.Node result = (org.w3c.dom.Node) expr.evaluate(doc, XPathConstants.NODE);\r
137         if (result != null) {\r
138             userNode = (T) result.getUserData(USER_KEY_NODE);\r
139         } \r
140         \r
141         return userNode;\r
142     }\r
143 \r
144 \r
145     /**\r
146      * build NodeMap, where key = qName; value = node\r
147      * \r
148      * @param value\r
149      * @return map of children, where key = qName and value is list of children groupped by qName  \r
150      */\r
151     public static Map<QName, List<Node<?>>> buildNodeMap(List<Node<?>> value) {\r
152         Map<QName, List<Node<?>>> nodeMapTmp = new HashMap<>();\r
153         if (value == null || value.isEmpty()) {\r
154             throw new IllegalStateException(\r
155                     "nodeList should not be null or empty");\r
156         }\r
157         for (Node<?> node : value) {\r
158             List<Node<?>> qList = nodeMapTmp.get(node.getNodeType());\r
159             if (qList == null) {\r
160                 qList = new ArrayList<>();\r
161                 nodeMapTmp.put(node.getNodeType(), qList);\r
162             }\r
163             qList.add(node);\r
164         }\r
165         return nodeMapTmp;\r
166     }\r
167 \r
168 \r
169     /**\r
170      * @param context\r
171      * @return map of lists, where key = path; value = {@link DataSchemaNode}\r
172      */\r
173     public static Map<String, ListSchemaNode> buildMapOfListNodes(\r
174             SchemaContext context) {\r
175         Map<String, ListSchemaNode> mapOfLists = new HashMap<>();\r
176         \r
177         Stack<DataSchemaNode> jobQueue = new Stack<>();\r
178         jobQueue.addAll(context.getDataDefinitions());\r
179         \r
180         while (!jobQueue.isEmpty()) {\r
181             DataSchemaNode dataSchema = jobQueue.pop();\r
182             if (dataSchema instanceof ListSchemaNode) {\r
183                 mapOfLists.put(schemaPathToPath(dataSchema.getPath().getPath()), (ListSchemaNode) dataSchema);\r
184             }\r
185             \r
186             if (dataSchema instanceof DataNodeContainer) {\r
187                 jobQueue.addAll(((DataNodeContainer) dataSchema).getChildNodes());\r
188             }\r
189         }\r
190         \r
191         return mapOfLists;\r
192     }\r
193 \r
194 \r
195     /**\r
196      * @param path\r
197      * @return\r
198      */\r
199     private static String schemaPathToPath(List<QName> qNamesPath) {\r
200         List<String> pathSeed = new ArrayList<>();\r
201         for (QName qNameItem : qNamesPath) {\r
202             pathSeed.add(qNameItem.getLocalName());\r
203         }\r
204         return Joiner.on(".").join(pathSeed);\r
205     }\r
206 }\r