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