Fixed bug when new childs were ommited during data store merge.
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / sal / dom / broker / util / YangDataOperations.xtend
1 /*
2  * Copyright (c) 2014 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.controller.sal.dom.broker.util
9
10 import org.opendaylight.yangtools.yang.data.api.CompositeNode
11 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
12 import static com.google.common.base.Preconditions.*;
13 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
14 import java.util.ArrayList
15
16 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
17 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
18 import org.opendaylight.yangtools.yang.data.api.Node
19 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
20 import java.util.List
21 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
22 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
23 import java.util.Collections
24 import java.util.HashSet
25 import org.opendaylight.yangtools.yang.common.QName
26 import static extension org.opendaylight.controller.sal.dom.broker.util.YangDataUtils.*;
27
28 class YangDataOperations {
29
30     static def CompositeNode merge(DataSchemaNode schema, CompositeNode stored, CompositeNode modified, boolean config) {
31         if (stored === null) {
32             return modified;
33         }
34
35         if (schema instanceof ListSchemaNode || schema instanceof ContainerSchemaNode) {
36             return mergeContainer(schema as DataNodeContainer, stored, modified, config);
37         }
38         throw new IllegalArgumentException("Supplied node is not data node container.");
39     }
40
41     private def static checkConfigurational(DataSchemaNode node, boolean config) {
42         if (config) {
43             checkArgument(node.configuration, "Supplied composite node is not configurational.");
44         }
45     }
46
47     private static dispatch def Iterable<? extends Node<?>> mergeMultiple(LeafSchemaNode node, List<Node<?>> original,
48         List<Node<?>> modified, boolean configurational) {
49         checkArgument(original.size === 1);
50         checkArgument(modified.size === 1);
51         
52         return modified;
53     }
54
55     private static dispatch def Iterable<? extends Node<?>> mergeMultiple(LeafListSchemaNode node,
56         List<Node<?>> original, List<Node<?>> modified, boolean configurational) {
57         return modified;
58     }
59
60     private static dispatch def Iterable<? extends Node<?>> mergeMultiple(ContainerSchemaNode node,
61         List<Node<?>> original, List<Node<?>> modified, boolean configurational) {
62         checkArgument(original.size === 1);
63         checkArgument(modified.size === 1);
64         return Collections.singletonList(
65             merge(node, original.get(0) as CompositeNode, modified.get(0) as CompositeNode, configurational));
66     }
67
68     private static dispatch def Iterable<? extends Node<?>> mergeMultiple(ListSchemaNode node, List<Node<?>> original,
69         List<Node<?>> modified, boolean configurational) {
70         
71         if(node.keyDefinition === null || node.keyDefinition.empty) {
72             return modified;
73         }
74         val originalMap = (original as List).toIndexMap(node.keyDefinition);
75         val modifiedMap = (modified as List).toIndexMap(node.keyDefinition);
76         
77         val List<Node<?>> mergedNodes = new ArrayList(original.size + modified.size);
78         for(entry : modifiedMap.entrySet) {
79             val originalEntry = originalMap.get(entry.key);
80             if(originalEntry != null) {
81                 originalMap.remove(entry.key);
82                 mergedNodes.add(merge(node,originalEntry,entry.value,configurational));
83             } else {
84                 mergedNodes.add(entry.value);
85             }
86         }
87         mergedNodes.addAll(originalMap.values);
88         return mergedNodes;
89     }
90
91     static private def CompositeNode mergeContainer(DataNodeContainer schema, CompositeNode stored,
92         CompositeNode modified, boolean config) {
93         if (stored == null) {
94             return modified;
95         }
96         checkNotNull(stored)
97         checkNotNull(modified)
98         checkArgument(stored.nodeType == modified.nodeType);
99
100         val mergedChildNodes = new ArrayList<Node<?>>(stored.children.size + modified.children.size);
101         
102         val toProcess = new HashSet<QName>(stored.keySet);
103         toProcess.addAll(modified.keySet);
104         
105         for (qname : toProcess) {
106             val schemaChild = schema.getDataChildByName(qname);
107             val storedChildren = stored.get(qname);
108             val modifiedChildren = modified.get(qname);
109
110             if (modifiedChildren !== null && !modifiedChildren.empty) {
111                 if (storedChildren === null || storedChildren.empty || schemaChild === null) {
112                     mergedChildNodes.addAll(modifiedChildren);
113                 } else {
114                     mergedChildNodes.addAll(mergeMultiple(schemaChild, storedChildren, modifiedChildren, config));
115                 }
116             } else if (storedChildren !== null && !storedChildren.empty) {
117                 mergedChildNodes.addAll(storedChildren);
118             }
119         }
120         return new CompositeNodeTOImpl(stored.nodeType, null, mergedChildNodes);
121     }
122
123 }