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