first implementation of yang-data-api
[controller.git] / opendaylight / sal / yang-prototype / yang / yang-data-impl / src / main / java / org / opendaylight / controller / yang / data / impl / NodeModificationBuilderImpl.java
1 /**\r
2  * \r
3  */\r
4 package org.opendaylight.controller.yang.data.impl;\r
5 \r
6 import java.util.HashMap;\r
7 import java.util.HashSet;\r
8 import java.util.List;\r
9 import java.util.Map;\r
10 import java.util.Set;\r
11 import java.util.Stack;\r
12 \r
13 import org.opendaylight.controller.yang.common.QName;\r
14 import org.opendaylight.controller.yang.data.api.CompositeNode;\r
15 import org.opendaylight.controller.yang.data.api.ModifyAction;\r
16 import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
17 import org.opendaylight.controller.yang.data.api.MutableNode;\r
18 import org.opendaylight.controller.yang.data.api.MutableSimpleNode;\r
19 import org.opendaylight.controller.yang.data.api.Node;\r
20 import org.opendaylight.controller.yang.data.api.NodeModificationBuilder;\r
21 import org.opendaylight.controller.yang.model.api.ListSchemaNode;\r
22 import org.opendaylight.controller.yang.model.api.SchemaContext;\r
23 \r
24 /**\r
25  * @author michal.rehak\r
26  *\r
27  */\r
28 public class NodeModificationBuilderImpl implements NodeModificationBuilder {\r
29     \r
30     private SchemaContext context;\r
31     \r
32     private Set<MutableNode<?>> changeLog;\r
33     private Map<Node<?>, Node<?>> originalToMutable;\r
34 \r
35     private MutableCompositeNode mutableRoot;\r
36 \r
37     /**\r
38      * @param originalTreeRootNode \r
39      * @param context\r
40      */\r
41     public NodeModificationBuilderImpl(CompositeNode originalTreeRootNode, SchemaContext context) {\r
42         this.context = context;\r
43         originalToMutable = new HashMap<>();\r
44         mutableRoot = NodeFactory.copyDeepNode(originalTreeRootNode, originalToMutable);\r
45         changeLog = new HashSet<>();\r
46     }\r
47 \r
48     /**\r
49      * add given node to it's parent's list of children\r
50      * @param newNode\r
51      */\r
52     private static void fixParentRelation(Node<?> newNode) {\r
53         if (newNode.getParent() != null) {\r
54             List<Node<?>> siblings = newNode.getParent().getChildren();\r
55             if (!siblings.contains(newNode)) {\r
56                 siblings.add(newNode);\r
57             }\r
58         }\r
59     }\r
60 \r
61     /**\r
62      * @param modNode\r
63      * @param action \r
64      */\r
65     private void addModificationToLog(MutableNode<?> modNode, ModifyAction action) {\r
66         modNode.setModifyAction(action);\r
67         changeLog.add(modNode);\r
68     }\r
69 \r
70     @Override\r
71     public void addNode(MutableSimpleNode<?> newNode) {\r
72         fixParentRelation(newNode);\r
73         addModificationToLog(newNode, ModifyAction.CREATE);\r
74     }\r
75     \r
76     @Override\r
77     public void addNode(MutableCompositeNode newNode) {\r
78         fixParentRelation(newNode);\r
79         addModificationToLog(newNode, ModifyAction.CREATE);\r
80     }\r
81     \r
82     @Override\r
83     public void replaceNode(MutableSimpleNode<?> replacementNode) {\r
84         addModificationToLog(replacementNode, ModifyAction.REPLACE);\r
85     }\r
86     \r
87     @Override\r
88     public void replaceNode(MutableCompositeNode replacementNode) {\r
89         addModificationToLog(replacementNode, ModifyAction.REPLACE);\r
90     }\r
91 \r
92     @Override\r
93     public void deleteNode(MutableCompositeNode deadNode) {\r
94         addModificationToLog(deadNode, ModifyAction.DELETE);\r
95     }\r
96     \r
97     @Override\r
98     public void deleteNode(MutableSimpleNode<?> deadNode) {\r
99         addModificationToLog(deadNode, ModifyAction.DELETE);\r
100     }\r
101 \r
102     @Override\r
103     public void removeNode(MutableSimpleNode<?> deadNode) {\r
104         addModificationToLog(deadNode, ModifyAction.REMOVE);\r
105     }\r
106     \r
107     @Override\r
108     public void removeNode(MutableCompositeNode deadNode) {\r
109         addModificationToLog(deadNode, ModifyAction.REMOVE);\r
110     }\r
111     \r
112     @Override\r
113     public void mergeNode(MutableCompositeNode alteredNode) {\r
114         addModificationToLog(alteredNode, ModifyAction.MERGE);\r
115     }\r
116 \r
117     /**\r
118      * @return minimalistic tree containing diffs only\r
119      */\r
120     @Override\r
121     public CompositeNode buildDiffTree() {\r
122         Set<Node<?>> wanted = new HashSet<>();\r
123         \r
124         // walk changeLog, collect all required nodes\r
125         for (MutableNode<?> mutant : changeLog) {\r
126             wanted.addAll(collectSelfAndAllParents(mutant));\r
127         }\r
128         \r
129         // TODO:: walk wanted and add relevant keys\r
130         Map<String, ListSchemaNode>  mapOfLists = NodeUtils.buildMapOfListNodes(context);\r
131         Set<Node<?>> wantedKeys = new HashSet<>();\r
132         for (Node<?> outlaw : wanted) {\r
133             if (outlaw instanceof CompositeNode) {\r
134                 String path = NodeUtils.buildPath(outlaw);\r
135                 if (mapOfLists.containsKey(path)) {\r
136                     ListSchemaNode listSchema = mapOfLists.get(path);\r
137                     if (listSchema.getQName().equals(outlaw.getNodeType())) {\r
138                         // try to add key subnode to wanted list\r
139                         List<QName> supportedKeys = listSchema.getKeyDefinition();\r
140                         for (Node<?> outlawChildren : ((CompositeNode) outlaw).getChildren()) {\r
141                             if (supportedKeys.contains(outlawChildren.getNodeType())) {\r
142                                 wantedKeys.add(outlawChildren);\r
143                             }\r
144                         }\r
145                     }\r
146                 }\r
147             }\r
148         }\r
149         wanted.addAll(wantedKeys);\r
150         \r
151         // remove all unwanted nodes from tree\r
152         removeUnrelevantNodes(mutableRoot, wanted);\r
153         \r
154         return mutableRoot;\r
155     }\r
156 \r
157     /**\r
158      * @param mutableRoot2\r
159      * @param wanted\r
160      */\r
161     private static void removeUnrelevantNodes(MutableCompositeNode mutRoot,\r
162             Set<Node<?>> wanted) {\r
163         Stack<MutableNode<?>> jobQueue = new Stack<>();\r
164         jobQueue.push(mutRoot);\r
165         while (!jobQueue.isEmpty()) {\r
166             MutableNode<?> mutNode = jobQueue.pop();\r
167             if (!wanted.contains(mutNode)) {\r
168                 if (mutNode.getParent() != null) {\r
169                     mutNode.getParent().getChildren().remove(mutNode);\r
170                 }\r
171             } else {\r
172                 if (mutNode instanceof MutableCompositeNode) {\r
173                     for (Node<?> mutChild : ((MutableCompositeNode) mutNode).getChildren()) {\r
174                         jobQueue.push((MutableNode<?>) mutChild);\r
175                     }\r
176                 }\r
177             }\r
178         }\r
179     }\r
180 \r
181     /**\r
182      * @param focusedAncestor\r
183      * @return set of parents and focusedAncestor itself\r
184      */\r
185     private static Set<Node<?>> collectSelfAndAllParents(Node<?> focusedAncestor) {\r
186         Set<Node<?>> family = new HashSet<>();\r
187         Node<?> tmpNode = focusedAncestor;\r
188         while (tmpNode != null) {\r
189             family.add(tmpNode);\r
190             tmpNode = tmpNode.getParent();\r
191         }\r
192         return family;\r
193     }\r
194 \r
195     /**\r
196      * @param originalNode\r
197      * @return mutable version of given node\r
198      */\r
199     @Override\r
200     public Node<?> getMutableEquivalent(Node<?> originalNode) {\r
201         return originalToMutable.get(originalNode);\r
202     }\r
203 \r
204 }\r