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