X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FSchemaAwareApplyOperation.java;h=909aaae1ca2483b365acef1f4072fbb41339a0c1;hp=b9b1ab035e09f2dfc8325a39535a5a30bfc6c570;hb=fd474e19dd339c1abb9ed528ff3fd052004d7fe2;hpb=632b3b4a1c9477ca5c744e04021e4061e4d97130 diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java index b9b1ab035e..909aaae1ca 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java @@ -1,17 +1,29 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkArgument; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; -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.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationApplyOperation; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ModificationType; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreNodeCompositeBuilder; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; 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; @@ -26,18 +38,21 @@ 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.OrderedLeafSetNode; 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; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; 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.ImmutableOrderedLeafSetNodeBuilder; 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.data.impl.schema.transform.base.AugmentationSchemaProxy; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -56,8 +71,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSet.Builder; import com.google.common.primitives.UnsignedLong; public abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { @@ -70,7 +83,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } else if (schemaNode instanceof ChoiceNode) { return new ChoiceModificationStrategy((ChoiceNode) schemaNode); } else if (schemaNode instanceof LeafListSchemaNode) { - return new LeafSetEntryModificationStrategy((LeafListSchemaNode) schemaNode); + return fromLeafListSchemaNode((LeafListSchemaNode) schemaNode); } else if (schemaNode instanceof LeafSchemaNode) { return new LeafModificationStrategy((LeafSchemaNode) schemaNode); } @@ -89,18 +102,29 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper return new UnorderedMapModificationStrategy(schemaNode); } + private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) { + if(schemaNode.isUserOrdered()) { + return new OrderedLeafSetModificationStrategy(schemaNode); + } else { + return new UnorderedLeafSetModificationStrategy(schemaNode); + } + } + + public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree, final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) { AugmentationSchema augSchema = null; - allAugments: for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) { - boolean containsAll = true; - for (DataSchemaNode child : potential.getChildNodes()) { - if (identifier.getPossibleChildNames().contains(child.getQName())) { - augSchema = potential; - break allAugments; + + allAugments: + for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) { + for (DataSchemaNode child : potential.getChildNodes()) { + if (identifier.getPossibleChildNames().contains(child.getQName())) { + augSchema = potential; + break allAugments; + } } } - } + if (augSchema != null) { return new AugmentationModificationStrategy(augSchema, resolvedTree); } @@ -116,50 +140,68 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override public void verifyStructure(final NodeModification modification) throws IllegalArgumentException { if (modification.getModificationType() == ModificationType.WRITE) { - verifyWritenStructure(modification.getWritenValue()); + verifyWrittenStructure(modification.getWrittenValue()); } } - protected abstract void verifyWritenStructure(NormalizedNode writenValue); + protected abstract void verifyWrittenStructure(NormalizedNode writtenValue); @Override - public boolean isApplicable(final NodeModification modification, final Optional current) { + public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { switch (modification.getModificationType()) { case DELETE: - return isDeleteApplicable(modification, current); + checkDeleteApplicable(modification, current); case SUBTREE_MODIFIED: - return isSubtreeModificationApplicable(modification, current); + checkSubtreeModificationApplicable(path,modification, current); + return; case WRITE: - return isWriteApplicable(modification, current); + checkWriteApplicable(path,modification, current); + return; + case MERGE: + checkMergeApplicable(path,modification,current); + return; case UNMODIFIED: - return true; + return; default: - return false; + throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported."); } + } - protected boolean isWriteApplicable(final NodeModification modification, final Optional current) { + protected void checkMergeApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { - return isNotConflicting(original.get(), current.get()); - } else if (current.isPresent()) { - return false; + /* + * We need to do conflict detection only and only if the value of leaf changed + * before two transactions. If value of leaf is unchanged between two transactions + * it should not cause transaction to fail, since result of this merge + * leads to same data. + */ + if(!original.get().getData().equals(current.get().getData())) { + + checkNotConflicting(path,original.get(), current.get()); + } } - return true; + } + protected void checkWriteApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { + Optional original = modification.getOriginal(); + if (original.isPresent() && current.isPresent()) { + checkNotConflicting(path,original.get(), current.get()); + } else if(original.isPresent()) { + throw new DataPreconditionFailedException(path,"Node was deleted by other transaction."); + } } - protected final boolean isNotConflicting(final StoreMetadataNode original, final StoreMetadataNode current) { - return original.getNodeVersion().equals(current.getNodeVersion()) - && original.getSubtreeVersion().equals(current.getSubtreeVersion()); + protected static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException { + checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction."); + checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction"); } - protected abstract boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current); + protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException; - private boolean isDeleteApplicable(final NodeModification modification, final Optional current) { - // FiXME: Add delete conflict detection. - return true; + private void checkDeleteApplicable(final NodeModification modification, final Optional current) { } @Override @@ -174,6 +216,10 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper modification); return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(), subtreeVersion))); + case MERGE: + if(currentMeta.isPresent()) { + return modification.storeSnapshot(Optional.of(applyMerge(modification,currentMeta.get(),subtreeVersion))); + } // Fallback to write is intentional - if node is not preexisting merge is same as write case WRITE: return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion))); case UNMODIFIED: @@ -183,14 +229,16 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } } + protected abstract StoreMetadataNode applyMerge(NodeModification modification, + StoreMetadataNode currentMeta, UnsignedLong subtreeVersion); + protected abstract StoreMetadataNode applyWrite(NodeModification modification, Optional currentMeta, UnsignedLong subtreeVersion); protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification, StoreMetadataNode currentMeta, UnsignedLong subtreeVersion); - public static abstract class ValueNodeModificationStrategy extends - SchemaAwareApplyOperation { + public static abstract class ValueNodeModificationStrategy extends SchemaAwareApplyOperation { private final T schema; private final Class> nodeClass; @@ -202,8 +250,8 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected void verifyWritenStructure(final NormalizedNode writenValue) { - checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass); + protected void verifyWrittenStructure(final NormalizedNode writtenValue) { + checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass); } @Override @@ -219,22 +267,24 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper + "is leaf type node. Subtree change is not allowed."); } + @Override + protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta, + final UnsignedLong subtreeVersion) { + return applyWrite(modification, Optional.of(currentMeta), subtreeVersion); + } + @Override protected StoreMetadataNode applyWrite(final NodeModification modification, final Optional currentMeta, final UnsignedLong subtreeVersion) { UnsignedLong nodeVersion = subtreeVersion; - if (currentMeta.isPresent()) { - nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion()); - } - return StoreMetadataNode.builder().setNodeVersion(nodeVersion).setSubtreeVersion(subtreeVersion) - .setData(modification.getWritenValue()).build(); + .setData(modification.getWrittenValue()).build(); } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - return false; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); } } @@ -273,123 +323,131 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } } + @Override + protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + // FIXME: Implement proper write check for replacement of node container + // prerequisite is to have transaction chain available for clients + // otherwise this will break chained writes to same node. + } + @SuppressWarnings("rawtypes") @Override - protected void verifyWritenStructure(final NormalizedNode writenValue) { - checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass); - checkArgument(writenValue instanceof NormalizedNodeContainer); - NormalizedNodeContainer writenCont = (NormalizedNodeContainer) writenValue; - for (Object child : writenCont.getValue()) { + protected void verifyWrittenStructure(final NormalizedNode writtenValue) { + checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass); + checkArgument(writtenValue instanceof NormalizedNodeContainer); + + NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue; + for (Object child : container.getValue()) { checkArgument(child instanceof NormalizedNode); - NormalizedNode childNode = (NormalizedNode) child; + + /* + * FIXME: fail-fast semantics: + * + * We can validate the data structure here, aborting the commit + * before it ever progresses to being committed. + */ } } @Override protected StoreMetadataNode applyWrite(final NodeModification modification, final Optional currentMeta, final UnsignedLong subtreeVersion) { - // - NormalizedNode newValue = modification.getWritenValue(); - UnsignedLong nodeVersion = subtreeVersion; + NormalizedNode newValue = modification.getWrittenValue(); + + final UnsignedLong nodeVersion; if (currentMeta.isPresent()) { nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion()); + } else { + nodeVersion = subtreeVersion; } - StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion); + final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion); if (!modification.hasAdditionalModifications()) { return newValueMeta; } + @SuppressWarnings("rawtypes") - NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier()); + NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue); StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) // .setNodeVersion(nodeVersion) // .setSubtreeVersion(subtreeVersion); - Set processedPreexisting = applyPreexistingChildren(modification, newValueMeta.getChildren(), - builder, nodeVersion); - applyNewChildren(modification, processedPreexisting, builder, nodeVersion); - - return builder.build(); + return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion); + } + @Override + protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta, + final UnsignedLong subtreeVersion) { + // For Node Containers - merge is same as subtree change - we only replace children. + return applySubtreeChange(modification, currentMeta, subtreeVersion); } @Override public StoreMetadataNode applySubtreeChange(final NodeModification modification, final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) { + // Bump subtree version to its new target + final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion()); - UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion()); @SuppressWarnings("rawtypes") - NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier()); - StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) + NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData()); + StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder, currentMeta) .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion()) .setSubtreeVersion(updatedSubtreeVersion); - // We process preexisting nodes - Set processedPreexisting = applyPreexistingChildren(modification, currentMeta.getChildren(), - builder, updatedSubtreeVersion); - applyNewChildren(modification, processedPreexisting, builder, updatedSubtreeVersion); - return builder.build(); + + return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion); } - private void applyNewChildren(final NodeModification modification, final Set ignore, - final StoreNodeCompositeBuilder builder, final UnsignedLong subtreeVersion) { - for (NodeModification childModification : modification.getModifications()) { - PathArgument childIdentifier = childModification.getIdentifier(); - // We skip allready processed modifications - if (ignore.contains(childIdentifier)) { - continue; - } + private StoreMetadataNode mutateChildren(final Iterable modifications, final StoreMetadataNode meta, + final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) { - builder.addIfPresent(resolveChildOperation(childIdentifier) // - .apply(childModification, Optional. absent(), subtreeVersion)); - } - } + for (NodeModification mod : modifications) { + final PathArgument id = mod.getIdentifier(); + final Optional cm = meta.getChild(id); - private Set applyPreexistingChildren(final NodeModification modification, - final Iterable children, final StoreNodeCompositeBuilder nodeBuilder, - final UnsignedLong subtreeVersion) { - Builder processedModifications = ImmutableSet. builder(); - for (StoreMetadataNode childMeta : children) { - PathArgument childIdentifier = childMeta.getIdentifier(); - // We retrieve Child modification metadata - Optional childModification = modification.getChild(childIdentifier); - // Node is modified - if (childModification.isPresent()) { - processedModifications.add(childIdentifier); - Optional result = resolveChildOperation(childIdentifier) // - .apply(childModification.get(), Optional.of(childMeta), subtreeVersion); - nodeBuilder.addIfPresent(result); + Optional result = resolveChildOperation(id).apply(mod, cm, nodeVersion); + if (result.isPresent()) { + builder.add(result.get()); } else { - // Child is unmodified - reuse existing metadata and data - // snapshot - nodeBuilder.add(childMeta); + builder.remove(id); } } - return processedModifications.build(); + + return builder.build(); } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - if (false == current.isPresent()) { - return false; - } - boolean result = true; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction."); + checkChildPreconditions(path,modification,current); + + } + + private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataPreconditionFailedException { StoreMetadataNode currentMeta = current.get(); for (NodeModification childMod : modification.getModifications()) { PathArgument childId = childMod.getIdentifier(); Optional childMeta = currentMeta.getChild(childId); - result &= resolveChildOperation(childId).isApplicable(childMod, childMeta); + InstanceIdentifier childPath = StoreUtils.append(path, childId); + resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta); + } + } + + @Override + protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + if(current.isPresent()) { + checkChildPreconditions(path,modification,current); } - return result; } @SuppressWarnings("rawtypes") - protected abstract NormalizedNodeContainerBuilder createBuilder(PathArgument identifier); + protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode original); } - public static abstract class DataNodeContainerModificationStrategy extends - NormalizedNodeContainerModificationStrategy { + public static abstract class DataNodeContainerModificationStrategy extends NormalizedNodeContainerModificationStrategy { private final T schema; private final LoadingCache childCache = CacheBuilder.newBuilder() @@ -430,7 +488,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override @SuppressWarnings("rawtypes") - protected abstract DataContainerNodeBuilder createBuilder(PathArgument identifier); + protected abstract DataContainerNodeBuilder createBuilder(NormalizedNode original); @Override public String toString() { @@ -439,8 +497,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } - public static class ContainerModificationStrategy extends - DataNodeContainerModificationStrategy { + public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy { public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) { super(schemaNode, ContainerNode.class); @@ -448,16 +505,13 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override @SuppressWarnings("rawtypes") - protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { - // TODO Auto-generated method stub - checkArgument(identifier instanceof NodeIdentifier); - return ImmutableContainerNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected DataContainerNodeBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof ContainerNode); + return ImmutableContainerNodeBuilder.create((ContainerNode) original); } - } - public static class UnkeyedListItemModificationStrategy extends - DataNodeContainerModificationStrategy { + public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy { public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) { super(schemaNode, UnkeyedListEntryNode.class); @@ -465,37 +519,32 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override @SuppressWarnings("rawtypes") - protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { - checkArgument(identifier instanceof NodeIdentifier); - return ImmutableUnkeyedListEntryNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected DataContainerNodeBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof UnkeyedListEntryNode); + return ImmutableUnkeyedListEntryNodeBuilder.create((UnkeyedListEntryNode) original); } - } - public static class AugmentationModificationStrategy extends - DataNodeContainerModificationStrategy { + public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy { protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) { - super(schema, AugmentationNode.class); - // FIXME: Use resolved children instead of unresolved. - + super(createAugmentProxy(schema,resolved), AugmentationNode.class); } @Override - protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { - return Builders.augmentationBuilder().withNodeIdentifier((AugmentationIdentifier) identifier); + @SuppressWarnings("rawtypes") + protected DataContainerNodeBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof AugmentationNode); + return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original); } - } public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy { - private final ChoiceNode schema; private final Map childNodes; public ChoiceModificationStrategy(final ChoiceNode schemaNode) { super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class); - this.schema = schemaNode; ImmutableMap.Builder child = ImmutableMap.builder(); for (ChoiceCaseNode caze : schemaNode.getCases()) { @@ -514,11 +563,10 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override @SuppressWarnings("rawtypes") - protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { - checkArgument(identifier instanceof NodeIdentifier); - return ImmutableChoiceNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected DataContainerNodeBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode); + return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original); } - } public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy { @@ -529,26 +577,27 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override @SuppressWarnings("rawtypes") - protected final DataContainerNodeBuilder createBuilder(final PathArgument identifier) { - return ImmutableMapEntryNodeBuilder.create().withNodeIdentifier((NodeIdentifierWithPredicates) identifier); + protected final DataContainerNodeBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof MapEntryNode); + return ImmutableMapEntryNodeBuilder.create((MapEntryNode) original); } - } - public static class LeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy { + public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy { private final Optional entryStrategy; @SuppressWarnings({ "unchecked", "rawtypes" }) - protected LeafSetModificationStrategy(final LeafListSchemaNode schema) { + protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) { super((Class) LeafSetNode.class); entryStrategy = Optional. of(new LeafSetEntryModificationStrategy(schema)); } @SuppressWarnings("rawtypes") @Override - protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) { - return ImmutableLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof LeafSetNode); + return ImmutableLeafSetNodeBuilder.create((LeafSetNode) original); } @Override @@ -558,7 +607,32 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } return Optional.absent(); } + } + + public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy { + + private final Optional entryStrategy; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) { + super((Class) LeafSetNode.class); + entryStrategy = Optional. of(new LeafSetEntryModificationStrategy(schema)); + } + @SuppressWarnings("rawtypes") + @Override + protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof OrderedLeafSetNode); + return ImmutableOrderedLeafSetNodeBuilder.create((OrderedLeafSetNode) original); + } + + @Override + public Optional getChild(final PathArgument identifier) { + if (identifier instanceof NodeWithValue) { + return entryStrategy; + } + return Optional.absent(); + } } public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation { @@ -569,7 +643,11 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper entryStrategy = Optional. of(new UnkeyedListItemModificationStrategy(schema)); } - + @Override + protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta, + final UnsignedLong subtreeVersion) { + return applyWrite(modification, Optional.of(currentMeta), subtreeVersion); + } @Override protected StoreMetadataNode applySubtreeChange(final NodeModification modification, @@ -580,7 +658,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override protected StoreMetadataNode applyWrite(final NodeModification modification, final Optional currentMeta, final UnsignedLong subtreeVersion) { - return StoreMetadataNode.createRecursively(modification.getWritenValue(), subtreeVersion); + return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion); } @Override @@ -592,14 +670,14 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected void verifyWritenStructure(final NormalizedNode writenValue) { + protected void verifyWrittenStructure(final NormalizedNode writtenValue) { } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - return false; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); } } @@ -615,8 +693,9 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @SuppressWarnings("rawtypes") @Override - protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) { - return ImmutableMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof MapNode); + return ImmutableMapNodeBuilder.create((MapNode) original); } @Override @@ -644,8 +723,9 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @SuppressWarnings("rawtypes") @Override - protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) { - return ImmutableOrderedMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { + checkArgument(original instanceof OrderedMapNode); + return ImmutableOrderedMapNodeBuilder.create((OrderedMapNode) original); } @Override @@ -662,8 +742,19 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } } - public void verifyIdentifier(final PathArgument identifier) { + public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) { + Set realChildSchemas = new HashSet<>(); + for(DataSchemaNode augChild : schema.getChildNodes()) { + realChildSchemas.add(resolved.getDataChildByName(augChild.getQName())); + } + return new AugmentationSchemaProxy(schema, realChildSchemas); + } + public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException { + if(!condition) { + throw new DataPreconditionFailedException(path, message); + } + return condition; } }