Use callbacks while parsing to NormalizedNodes.
[controller.git] / opendaylight / netconf / mdsal-netconf-connector / src / main / java / org / opendaylight / controller / netconf / mdsal / connector / ops / EditOperationStrategyProvider.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.controller.netconf.mdsal.connector.ops;
10
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Map;
14 import javax.annotation.Nullable;
15 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.EditConfigInput;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ExtensibleParser;
35 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
36
37 class EditOperationStrategyProvider extends DomToNormalizedNodeParserFactory.BuildingStrategyProvider {
38
39     private static final QName OPERATION_ATTRIBUTE = QName.create(EditConfigInput.QNAME.getNamespace(), null, XmlNetconfConstants.OPERATION_ATTR_KEY);
40
41     private final DataTreeChangeTracker changeTracker;
42
43     public EditOperationStrategyProvider(final DataTreeChangeTracker changeTracker) {
44         this.changeTracker = changeTracker;
45     }
46
47     @Override
48     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, LeafNode<?>> forLeaf() {
49         return new NetconfOperationLeafStrategy(changeTracker);
50     }
51
52     @Override
53     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, ContainerNode> forContainer() {
54         return new NetconfOperationContainerStrategy<>(changeTracker);
55     }
56
57     @Override
58     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, MapNode> forMap() {
59         return new NetconfOperationCollectionStrategy<>(changeTracker);
60     }
61
62     @Override
63     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeWithValue, LeafSetEntryNode<?>> forLeafSetEntry() {
64         return new NetconfOperationLeafSetEntryStrategy(changeTracker);
65     }
66
67     @Override
68     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> forMapEntry() {
69         return new NetconfOperationContainerStrategy<>(changeTracker);
70     }
71
72     @Override
73     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, OrderedMapNode> forOrderedList() {
74         return new NetconfOperationCollectionStrategy<>(changeTracker);
75     }
76
77     @Override
78     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, UnkeyedListEntryNode> forUnkeyedListEntry() {
79         return new NetconfOperationContainerStrategy<>(changeTracker);
80     }
81
82     @Override
83     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, UnkeyedListNode> forUnkeyedList() {
84         return new NetconfOperationCollectionStrategy<>(changeTracker);
85     }
86
87     @Override
88     protected ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, ChoiceNode> forChoice() {
89         return new NetconfOperationContainerStrategy<>(changeTracker);
90     }
91
92     @Override
93     public ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.AugmentationIdentifier, AugmentationNode> forAugmentation() {
94         return new NetconfOperationContainerStrategy<>(changeTracker);
95     }
96
97     private static class NetconfOperationCollectionStrategy<N extends NormalizedNode<YangInstanceIdentifier.NodeIdentifier, ?>> implements ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, N> {
98         private final DataTreeChangeTracker changeTracker;
99
100         public NetconfOperationCollectionStrategy(final DataTreeChangeTracker changeTracker) {
101             this.changeTracker = changeTracker;
102         }
103
104         @Nullable
105         @Override
106         public N build(final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ?, N> builder) {
107             changeTracker.popPath();
108             return builder.build();
109         }
110
111         @Override
112         public void prepareAttributes(final Map<QName, String> attributes, final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ?, N> containerBuilder) {
113             changeTracker.pushPath(containerBuilder.build().getIdentifier());
114         }
115     }
116
117     public static final class NetconfOperationLeafStrategy implements ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeIdentifier, LeafNode<?>> {
118
119         private final DataTreeChangeTracker dataTreeChangeTracker;
120
121         public NetconfOperationLeafStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
122             this.dataTreeChangeTracker = dataTreeChangeTracker;
123         }
124
125         @Nullable
126         @Override
127         public LeafNode<?> build(final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ?, LeafNode<?>> builder) {
128             LeafNode<?> node = builder.build();
129             String operation = (String) node.getAttributeValue(OPERATION_ATTRIBUTE);
130             if (operation == null) {
131                 return node;
132             }
133
134             if(builder instanceof AttributesBuilder<?>) {
135                 ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
136             }
137
138             node = builder.build();
139
140             ModifyAction action = ModifyAction.fromXmlValue(operation);
141             if (dataTreeChangeTracker.getDeleteOperationTracker() > 0 || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
142                 return node;
143             } else {
144                 if (!action.equals(dataTreeChangeTracker.peekAction())) {
145                     dataTreeChangeTracker.pushPath(node.getIdentifier());
146                     dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action, new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
147                     dataTreeChangeTracker.popPath();
148                     return null;
149                 } else {
150                     return node;
151                 }
152             }
153         }
154
155         @Override
156         public void prepareAttributes(final Map<QName, String> attributes, final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ?, LeafNode<?>> containerBuilder) {
157             // Noop
158         }
159     }
160
161     public static final class NetconfOperationLeafSetEntryStrategy implements ExtensibleParser.BuildingStrategy<YangInstanceIdentifier.NodeWithValue, LeafSetEntryNode<?>> {
162
163         private final DataTreeChangeTracker dataTreeChangeTracker;
164
165         public NetconfOperationLeafSetEntryStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
166             this.dataTreeChangeTracker = dataTreeChangeTracker;
167         }
168
169         @Nullable
170         @Override
171         public LeafSetEntryNode<?> build(final NormalizedNodeBuilder<YangInstanceIdentifier.NodeWithValue, ?, LeafSetEntryNode<?>> builder) {
172             LeafSetEntryNode<?> node = builder.build();
173             String operation = (String) node.getAttributeValue(OPERATION_ATTRIBUTE);
174             if (operation == null) {
175                 return node;
176             }
177
178             if (builder instanceof AttributesBuilder<?>) {
179                 ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
180             }
181
182             node = builder.build();
183
184             ModifyAction action = ModifyAction.fromXmlValue(operation);
185             if (dataTreeChangeTracker.getDeleteOperationTracker() > 0 || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
186                 return node;
187             } else {
188                 if (!action.equals(dataTreeChangeTracker.peekAction())) {
189                     dataTreeChangeTracker.pushPath(node.getIdentifier());
190                     dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action, new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
191                     dataTreeChangeTracker.popPath();
192                     return null;
193                 } else {
194                     return node;
195                 }
196             }
197         }
198
199         @Override
200         public void prepareAttributes(final Map<QName, String> attributes, final NormalizedNodeBuilder<YangInstanceIdentifier.NodeWithValue, ?, LeafSetEntryNode<?>> containerBuilder) {
201
202         }
203     }
204
205     public static final class NetconfOperationContainerStrategy<P extends YangInstanceIdentifier.PathArgument, N extends DataContainerNode<P>> implements ExtensibleParser.BuildingStrategy<P, N> {
206
207         private final DataTreeChangeTracker dataTreeChangeTracker;
208
209         public NetconfOperationContainerStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
210             this.dataTreeChangeTracker = dataTreeChangeTracker;
211         }
212
213         @Nullable
214         @Override
215         public N build(final NormalizedNodeBuilder<P, ?, N> builder) {
216             if (builder instanceof AttributesBuilder<?>) {
217                 ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
218             }
219
220             final N node = builder.build();
221             final ModifyAction currentAction = dataTreeChangeTracker.popAction();
222
223             //if we know that we are going to delete a parent node just complete the entire subtree
224             if (dataTreeChangeTracker.getDeleteOperationTracker() > 0 || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
225                 dataTreeChangeTracker.popPath();
226                 return node;
227             } else {
228                 //if parent and current actions dont match create a DataTreeChange and add it to the change list
229                 //dont add a new child to the parent node
230                 if (!currentAction.equals(dataTreeChangeTracker.peekAction())) {
231                     dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, currentAction, new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
232                     dataTreeChangeTracker.popPath();
233                     return null;
234                 } else {
235                     dataTreeChangeTracker.popPath();
236                     return node;
237                 }
238             }
239         }
240
241         @Override
242         public void prepareAttributes(final Map<QName, String> attributes, final NormalizedNodeBuilder<P, ?, N> containerBuilder) {
243             dataTreeChangeTracker.pushPath(containerBuilder.build().getIdentifier());
244             final String operation = attributes.get(OPERATION_ATTRIBUTE);
245             if (operation != null) {
246                 dataTreeChangeTracker.pushAction(ModifyAction.fromXmlValue(operation));
247             } else {
248                 dataTreeChangeTracker.pushAction(dataTreeChangeTracker.peekAction() != null
249                         ? dataTreeChangeTracker.peekAction() : dataTreeChangeTracker.getDefaultAction());
250             }
251         }
252     }
253 }