BUG-509, BUG-808: Added datastore support for lists without keys.
authorRobert Varga <rovarga@cisco.com>
Tue, 22 Apr 2014 12:54:04 +0000 (14:54 +0200)
committerRobert Varga <rovarga@cisco.com>
Tue, 22 Apr 2014 13:19:35 +0000 (15:19 +0200)
The datastore needs to support users who do not specify a list key, but
how expect the item ordering to be retained.

Added test which test all three possible behaviours of list
statement: ordered map, unordered map and list without keys.

Change-Id: I9e136267f57a88e4d2a6a4476025c33497373518
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java

index d6d87bac84b307d388147cc3bd44c0346b5afa77..9cdf70322c772568ad4f69f811711a9a5a5c39ac 100644 (file)
@@ -118,6 +118,10 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider
         return schemaContext;
     }
 
+    public DOMDataBroker getDomAsyncDataBroker() {
+        return newDOMDataBroker;
+    }
+
     protected BindingTestContext(final ListeningExecutorService executor, final ClassPool classPool, final boolean startWithSchema) {
         this.executor = executor;
         this.classPool = classPool;
index ae9b17bde4c413c0fee567193c84ff72dca06913..a36d984fa75c88e50360b7da64a8c8bbb7dcd832 100644 (file)
@@ -30,7 +30,6 @@ import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
@@ -110,7 +109,6 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
         @Override
         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
-            // TODO Auto-generated method stub
             return null;
         }
 
@@ -148,16 +146,16 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         }
     }
 
-    private static abstract class CompositeNodeNormalizationOpertation<T extends PathArgument> extends
+    private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
             DataNormalizationOperation<T> {
 
-        protected CompositeNodeNormalizationOpertation(final T identifier) {
+        protected CompositeNodeNormalizationOperation(final T identifier) {
             super(identifier);
         }
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
         @Override
-        public final NormalizedNodeContainer<?, ?, ?> normalize(final Node<?> legacyData) {
+        public final NormalizedNode<?, ?> normalize(final Node<?> legacyData) {
             checkArgument(legacyData != null);
             if (!isMixin() && getIdentifier().getNodeType() != null) {
                 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
@@ -197,7 +195,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
                     builder.addChild(childOp.normalize(childLegacy));
                 }
             }
-            return (NormalizedNodeContainer<?, ?, ?>) builder.build();
+            return builder.build();
         }
 
         @SuppressWarnings("rawtypes")
@@ -206,7 +204,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     }
 
     private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
-            CompositeNodeNormalizationOpertation<T> {
+            CompositeNodeNormalizationOperation<T> {
 
         private final DataNodeContainer schema;
         private final Map<QName, DataNormalizationOperation<?>> byQName;
@@ -295,6 +293,24 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         }
     }
 
+    private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
+
+        protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
+            super(new NodeIdentifier(schema.getQName()), schema);
+        }
+
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+            return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
+        }
+
+        @Override
+        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
+            return Builders.unkeyedListEntryBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
+        }
+
+    }
+
     private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
 
         protected ContainerNormalization(final ContainerSchemaNode schema) {
@@ -314,7 +330,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     }
 
     private static abstract class MixinNormalizationOp<T extends PathArgument> extends
-            CompositeNodeNormalizationOpertation<T> {
+            CompositeNodeNormalizationOperation<T> {
 
         protected MixinNormalizationOp(final T identifier) {
             super(identifier);
@@ -327,11 +343,30 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     }
 
-    private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
+
+    private static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
+
+
+        public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
+            super(potential);
+        }
+
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+            return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
+        }
+
+        @Override
+        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
+            return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier()).build();
+        }
+    }
+
+    private static class UnorderedLeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
 
         private final DataNormalizationOperation<?> innerOp;
 
-        public LeafListMixinNormalization(final LeafListSchemaNode potential) {
+        public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
             super(new NodeIdentifier(potential.getQName()));
             innerOp = new LeafListEntryNormalization(potential);
         }
@@ -415,11 +450,11 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     }
 
-    private static final class ListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
+    private static class UnorderedMapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
 
         private final ListItemNormalization innerNode;
 
-        public ListMixinNormalization(final ListSchemaNode list) {
+        public UnorderedMapMixinNormalization(final ListSchemaNode list) {
             super(new NodeIdentifier(list.getQName()));
             this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
                     Collections.<QName, Object> emptyMap()), list);
@@ -454,6 +489,64 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     }
 
+
+    private static class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
+
+        private final UnkeyedListItemNormalization innerNode;
+
+        public UnkeyedListMixinNormalization(final ListSchemaNode list) {
+            super(new NodeIdentifier(list.getQName()));
+            this.innerNode = new UnkeyedListItemNormalization(list);
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+            return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier());
+        }
+
+        @Override
+        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
+            return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier()).build();
+        }
+
+        @Override
+        public DataNormalizationOperation<?> getChild(final PathArgument child) {
+            if (child.getNodeType().equals(getIdentifier().getNodeType())) {
+                return innerNode;
+            }
+            return null;
+        }
+
+        @Override
+        public DataNormalizationOperation<?> getChild(final QName child) {
+            if (getIdentifier().getNodeType().equals(child)) {
+                return innerNode;
+            }
+            return null;
+        }
+
+    }
+
+    private static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
+
+        public OrderedMapMixinNormalization(final ListSchemaNode list) {
+            super(list);
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+            return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
+        }
+
+        @Override
+        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
+            return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier()).build();
+        }
+
+    }
+
     private static class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
 
         private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
