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