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