@@ -569,17 +662,37 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         if (potential instanceof ContainerSchemaNode) {
             return new ContainerNormalization((ContainerSchemaNode) potential);
         } else if (potential instanceof ListSchemaNode) {
-            return new ListMixinNormalization((ListSchemaNode) potential);
+
+            return fromListSchemaNode((ListSchemaNode) potential);
         } else if (potential instanceof LeafSchemaNode) {
             return new LeafNormalization(new NodeIdentifier(potential.getQName()));
         } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
             return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
         } else if (potential instanceof LeafListSchemaNode) {
-            return new LeafListMixinNormalization((LeafListSchemaNode) potential);
+            return fromLeafListSchemaNode((LeafListSchemaNode) potential);
         }
         return null;
     }
 
+    private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
+        List<QName> keyDefinition = potential.getKeyDefinition();
+        if(keyDefinition == null || keyDefinition.isEmpty()) {
+            return new UnkeyedListMixinNormalization(potential);
+        }
+        if(potential.isUserOrdered()) {
+            return new OrderedMapMixinNormalization(potential);
+        }
+        return new UnorderedMapMixinNormalization(potential);
+    }
+
+    private static DataNormalizationOperation<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
+        if(potential.isUserOrdered()) {
+            return new OrderedLeafListMixinNormalization(potential);
+        }
+        return new UnorderedLeafListMixinNormalization(potential);
+    }
+
+
     public static DataNormalizationOperation<?> from(final SchemaContext ctx) {
         return new ContainerNormalization(ctx);
     }
index 8fb6ff38a2477243545fe6fef86ca48532c4d493..33a9869a6b8d9f74605ef1362432cb4f9026f269 100644 (file)
@@ -25,13 +25,14 @@ import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -165,6 +166,8 @@ public class DataNormalizer {
         for (NormalizedNode<?, ?> child : node.getValue()) {
             if (child instanceof MixinNode && child instanceof NormalizedNodeContainer<?, ?, ?>) {
                 builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child));
+            } else if( child instanceof UnkeyedListNode) {
+                builder.addAll(toLegacyNodesFromUnkeyedList((UnkeyedListNode) child));
             } else {
                 addToBuilder(builder, toLegacy(child));
             }
@@ -172,6 +175,14 @@ public class DataNormalizer {
         return builder.toInstance();
     }
 
+    private static Iterable<? extends Node<?>> toLegacyNodesFromUnkeyedList(final UnkeyedListNode mixin) {
+        ArrayList<Node<?>> ret = new ArrayList<>();
+        for (NormalizedNode<?, ?> child : mixin.getValue()) {
+            ret.add(toLegacy(child));
+        }
+        return FluentIterable.from(ret).filter(Predicates.notNull());
+    }
+
     private static void addToBuilder(final CompositeNodeBuilder<ImmutableCompositeNode> builder, final Node<?> legacy) {
         if (legacy != null) {
             builder.add(legacy);
@@ -189,13 +200,7 @@ public class DataNormalizer {
                 ret.add(toLegacy(child));
             }
         }
-        return FluentIterable.from(ret).filter(new Predicate<Node<?>>() {
-
-            @Override
-            public boolean apply(final Node<?> input) {
-                return input != null;
-            }
-        });
+        return FluentIterable.from(ret).filter(Predicates.notNull());
     }
 
     public DataNormalizationOperation<?> getRootOperation() {
index dd7eb3f71b68012b497bee6b5fb2119bcf9455c9..b9b1ab035e09f2dfc8325a39535a5a30bfc6c570 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -10,6 +11,7 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
@@ -24,6 +26,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
@@ -32,6 +36,8 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableCo
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -60,7 +66,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
         if (schemaNode instanceof ContainerSchemaNode) {
             return new ContainerModificationStrategy((ContainerSchemaNode) schemaNode);
         } else if (schemaNode instanceof ListSchemaNode) {
-            return new ListMapModificationStrategy((ListSchemaNode) schemaNode);
+            return fromListSchemaNode((ListSchemaNode) schemaNode);
         } else if (schemaNode instanceof ChoiceNode) {
             return new ChoiceModificationStrategy((ChoiceNode) schemaNode);
         } else if (schemaNode instanceof LeafListSchemaNode) {
@@ -71,26 +77,36 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
         throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
     }
 
+    private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
+        List<QName> keyDefinition = schemaNode.getKeyDefinition();
+        if (keyDefinition == null || keyDefinition.isEmpty()) {
+            return new UnkeyedListModificationStrategy(schemaNode);
+        }
+        if (schemaNode.isUserOrdered()) {
+            return new OrderedMapModificationStrategy(schemaNode);
+        }
+
+        return new UnorderedMapModificationStrategy(schemaNode);
+    }
+
     public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
             final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
         AugmentationSchema augSchema = null;
