Merge "BUG-1070: introduce YangSyntaxErrorException"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / LazyNodeToNodeMap.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.ArrayList;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.Stack;
15
16 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
17 import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
18 import org.opendaylight.yangtools.yang.data.api.MutableNode;
19 import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
20 import org.opendaylight.yangtools.yang.data.api.Node;
21 import org.opendaylight.yangtools.yang.data.api.NodeModification;
22 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
23
24 /**
25  * @author michal.rehak
26  *
27  */
28 public class LazyNodeToNodeMap {
29
30     private final Map<Node<?>, Node<?>> node2node = new HashMap<>();
31     private CompositeNode originalRoot;
32     private MutableCompositeNode mutableRoot;
33
34     /**
35      * @param originalNode
36      * @return mutable twin
37      */
38     public Node<?> getMutableEquivalent(final Node<?> originalNode) {
39         Node<?> mutableNode = node2node.get(originalNode);
40         if (mutableNode == null) {
41             addPathMembers(originalNode);
42             mutableNode = node2node.get(originalNode);
43         }
44
45         return mutableNode;
46     }
47
48     /**
49      * @param originalNode
50      */
51     private void addPathMembers(final Node<?> originalNode) {
52         Stack<Node<?>> jobQueue = new Stack<>();
53         jobQueue.push(originalNode);
54         while (!jobQueue.isEmpty()) {
55             Node<?> node2add = jobQueue.pop();
56             boolean fixChildrenRefOnly = false;
57             if (node2node.containsKey(node2add)) {
58                 if (node2add instanceof SimpleNode<?>) {
59                     continue;
60                 }
61                 fixChildrenRefOnly = true;
62             }
63
64             CompositeNode nextParent = node2add.getParent();
65             MutableNode<?> mutableEquivalent = null;
66
67             if (node2add instanceof SimpleNode<?>) {
68                 SimpleNode<?> node2addSimple = (SimpleNode<?>) node2add;
69                 MutableSimpleNode<?> nodeMutant = NodeFactory.createMutableSimpleNode(
70                         node2add.getNodeType(), null, node2addSimple.getValue(),
71                         node2addSimple.getModificationAction(), node2addSimple);
72                 mutableEquivalent = nodeMutant;
73             } else if (node2add instanceof CompositeNode) {
74                 MutableCompositeNode nodeMutant = null;
75                 if (fixChildrenRefOnly) {
76                     nodeMutant = (MutableCompositeNode) node2node.get(node2add);
77                 } else {
78                     CompositeNode node2addComposite = (CompositeNode) node2add;
79                     nodeMutant = NodeFactory.createMutableCompositeNode(node2add.getNodeType(),
80                         null, null,
81                         ((NodeModification) node2add).getModificationAction(), node2addComposite);
82                 }
83
84                 mutableEquivalent = nodeMutant;
85
86                 // tidy up children
87                 if (nodeMutant.getValue() == null) {
88                     nodeMutant.setValue(new ArrayList<Node<?>>());
89                 }
90                 for (Node<?> originalChildNode : ((CompositeNode) node2add).getValue()) {
91                     MutableNode<?> mutableChild = (MutableNode<?>) node2node.get(originalChildNode);
92                     fixChildrenRef(nodeMutant, mutableChild);
93                 }
94
95                 if (nodeMutant.getValue() != null && !nodeMutant.getValue().isEmpty()) {
96                     nodeMutant.init();
97                 }
98
99                 // store tree root, if occured
100                 if (nextParent == null) {
101                     if (originalRoot == null) {
102                         originalRoot = (CompositeNode) node2add;
103                         mutableRoot = nodeMutant;
104                     } else {
105                         if (!originalRoot.equals(node2add)) {
106                             throw new IllegalStateException("Different tree root node obtained - " +
107                                         "perhaps nodes of different trees are getting mixed up.");
108                         }
109                     }
110                 }
111             }
112
113             // feed jobQueue
114             node2node.put(node2add, mutableEquivalent);
115             if (nextParent != null) {
116                 jobQueue.push(nextParent);
117             }
118         }
119     }
120
121     /**
122      * @param nodeMutant
123      * @param mutableChild
124      */
125     private static void fixChildrenRef(final MutableCompositeNode nodeMutant,
126             final MutableNode<?> mutableChild) {
127         if (mutableChild != null) {
128             if (!nodeMutant.getValue().contains(mutableChild)) {
129                 nodeMutant.getValue().add(mutableChild);
130             }
131             CompositeNode parentOfChild = mutableChild.getParent();
132             if (parentOfChild == null) {
133                 mutableChild.setParent(nodeMutant);
134             } else {
135                 if (!parentOfChild.equals(nodeMutant)) {
136                     throw new IllegalStateException("Different parent node obtained - " +
137                             "perhaps nodes of different trees are getting mixed up.");
138                 }
139             }
140         }
141     }
142
143     /**
144      * @return the mutableRoot
145      */
146     public MutableCompositeNode getMutableRoot() {
147         return mutableRoot;
148     }
149
150     /**
151      * @return set of original nodes, registered in map as keys
152      */
153     public Set<Node<?>> getKeyNodes() {
154         return node2node.keySet();
155     }
156 }