Merge "Fix for Bug 511 (model + integration-test)"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / NodeFactory.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 java.util.AbstractMap.SimpleEntry;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Stack;
17
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
20 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
21 import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
22 import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
23 import org.opendaylight.yangtools.yang.data.api.Node;
24 import org.opendaylight.yangtools.yang.data.api.NodeModification;
25 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
26
27 /**
28  * @author michal.rehak
29  *
30  */
31 public abstract class NodeFactory {
32
33     /**
34      * @param qName
35      * @param parent
36      * @param value
37      * @return simple node modification, based on given qname, value and parent
38      */
39     public static <T> SimpleNode<T> createImmutableSimpleNode(QName qName,
40             CompositeNode parent, T value) {
41         return createImmutableSimpleNode(qName, parent, value, null);
42     }
43
44     /**
45      * @param qName
46      * @param parent
47      * @param value
48      * @param modifyAction
49      * @param original originating node, if available
50      * @return simple node modification, based on given qname, value and parent
51      */
52     public static <T> MutableSimpleNode<T> createMutableSimpleNode(QName qName,
53             CompositeNode parent, Object value, ModifyAction modifyAction, SimpleNode<T> original) {
54         @SuppressWarnings("unchecked")
55         MutableSimpleNodeTOImpl<T> simpleNodeTOImpl =
56                 new MutableSimpleNodeTOImpl<T>(qName, parent, (T) value, modifyAction);
57         simpleNodeTOImpl.setOriginal(original);
58         return simpleNodeTOImpl;
59     }
60
61     /**
62      * @param qName
63      * @param parent
64      * @param value
65      * @return composite node modification, based on given qname, value (children), parent and modifyAction
66      */
67     public static CompositeNode createImmutableCompositeNode(QName qName,
68             CompositeNode parent, List<Node<?>> value) {
69         return createImmutableCompositeNode(qName, parent, value, null);
70     }
71
72     /**
73      * @param qName
74      * @param parent
75      * @param valueArg
76      * @param modifyAction
77      * @param original originating node, if available
78      * @return composite node modification, based on given qName, value (children), parent and modifyAction
79      */
80     public static MutableCompositeNode createMutableCompositeNode(QName qName,
81             CompositeNode parent, List<Node<?>> valueArg, ModifyAction modifyAction, CompositeNode original) {
82         List<Node<?>> value = valueArg;
83         if (value == null) {
84             value = new ArrayList<>();
85         }
86         MutableCompositeNodeTOImpl compositeNodeTOImpl =
87                 new MutableCompositeNodeTOImpl(qName, parent, value, modifyAction);
88         compositeNodeTOImpl.setOriginal(original);
89         return compositeNodeTOImpl;
90     }
91
92
93     /**
94      * @param qName
95      * @param parent
96      * @param value
97      * @param modifyAction
98      * @return simple node modification, based on given qname, value, parent and modifyAction
99      */
100     public static <T> SimpleNode<T> createImmutableSimpleNode(QName qName,
101             CompositeNode parent, T value, ModifyAction modifyAction) {
102         SimpleNodeTOImpl<T> simpleNodeModTOImpl =
103                 new SimpleNodeTOImpl<T>(qName, parent, value, modifyAction);
104         return simpleNodeModTOImpl;
105     }
106
107     /**
108      * @param qName
109      * @param parent
110      * @param value
111      * @param modifyAction
112      * @return composite node modification, based on given qname, value (children), parent and modifyAction
113      */
114     public static CompositeNode createImmutableCompositeNode(QName qName,
115             CompositeNode parent, List<Node<?>> value, ModifyAction modifyAction) {
116         CompositeNodeTOImpl compositeNodeModTOImpl =
117                 new CompositeNodeTOImpl(qName, parent, value, modifyAction);
118         return compositeNodeModTOImpl;
119     }
120
121     /**
122      * @param node
123      * @return copy of given node, parent and value are the same, but parent
124      * has no reference to this copy
125      */
126     public static <T> SimpleNode<T> copyNode(SimpleNode<T> node) {
127         SimpleNode<T> twinNode = createImmutableSimpleNode(
128                     node.getNodeType(), node.getParent(), node.getValue());
129         return twinNode;
130     }
131
132     /**
133      * @param node
134      * @return copy of given node, parent and value are the same, but parent
135      * has no reference to this copy
136      */
137     public static <T> MutableSimpleNode<T> copyNodeAsMutable(SimpleNode<T> node) {
138         MutableSimpleNode<T> twinNode = createMutableSimpleNode(
139                     node.getNodeType(), node.getParent(), node.getValue(),
140                     node.getModificationAction(), null);
141         return twinNode;
142     }
143
144     /**
145      * @param node
146      * @param children
147      * @return copy of given node, parent and children are the same, but parent and children
148      * have no reference to this copy
149      */
150     public static CompositeNode copyNode(CompositeNode node, Node<?>... children) {
151         CompositeNode twinNode = createImmutableCompositeNode(
152                 node.getNodeType(), node.getParent(), Arrays.asList(children), node.getModificationAction());
153         return twinNode;
154     }
155
156     /**
157      * @param node
158      * @return copy of given node, parent and children are the same, but parent and children
159      * have no reference to this copy
160      */
161     public static CompositeNode copyNode(CompositeNode node) {
162        return copyNode(node, node.getChildren().toArray(new Node<?>[0]));
163     }
164
165     /**
166      * @param node root of original tree
167      * @param originalToCopyArg (optional) empty map, where binding between original and copy
168      * will be stored
169      * @return copy of given node and all subnodes recursively
170      */
171     public static MutableCompositeNode copyDeepAsMutable(CompositeNode node,
172             Map<Node<?>, Node<?>> originalToCopyArg) {
173
174         Map<Node<?>, Node<?>> originalToCopy = originalToCopyArg;
175         if (originalToCopy == null) {
176             originalToCopy = new HashMap<>();
177         }
178
179         MutableCompositeNode mutableRoot = createMutableCompositeNode(node.getNodeType(), null, null,
180                 node.getModificationAction(), null);
181         Stack<SimpleEntry<CompositeNode, MutableCompositeNode>> jobQueue = new Stack<>();
182         jobQueue.push(new SimpleEntry<CompositeNode, MutableCompositeNode>(node, mutableRoot));
183         originalToCopy.put(node, mutableRoot);
184
185         while (!jobQueue.isEmpty()) {
186             SimpleEntry<CompositeNode, MutableCompositeNode> job = jobQueue.pop();
187             CompositeNode originalNode = job.getKey();
188             MutableCompositeNode mutableNode = job.getValue();
189             mutableNode.setValue(new ArrayList<Node<?>>());
190
191             for (Node<?> child : originalNode.getChildren()) {
192                 Node<?> mutableAscendant = null;
193                 if (child instanceof CompositeNode) {
194                     MutableCompositeNode newMutable =
195                             createMutableCompositeNode(child.getNodeType(), mutableNode, null,
196                                     ((NodeModification) child).getModificationAction(), null);
197                     jobQueue.push(new SimpleEntry<CompositeNode, MutableCompositeNode>(
198                             (CompositeNode) child, newMutable));
199                     mutableAscendant = newMutable;
200                 } else if (child instanceof SimpleNode<?>) {
201                     mutableAscendant =
202                             createMutableSimpleNode(child.getNodeType(), mutableNode,
203                                     child.getValue(),
204                                     ((NodeModification) child).getModificationAction(), null);
205                 } else {
206                     throw new IllegalStateException("Node class deep copy not supported: "
207                             +child.getClass().getName());
208                 }
209
210                 mutableNode.getChildren().add(mutableAscendant);
211                 originalToCopy.put(child, mutableAscendant);
212             }
213             mutableNode.init();
214         }
215
216         return mutableRoot;
217     }
218
219     /**
220      * @param node root of original tree
221      * @param originalToCopyArg (optional) empty map, where binding between original and copy
222      * will be stored
223      * @return copy of given node and all subnodes recursively
224      */
225     public static CompositeNode copyDeepAsImmutable(CompositeNode node,
226             Map<Node<?>, Node<?>> originalToCopyArg) {
227         Stack<CompositeNode> jobQueue = new Stack<>();
228         jobQueue.push(node);
229
230         Map<Node<?>, Node<?>> originalToCopy = originalToCopyArg;
231         if (originalToCopy == null) {
232             originalToCopy = new HashMap<>();
233         }
234
235         while (!jobQueue.isEmpty()) {
236             CompositeNode jobNode = jobQueue.peek();
237             if (!originalToCopy.isEmpty()
238                     && originalToCopy.keySet().containsAll(jobNode.getChildren())) {
239                 jobQueue.pop();
240                 List<Node<?>> newChildren = NodeUtils.collectMapValues(jobNode.getChildren(), originalToCopy);
241                 CompositeNode nodeCopy = createImmutableCompositeNode(jobNode.getNodeType(), null,
242                         newChildren, jobNode.getModificationAction());
243                 NodeUtils.fixChildrenRelation(nodeCopy);
244                 originalToCopy.put(jobNode, nodeCopy);
245             } else {
246                 for (Node<?> child : jobNode.getChildren()) {
247                     if (child instanceof SimpleNode<?>) {
248                         originalToCopy.put(child, createImmutableSimpleNode(
249                                 child.getNodeType(), null, child.getValue(),
250                                 ((NodeModification) child).getModificationAction()));
251                     } else if (child instanceof CompositeNode) {
252                         jobQueue.push((CompositeNode) child);
253                     }
254                 }
255             }
256         }
257
258         return (CompositeNode) originalToCopy.get(node);
259     }
260
261 }