-        allAugments : for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
+        allAugments: for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
             boolean containsAll = true;
-            for(DataSchemaNode child : potential.getChildNodes()) {
-                if(identifier.getPossibleChildNames().contains(child.getQName())) {
+            for (DataSchemaNode child : potential.getChildNodes()) {
+                if (identifier.getPossibleChildNames().contains(child.getQName())) {
                     augSchema = potential;
                     break allAugments;
                 }
             }
         }
-        if(augSchema != null) {
-            return new AugmentationModificationStrategy(augSchema,resolvedTree);
+        if (augSchema != null) {
+            return new AugmentationModificationStrategy(augSchema, resolvedTree);
         }
         return null;
     }
 
-
-
     protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
         Optional<ModificationApplyOperation> potential = getChild(child);
         checkArgument(potential.isPresent(), "Operation for child %s is not defined.", child);
@@ -152,10 +168,12 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
         switch (modification.getModificationType()) {
         case DELETE:
-            return modification.storeSnapshot(Optional.<StoreMetadataNode>absent());
+            return modification.storeSnapshot(Optional.<StoreMetadataNode> absent());
         case SUBTREE_MODIFIED:
-            Preconditions.checkArgument(currentMeta.isPresent(),"Metadata not available for modification",modification);
-            return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(), subtreeVersion)));
+            Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
+                    modification);
+            return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(),
+                    subtreeVersion)));
         case WRITE:
             return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion)));
         case UNMODIFIED:
@@ -374,8 +392,8 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
             NormalizedNodeContainerModificationStrategy {
 
         private final T schema;
-        private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder().build(
-                CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
+        private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
+                .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
 
                     @Override
                     public ModificationApplyOperation apply(final PathArgument identifier) {
@@ -438,6 +456,22 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
     }
 
+    public static class UnkeyedListItemModificationStrategy extends
+            DataNodeContainerModificationStrategy<ListSchemaNode> {
+
+        public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
+            super(schemaNode, UnkeyedListEntryNode.class);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
+            checkArgument(identifier instanceof NodeIdentifier);
+            return ImmutableUnkeyedListEntryNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
+        }
+
+    }
+
     public static class AugmentationModificationStrategy extends
             DataNodeContainerModificationStrategy<AugmentationSchema> {
 
@@ -447,7 +481,6 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
         }
 
-
         @Override
         protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) {
             return Builders.augmentationBuilder().withNodeIdentifier((AugmentationIdentifier) identifier);
@@ -458,17 +491,17 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
     public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
 
         private final ChoiceNode schema;
-        private final Map<PathArgument,ModificationApplyOperation> childNodes;
+        private final Map<PathArgument, ModificationApplyOperation> childNodes;
 
         public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
             super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
             this.schema = schemaNode;
             ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
 
-            for(ChoiceCaseNode caze : schemaNode.getCases()) {
-                for(DataSchemaNode cazeChild : caze.getChildNodes()) {
+            for (ChoiceCaseNode caze : schemaNode.getCases()) {
+                for (DataSchemaNode cazeChild : caze.getChildNodes()) {
                     SchemaAwareApplyOperation childNode = from(cazeChild);
-                    child.put(new NodeIdentifier(cazeChild.getQName()),childNode);
+                    child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
                 }
             }
             childNodes = child.build();
@@ -528,11 +561,54 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
     }
 
-    public static class ListMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+    public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        protected UnkeyedListModificationStrategy(final ListSchemaNode schema) {
+            entryStrategy = Optional.<ModificationApplyOperation> of(new UnkeyedListItemModificationStrategy(schema));
+        }
+
+
+
+        @Override
+        protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
+                final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+            throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
+        }
+
+        @Override
+        protected StoreMetadataNode applyWrite(final NodeModification modification,
+                final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+            return StoreMetadataNode.createRecursively(modification.getWritenValue(), subtreeVersion);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+            if (child instanceof NodeIdentifier) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+
+        @Override
+        protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
+
+        }
+
+        @Override
+        protected boolean isSubtreeModificationApplicable(final NodeModification modification,
+                final Optional<StoreMetadataNode> current) {
+            return false;
+        }
+
+    }
+
+    public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
 
         private final Optional<ModificationApplyOperation> entryStrategy;
 
-        protected ListMapModificationStrategy(final ListSchemaNode schema) {
+        protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
             super(MapNode.class);
             entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
         }
@@ -553,7 +629,36 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
         @Override
         public String toString() {
-            return "ListMapModificationStrategy [entry=" + entryStrategy + "]";
+            return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
+        }
+    }
+
+    public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
+            super(OrderedMapNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
+            return ImmutableOrderedMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeIdentifierWithPredicates) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+
+        @Override
+        public String toString() {
+            return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
         }
     }