BUG-704 Remove pax from netconf identity-ref test.
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / SchemaAwareApplyOperation.java
1 package org.opendaylight.controller.md.sal.dom.store.impl;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.concurrent.ExecutionException;
10
11 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
12 import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
13 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
14 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
20 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
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.NormalizedNodeContainer;
30 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
44 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
45 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
46 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
47 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
48 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
50 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
54
55 import com.google.common.base.Function;
56 import com.google.common.base.Optional;
57 import com.google.common.base.Preconditions;
58 import com.google.common.cache.CacheBuilder;
59 import com.google.common.cache.CacheLoader;
60 import com.google.common.cache.LoadingCache;
61 import com.google.common.collect.ImmutableMap;
62 import com.google.common.collect.ImmutableSet;
63 import com.google.common.collect.ImmutableSet.Builder;
64 import com.google.common.primitives.UnsignedLong;
65
66 public abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
67
68     public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode) {
69         if (schemaNode instanceof ContainerSchemaNode) {
70             return new ContainerModificationStrategy((ContainerSchemaNode) schemaNode);
71         } else if (schemaNode instanceof ListSchemaNode) {
72             return fromListSchemaNode((ListSchemaNode) schemaNode);
73         } else if (schemaNode instanceof ChoiceNode) {
74             return new ChoiceModificationStrategy((ChoiceNode) schemaNode);
75         } else if (schemaNode instanceof LeafListSchemaNode) {
76             return fromLeafListSchemaNode((LeafListSchemaNode) schemaNode);
77         } else if (schemaNode instanceof LeafSchemaNode) {
78             return new LeafModificationStrategy((LeafSchemaNode) schemaNode);
79         }
80         throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
81     }
82
83     private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
84         List<QName> keyDefinition = schemaNode.getKeyDefinition();
85         if (keyDefinition == null || keyDefinition.isEmpty()) {
86             return new UnkeyedListModificationStrategy(schemaNode);
87         }
88         if (schemaNode.isUserOrdered()) {
89             return new OrderedMapModificationStrategy(schemaNode);
90         }
91
92         return new UnorderedMapModificationStrategy(schemaNode);
93     }
94
95     private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
96         if(schemaNode.isUserOrdered()) {
97             return new OrderedLeafSetModificationStrategy(schemaNode);
98         } else {
99             return new UnorderedLeafSetModificationStrategy(schemaNode);
100         }
101     }
102
103
104     public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
105             final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
106         AugmentationSchema augSchema = null;
107         allAugments: for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
108             boolean containsAll = true;
109             for (DataSchemaNode child : potential.getChildNodes()) {
110                 if (identifier.getPossibleChildNames().contains(child.getQName())) {
111                     augSchema = potential;
112                     break allAugments;
113                 }
114             }
115         }
116         if (augSchema != null) {
117             return new AugmentationModificationStrategy(augSchema, resolvedTree);
118         }
119         return null;
120     }
121
122     protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
123         Optional<ModificationApplyOperation> potential = getChild(child);
124         checkArgument(potential.isPresent(), "Operation for child %s is not defined.", child);
125         return potential.get();
126     }
127
128     @Override
129     public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
130         if (modification.getModificationType() == ModificationType.WRITE) {
131             verifyWritenStructure(modification.getWritenValue());
132         }
133     }
134
135     protected abstract void verifyWritenStructure(NormalizedNode<?, ?> writenValue);
136
137     @Override
138     public boolean isApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
139         switch (modification.getModificationType()) {
140         case DELETE:
141             return isDeleteApplicable(modification, current);
142         case SUBTREE_MODIFIED:
143             return isSubtreeModificationApplicable(modification, current);
144         case WRITE:
145             return isWriteApplicable(modification, current);
146         case MERGE:
147             return isMergeApplicable(modification,current);
148         case UNMODIFIED:
149             return true;
150         default:
151             return false;
152         }
153     }
154
155     private boolean isMergeApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
156         Optional<StoreMetadataNode> original = modification.getOriginal();
157         if (original.isPresent() && current.isPresent()) {
158             return isNotConflicting(original.get(), current.get());
159         } else if (current.isPresent()) {
160             return true;
161         }
162         return true;
163     }
164
165     protected boolean isWriteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
166         Optional<StoreMetadataNode> original = modification.getOriginal();
167         if (original.isPresent() && current.isPresent()) {
168             return isNotConflicting(original.get(), current.get());
169         } else if (current.isPresent()) {
170             return false;
171         }
172         return true;
173
174     }
175
176     protected final boolean isNotConflicting(final StoreMetadataNode original, final StoreMetadataNode current) {
177         return original.getNodeVersion().equals(current.getNodeVersion())
178                 && original.getSubtreeVersion().equals(current.getSubtreeVersion());
179     }
180
181     protected abstract boolean isSubtreeModificationApplicable(final NodeModification modification,
182             final Optional<StoreMetadataNode> current);
183
184     private boolean isDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
185         // FiXME: Add delete conflict detection.
186         return true;
187     }
188
189     @Override
190     public final Optional<StoreMetadataNode> apply(final NodeModification modification,
191             final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
192
193         switch (modification.getModificationType()) {
194         case DELETE:
195             return modification.storeSnapshot(Optional.<StoreMetadataNode> absent());
196         case SUBTREE_MODIFIED:
197             Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
198                     modification);
199             return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(),
200                     subtreeVersion)));
201         case MERGE:
202             if(currentMeta.isPresent()) {
203                 return modification.storeSnapshot(Optional.of(applyMerge(modification,currentMeta.get(),subtreeVersion)));
204             } // Fallback to write is intentional - if node is not preexisting merge is same as write
205         case WRITE:
206             return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion)));
207         case UNMODIFIED:
208             return currentMeta;
209         default:
210             throw new IllegalArgumentException("Provided modification type is not supported.");
211         }
212     }
213
214     protected abstract StoreMetadataNode applyMerge(NodeModification modification,
215             StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
216
217     protected abstract StoreMetadataNode applyWrite(NodeModification modification,
218             Optional<StoreMetadataNode> currentMeta, UnsignedLong subtreeVersion);
219
220     protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
221             StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
222
223     public static abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends
224             SchemaAwareApplyOperation {
225
226         private final T schema;
227         private final Class<? extends NormalizedNode<?, ?>> nodeClass;
228
229         protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
230             super();
231             this.schema = schema;
232             this.nodeClass = nodeClass;
233         }
234
235         @Override
236         protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
237             checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass);
238         }
239
240         @Override
241         public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
242             throw new UnsupportedOperationException("Node " + schema.getPath()
243                     + "is leaf type node. Child nodes not allowed");
244         }
245
246         @Override
247         protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
248                 final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
249             throw new UnsupportedOperationException("Node " + schema.getPath()
250                     + "is leaf type node. Subtree change is not allowed.");
251         }
252
253         @Override
254         protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
255                 final UnsignedLong subtreeVersion) {
256             return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
257         }
258
259         @Override
260         protected StoreMetadataNode applyWrite(final NodeModification modification,
261                 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
262             UnsignedLong nodeVersion = subtreeVersion;
263             return StoreMetadataNode.builder().setNodeVersion(nodeVersion).setSubtreeVersion(subtreeVersion)
264                     .setData(modification.getWritenValue()).build();
265         }
266
267         @Override
268         protected boolean isSubtreeModificationApplicable(final NodeModification modification,
269                 final Optional<StoreMetadataNode> current) {
270             return false;
271         }
272
273     }
274
275     public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
276
277         @SuppressWarnings({ "unchecked", "rawtypes" })
278         protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
279             super(schema, (Class) LeafSetEntryNode.class);
280         }
281     }
282
283     public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
284
285         @SuppressWarnings({ "unchecked", "rawtypes" })
286         protected LeafModificationStrategy(final LeafSchemaNode schema) {
287             super(schema, (Class) LeafNode.class);
288         }
289     }
290
291     public static abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
292
293         private final Class<? extends NormalizedNode<?, ?>> nodeClass;
294
295         protected NormalizedNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
296             this.nodeClass = nodeClass;
297         }
298
299         @Override
300         public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
301             if (modification.getModificationType() == ModificationType.WRITE) {
302
303             }
304             for (NodeModification childModification : modification.getModifications()) {
305                 resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
306             }
307         }
308
309         @SuppressWarnings("rawtypes")
310         @Override
311         protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
312             checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass);
313             checkArgument(writenValue instanceof NormalizedNodeContainer);
314             NormalizedNodeContainer writenCont = (NormalizedNodeContainer) writenValue;
315             for (Object child : writenCont.getValue()) {
316                 checkArgument(child instanceof NormalizedNode);
317                 NormalizedNode childNode = (NormalizedNode) child;
318             }
319         }
320
321         @Override
322         protected StoreMetadataNode applyWrite(final NodeModification modification,
323                 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
324             //
325             NormalizedNode<?, ?> newValue = modification.getWritenValue();
326
327             UnsignedLong nodeVersion = subtreeVersion;
328             if (currentMeta.isPresent()) {
329                 nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
330             }
331             StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion);
332
333             if (!modification.hasAdditionalModifications()) {
334                 return newValueMeta;
335             }
336             @SuppressWarnings("rawtypes")
337             NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier());
338             StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) //
339                     .setNodeVersion(nodeVersion) //
340                     .setSubtreeVersion(subtreeVersion);
341
342             Set<PathArgument> processedPreexisting = applyPreexistingChildren(modification, newValueMeta.getChildren(),
343                     builder, nodeVersion);
344             applyNewChildren(modification, processedPreexisting, builder, nodeVersion);
345
346             return builder.build();
347
348         }
349
350         @Override
351         protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
352                 final UnsignedLong subtreeVersion) {
353             // For Node Containers - merge is same as subtree change - we only replace children.
354             return applySubtreeChange(modification, currentMeta, subtreeVersion);
355         }
356
357         @Override
358         public StoreMetadataNode applySubtreeChange(final NodeModification modification,
359                 final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
360
361             UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
362             @SuppressWarnings("rawtypes")
363             NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier());
364             StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder)
365                     .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion())
366                     .setSubtreeVersion(updatedSubtreeVersion);
367             // We process preexisting nodes
368             Set<PathArgument> processedPreexisting = applyPreexistingChildren(modification, currentMeta.getChildren(),
369                     builder, updatedSubtreeVersion);
370             applyNewChildren(modification, processedPreexisting, builder, updatedSubtreeVersion);
371             return builder.build();
372         }
373
374         private void applyNewChildren(final NodeModification modification, final Set<PathArgument> ignore,
375                 final StoreNodeCompositeBuilder builder, final UnsignedLong subtreeVersion) {
376             for (NodeModification childModification : modification.getModifications()) {
377                 PathArgument childIdentifier = childModification.getIdentifier();
378                 // We skip allready processed modifications
379                 if (ignore.contains(childIdentifier)) {
380                     continue;
381                 }
382
383                 builder.addIfPresent(resolveChildOperation(childIdentifier) //
384                         .apply(childModification, Optional.<StoreMetadataNode> absent(), subtreeVersion));
385             }
386         }
387
388         private Set<PathArgument> applyPreexistingChildren(final NodeModification modification,
389                 final Iterable<StoreMetadataNode> children, final StoreNodeCompositeBuilder nodeBuilder,
390                 final UnsignedLong subtreeVersion) {
391             Builder<PathArgument> processedModifications = ImmutableSet.<PathArgument> builder();
392             for (StoreMetadataNode childMeta : children) {
393                 PathArgument childIdentifier = childMeta.getIdentifier();
394                 // We retrieve Child modification metadata
395                 Optional<NodeModification> childModification = modification.getChild(childIdentifier);
396                 // Node is modified
397                 if (childModification.isPresent()) {
398                     processedModifications.add(childIdentifier);
399                     Optional<StoreMetadataNode> result = resolveChildOperation(childIdentifier) //
400                             .apply(childModification.get(), Optional.of(childMeta), subtreeVersion);
401                     nodeBuilder.addIfPresent(result);
402                 } else {
403                     // Child is unmodified - reuse existing metadata and data
404                     // snapshot
405                     nodeBuilder.add(childMeta);
406                 }
407             }
408             return processedModifications.build();
409         }
410
411         @Override
412         protected boolean isSubtreeModificationApplicable(final NodeModification modification,
413                 final Optional<StoreMetadataNode> current) {
414             if (false == current.isPresent()) {
415                 return false;
416             }
417             boolean result = true;
418             StoreMetadataNode currentMeta = current.get();
419             for (NodeModification childMod : modification.getModifications()) {
420                 PathArgument childId = childMod.getIdentifier();
421                 Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
422                 result &= resolveChildOperation(childId).isApplicable(childMod, childMeta);
423             }
424             return result;
425         }
426
427         @SuppressWarnings("rawtypes")
428         protected abstract NormalizedNodeContainerBuilder createBuilder(PathArgument identifier);
429     }
430
431     public static abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends
432             NormalizedNodeContainerModificationStrategy {
433
434         private final T schema;
435         private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
436                 .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
437
438                     @Override
439                     public ModificationApplyOperation apply(final PathArgument identifier) {
440                         if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
441                             return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier);
442                         }
443
444                         DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType());
445                         if (child == null) {
446                             return null;
447                         }
448                         return from(child);
449                     }
450                 }));
451
452         protected DataNodeContainerModificationStrategy(final T schema,
453                 final Class<? extends NormalizedNode<?, ?>> nodeClass) {
454             super(nodeClass);
455             this.schema = schema;
456         }
457
458         protected T getSchema() {
459             return schema;
460         }
461
462         @Override
463         public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
464             try {
465                 return Optional.<ModificationApplyOperation> fromNullable(childCache.get(identifier));
466             } catch (ExecutionException e) {
467                 return Optional.absent();
468             }
469         }
470
471         @Override
472         @SuppressWarnings("rawtypes")
473         protected abstract DataContainerNodeBuilder createBuilder(PathArgument identifier);
474
475         @Override
476         public String toString() {
477             return getClass().getSimpleName() + " [" + schema + "]";
478         }
479
480     }
481
482     public static class ContainerModificationStrategy extends
483             DataNodeContainerModificationStrategy<ContainerSchemaNode> {
484
485         public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
486             super(schemaNode, ContainerNode.class);
487         }
488
489         @Override
490         @SuppressWarnings("rawtypes")
491         protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
492             // TODO Auto-generated method stub
493             checkArgument(identifier instanceof NodeIdentifier);
494             return ImmutableContainerNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
495         }
496
497     }
498
499     public static class UnkeyedListItemModificationStrategy extends
500             DataNodeContainerModificationStrategy<ListSchemaNode> {
501
502         public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
503             super(schemaNode, UnkeyedListEntryNode.class);
504         }
505
506         @Override
507         @SuppressWarnings("rawtypes")
508         protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
509             checkArgument(identifier instanceof NodeIdentifier);
510             return ImmutableUnkeyedListEntryNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
511         }
512
513     }
514
515     public static class AugmentationModificationStrategy extends
516             DataNodeContainerModificationStrategy<AugmentationSchema> {
517
518         protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
519             super(createAugmentProxy(schema,resolved), AugmentationNode.class);
520             // FIXME: Use resolved children instead of unresolved.
521
522         }
523
524         @Override
525         protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
526             return Builders.augmentationBuilder().withNodeIdentifier((AugmentationIdentifier) identifier);
527         }
528
529     }
530
531     public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
532
533         private final ChoiceNode schema;
534         private final Map<PathArgument, ModificationApplyOperation> childNodes;
535
536         public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
537             super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
538             this.schema = schemaNode;
539             ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
540
541             for (ChoiceCaseNode caze : schemaNode.getCases()) {
542                 for (DataSchemaNode cazeChild : caze.getChildNodes()) {
543                     SchemaAwareApplyOperation childNode = from(cazeChild);
544                     child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
545                 }
546             }
547             childNodes = child.build();
548         }
549
550         @Override
551         public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
552             return Optional.fromNullable(childNodes.get(child));
553         }
554
555         @Override
556         @SuppressWarnings("rawtypes")
557         protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
558             checkArgument(identifier instanceof NodeIdentifier);
559             return ImmutableChoiceNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
560         }
561
562     }
563
564     public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
565
566         protected ListEntryModificationStrategy(final ListSchemaNode schema) {
567             super(schema, MapEntryNode.class);
568         }
569
570         @Override
571         @SuppressWarnings("rawtypes")
572         protected final DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
573             return ImmutableMapEntryNodeBuilder.create().withNodeIdentifier((NodeIdentifierWithPredicates) identifier);
574         }
575
576     }
577
578     public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
579
580         private final Optional<ModificationApplyOperation> entryStrategy;
581
582         @SuppressWarnings({ "unchecked", "rawtypes" })
583         protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
584             super((Class) LeafSetNode.class);
585             entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
586         }
587
588         @SuppressWarnings("rawtypes")
589         @Override
590         protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
591             return ImmutableLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
592         }
593
594         @Override
595         public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
596             if (identifier instanceof NodeWithValue) {
597                 return entryStrategy;
598             }
599             return Optional.absent();
600         }
601
602     }
603
604     public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
605
606         private final Optional<ModificationApplyOperation> entryStrategy;
607
608         @SuppressWarnings({ "unchecked", "rawtypes" })
609         protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
610             super((Class) LeafSetNode.class);
611             entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
612         }
613
614         @SuppressWarnings("rawtypes")
615         @Override
616         protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
617             return ImmutableOrderedLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
618         }
619
620         @Override
621         public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
622             if (identifier instanceof NodeWithValue) {
623                 return entryStrategy;
624             }
625             return Optional.absent();
626         }
627
628     }
629
630     public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
631
632         private final Optional<ModificationApplyOperation> entryStrategy;
633
634         protected UnkeyedListModificationStrategy(final ListSchemaNode schema) {
635             entryStrategy = Optional.<ModificationApplyOperation> of(new UnkeyedListItemModificationStrategy(schema));
636         }
637
638         @Override
639         protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
640                 final UnsignedLong subtreeVersion) {
641             return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
642         }
643
644         @Override
645         protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
646                 final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
647             throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
648         }
649
650         @Override
651         protected StoreMetadataNode applyWrite(final NodeModification modification,
652                 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
653             return StoreMetadataNode.createRecursively(modification.getWritenValue(), subtreeVersion);
654         }
655
656         @Override
657         public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
658             if (child instanceof NodeIdentifier) {
659                 return entryStrategy;
660             }
661             return Optional.absent();
662         }
663
664         @Override
665         protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
666
667         }
668
669         @Override
670         protected boolean isSubtreeModificationApplicable(final NodeModification modification,
671                 final Optional<StoreMetadataNode> current) {
672             return false;
673         }
674
675     }
676
677     public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
678
679         private final Optional<ModificationApplyOperation> entryStrategy;
680
681         protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
682             super(MapNode.class);
683             entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
684         }
685
686         @SuppressWarnings("rawtypes")
687         @Override
688         protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
689             return ImmutableMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
690         }
691
692         @Override
693         public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
694             if (identifier instanceof NodeIdentifierWithPredicates) {
695                 return entryStrategy;
696             }
697             return Optional.absent();
698         }
699
700         @Override
701         public String toString() {
702             return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
703         }
704     }
705
706     public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
707
708         private final Optional<ModificationApplyOperation> entryStrategy;
709
710         protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
711             super(OrderedMapNode.class);
712             entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
713         }
714
715         @SuppressWarnings("rawtypes")
716         @Override
717         protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
718             return ImmutableOrderedMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
719         }
720
721         @Override
722         public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
723             if (identifier instanceof NodeIdentifierWithPredicates) {
724                 return entryStrategy;
725             }
726             return Optional.absent();
727         }
728
729         @Override
730         public String toString() {
731             return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
732         }
733     }
734
735     public void verifyIdentifier(final PathArgument identifier) {
736
737     }
738
739     public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
740         Set<DataSchemaNode> realChildSchemas = new HashSet<>();
741         for(DataSchemaNode augChild : schema.getChildNodes()) {
742             realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
743         }
744         return new AugmentationSchemaProxy(schema, realChildSchemas);
745     }
746
747 }